diff --git a/bower.json b/bower.json index ac19123542c..635783e6c25 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "ionic", - "version": "1.0.0-beta.3", - "codename": "americium", + "version": "1.0.0-beta.4", + "codename": "antimony-antelope", "homepage": "https://github.com/driftyco/ionic", "authors": [ "Max Lynch ", diff --git a/component.json b/component.json index e439806f0a8..da59aaa43e7 100644 --- a/component.json +++ b/component.json @@ -1,7 +1,7 @@ { "repo": "driftyco/ionic", "development": {}, - "version": "1.0.0-beta.3", + "version": "1.0.0-beta.4", "styles": [ "dist/css/ionic.css" ], diff --git a/config/CODENAMES b/config/CODENAMES index 0359e34aeb0..dd17773d16b 100644 --- a/config/CODENAMES +++ b/config/CODENAMES @@ -1,8 +1 @@ -antimony-antelope -barium-bobcat -cadmium-camel -darmstadtium-dingo -einsteinium-emu -fermium-flamingo -gadolinium-gator -hafnium-heron +barium-bobcat cadmium-camel darmstadtium-dingo einsteinium-emu fermium-flamingo gadolinium-gator hafnium-heron diff --git a/package.json b/package.json index 2bf3bf28f49..066f409aba1 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "ionic", "private": false, "version": "1.0.0-beta.4", - "codename": "americium", + "codename": "antimony-antelope", "repository": { "url": "git://github.com/driftyco/ionic.git" }, diff --git a/release/css/ionic.css b/release/css/ionic.css index 71b61207e86..a53f73987c9 100644 --- a/release/css/ionic.css +++ b/release/css/ionic.css @@ -2,7 +2,7 @@ * Copyright 2014 Drifty Co. * http://drifty.com/ * - * Ionic, v1.0.0-beta.3 + * Ionic, v1.0.0-beta.4 * A powerful HTML5 mobile app framework. * http://ionicframework.com/ * @@ -2116,6 +2116,8 @@ body.grade-b, body.grade-c { .scroll-refresher .ionic-refresher-content .text-refreshing, .scroll-refresher .ionic-refresher-content .text-pulling { line-height: 16px; font-size: 16px; } + .scroll-refresher .ionic-refresher-content.ionic-refresher-with-text { + bottom: 10px; } .scroll-refresher .icon-refreshing, .scroll-refresher .icon-pulling { width: 100%; -webkit-backface-visibility: hidden; @@ -2232,8 +2234,7 @@ ion-infinite-scroll.active .scroll-infinite { left: 0; width: 100%; height: 100%; - background-color: #fff; - overflow: hidden; } + background-color: #fff; } /** * Typography @@ -3000,7 +3001,7 @@ a.subdued { .tabs-item-hide > .tabs, .tabs.tabs-item-hide { display: none; } -.tabs-icon-top > .tabs .tab-item, .tabs-icon-bottom > .tabs .tab-item { +.tabs-icon-top > .tabs .tab-item, .tabs-icon-top.tabs .tab-item, .tabs-icon-bottom > .tabs .tab-item, .tabs-icon-bottom.tabs .tab-item { font-size: 12px; line-height: 14px; } @@ -3010,22 +3011,22 @@ a.subdued { height: 32px; font-size: 32px; } -.tabs-icon-left > .tabs .tab-item, .tabs-icon-right > .tabs .tab-item { +.tabs-icon-left.tabs .tab-item, .tabs-icon-left > .tabs .tab-item, .tabs-icon-right.tabs .tab-item, .tabs-icon-right > .tabs .tab-item { font-size: 12px; } - .tabs-icon-left > .tabs .tab-item .icon, .tabs-icon-right > .tabs .tab-item .icon { + .tabs-icon-left.tabs .tab-item .icon, .tabs-icon-left > .tabs .tab-item .icon, .tabs-icon-right.tabs .tab-item .icon, .tabs-icon-right > .tabs .tab-item .icon { display: inline-block; vertical-align: top; } - .tabs-icon-left > .tabs .tab-item .icon:before, .tabs-icon-right > .tabs .tab-item .icon:before { + .tabs-icon-left.tabs .tab-item .icon:before, .tabs-icon-left > .tabs .tab-item .icon:before, .tabs-icon-right.tabs .tab-item .icon:before, .tabs-icon-right > .tabs .tab-item .icon:before { font-size: 24px; line-height: 49px; } -.tabs-icon-left .tab-item .icon { +.tabs-icon-left > .tabs .tab-item .icon, .tabs-icon-left.tabs .tab-item .icon { padding-right: 3px; } -.tabs-icon-right .tab-item .icon { +.tabs-icon-right > .tabs .tab-item .icon, .tabs-icon-right.tabs .tab-item .icon { padding-left: 3px; } -.tabs-icon-only .icon { +.tabs-icon-only > .tabs .icon, .tabs-icon-only.tabs .icon { line-height: inherit; } .tab-item.has-badge { @@ -3165,7 +3166,7 @@ a.subdued { .modal-open { pointer-events: none; } - .modal-open .modal { + .modal-open .modal, .modal-open .modal-backdrop { pointer-events: auto; } /** @@ -4463,10 +4464,14 @@ input[type="radio"][disabled], input[type="checkbox"][disabled], input[type="rad transform: translate3d(22px, 0, 0); background-color: #fff; } -.item-toggle { +.item-toggle.active { + box-shadow: none; } + +.item-toggle, .item-toggle.item-complex .item-content { padding-right: 99px; } - .item-toggle.active { - box-shadow: none; } + +.item-toggle.item-complex { + padding-right: 0; } .item-toggle .toggle { position: absolute; @@ -6194,9 +6199,10 @@ a.button { .invisible { visibility: hidden; } -.keyboard-open .bar-footer, .keyboard-open .tabs, .footer-hide .bar-footer, .footer-hide .tabs { +.keyboard-open .hide-on-keyboard-open { display: none; } -.keyboard-open .has-footer, .keyboard-open .has-tabs, .footer-hide .has-footer, .footer-hide .has-tabs { + +.keyboard-open .tabs.hide-on-keyboard-open + .pane .has-tabs, .keyboard-open .bar-footer.hide-on-keyboard-open + .pane .has-footer { bottom: 0; } .inline { @@ -6220,6 +6226,9 @@ a.button { -ms-touch-action: none; -ms-content-zooming: none; } +.no-resize { + resize: none; } + .block { display: block; clear: both; } @@ -6359,7 +6368,7 @@ a.button { /** * Platform * -------------------------------------------------- - * Platform specific tweaks when in Cordova. + * Platform specific tweaks */ .platform-ios7.platform-cordova:not(.fullscreen) .bar-header:not(.bar-subheader) { height: 64px; } @@ -6379,3 +6388,11 @@ a.button { top: 157px; } .platform-ios7.platform-cordova.status-bar-hide { margin-bottom: 20px; } + +@media (orientation: landscape) { + .platform-ios7.platform-browser.platform-ipad { + position: fixed; } } + +.platform-android2:not(.enable-transitions) * { + -webkit-transition: none !important; + transition: none !important; } diff --git a/release/css/ionic.min.css b/release/css/ionic.min.css index 71b61207e86..a53f73987c9 100644 --- a/release/css/ionic.min.css +++ b/release/css/ionic.min.css @@ -2,7 +2,7 @@ * Copyright 2014 Drifty Co. * http://drifty.com/ * - * Ionic, v1.0.0-beta.3 + * Ionic, v1.0.0-beta.4 * A powerful HTML5 mobile app framework. * http://ionicframework.com/ * @@ -2116,6 +2116,8 @@ body.grade-b, body.grade-c { .scroll-refresher .ionic-refresher-content .text-refreshing, .scroll-refresher .ionic-refresher-content .text-pulling { line-height: 16px; font-size: 16px; } + .scroll-refresher .ionic-refresher-content.ionic-refresher-with-text { + bottom: 10px; } .scroll-refresher .icon-refreshing, .scroll-refresher .icon-pulling { width: 100%; -webkit-backface-visibility: hidden; @@ -2232,8 +2234,7 @@ ion-infinite-scroll.active .scroll-infinite { left: 0; width: 100%; height: 100%; - background-color: #fff; - overflow: hidden; } + background-color: #fff; } /** * Typography @@ -3000,7 +3001,7 @@ a.subdued { .tabs-item-hide > .tabs, .tabs.tabs-item-hide { display: none; } -.tabs-icon-top > .tabs .tab-item, .tabs-icon-bottom > .tabs .tab-item { +.tabs-icon-top > .tabs .tab-item, .tabs-icon-top.tabs .tab-item, .tabs-icon-bottom > .tabs .tab-item, .tabs-icon-bottom.tabs .tab-item { font-size: 12px; line-height: 14px; } @@ -3010,22 +3011,22 @@ a.subdued { height: 32px; font-size: 32px; } -.tabs-icon-left > .tabs .tab-item, .tabs-icon-right > .tabs .tab-item { +.tabs-icon-left.tabs .tab-item, .tabs-icon-left > .tabs .tab-item, .tabs-icon-right.tabs .tab-item, .tabs-icon-right > .tabs .tab-item { font-size: 12px; } - .tabs-icon-left > .tabs .tab-item .icon, .tabs-icon-right > .tabs .tab-item .icon { + .tabs-icon-left.tabs .tab-item .icon, .tabs-icon-left > .tabs .tab-item .icon, .tabs-icon-right.tabs .tab-item .icon, .tabs-icon-right > .tabs .tab-item .icon { display: inline-block; vertical-align: top; } - .tabs-icon-left > .tabs .tab-item .icon:before, .tabs-icon-right > .tabs .tab-item .icon:before { + .tabs-icon-left.tabs .tab-item .icon:before, .tabs-icon-left > .tabs .tab-item .icon:before, .tabs-icon-right.tabs .tab-item .icon:before, .tabs-icon-right > .tabs .tab-item .icon:before { font-size: 24px; line-height: 49px; } -.tabs-icon-left .tab-item .icon { +.tabs-icon-left > .tabs .tab-item .icon, .tabs-icon-left.tabs .tab-item .icon { padding-right: 3px; } -.tabs-icon-right .tab-item .icon { +.tabs-icon-right > .tabs .tab-item .icon, .tabs-icon-right.tabs .tab-item .icon { padding-left: 3px; } -.tabs-icon-only .icon { +.tabs-icon-only > .tabs .icon, .tabs-icon-only.tabs .icon { line-height: inherit; } .tab-item.has-badge { @@ -3165,7 +3166,7 @@ a.subdued { .modal-open { pointer-events: none; } - .modal-open .modal { + .modal-open .modal, .modal-open .modal-backdrop { pointer-events: auto; } /** @@ -4463,10 +4464,14 @@ input[type="radio"][disabled], input[type="checkbox"][disabled], input[type="rad transform: translate3d(22px, 0, 0); background-color: #fff; } -.item-toggle { +.item-toggle.active { + box-shadow: none; } + +.item-toggle, .item-toggle.item-complex .item-content { padding-right: 99px; } - .item-toggle.active { - box-shadow: none; } + +.item-toggle.item-complex { + padding-right: 0; } .item-toggle .toggle { position: absolute; @@ -6194,9 +6199,10 @@ a.button { .invisible { visibility: hidden; } -.keyboard-open .bar-footer, .keyboard-open .tabs, .footer-hide .bar-footer, .footer-hide .tabs { +.keyboard-open .hide-on-keyboard-open { display: none; } -.keyboard-open .has-footer, .keyboard-open .has-tabs, .footer-hide .has-footer, .footer-hide .has-tabs { + +.keyboard-open .tabs.hide-on-keyboard-open + .pane .has-tabs, .keyboard-open .bar-footer.hide-on-keyboard-open + .pane .has-footer { bottom: 0; } .inline { @@ -6220,6 +6226,9 @@ a.button { -ms-touch-action: none; -ms-content-zooming: none; } +.no-resize { + resize: none; } + .block { display: block; clear: both; } @@ -6359,7 +6368,7 @@ a.button { /** * Platform * -------------------------------------------------- - * Platform specific tweaks when in Cordova. + * Platform specific tweaks */ .platform-ios7.platform-cordova:not(.fullscreen) .bar-header:not(.bar-subheader) { height: 64px; } @@ -6379,3 +6388,11 @@ a.button { top: 157px; } .platform-ios7.platform-cordova.status-bar-hide { margin-bottom: 20px; } + +@media (orientation: landscape) { + .platform-ios7.platform-browser.platform-ipad { + position: fixed; } } + +.platform-android2:not(.enable-transitions) * { + -webkit-transition: none !important; + transition: none !important; } diff --git a/release/js/ionic-angular.js b/release/js/ionic-angular.js index 1d3328a37e3..5c7f7c243d5 100644 --- a/release/js/ionic-angular.js +++ b/release/js/ionic-angular.js @@ -2,7 +2,7 @@ * Copyright 2014 Drifty Co. * http://drifty.com/ * - * Ionic, v1.0.0-beta.3 + * Ionic, v1.0.0-beta.4 * A powerful HTML5 mobile app framework. * http://ionicframework.com/ * @@ -276,6 +276,68 @@ angular.element.prototype.removeClass = function(cssClasses) { return this; }; + +/** + * @ngdoc service + * @name $ionicAnimation + * @module ionic + * @description + * + * A powerful animation and transition system for Ionic apps. + * + * @usage + * + * ```js + * angular.module('mySuperApp', ['ionic']) + * .controller(function($scope, $ionicAnimation) { + * var anim = $ionicAnimate({ + * // A unique, reusable name + * name: 'popIn', + * + * // The duration of an auto playthrough + * duration: 0.5, + * + * // How long to wait before running the animation + * delay: 0, + * + * // Whether to reverse after doing one run through + * autoReverse: false, + * + * // How many times to repeat? -1 or null for infinite + * repeat: -1, + * + * // Timing curve to use (same as CSS timing functions), or a function of time "t" to handle it yourself + * curve: 'ease-in-out' + * + * onStart: function() { + * // Callback on start + * }, + * onEnd: function() { + * // Callback on end + * }, + * step: function(amt) { + * + * } + * }) + * }); + * ``` + * + */ +IonicModule +.provider('$ionicAnimation', function() { + var useSlowAnimations = false; + this.setSlowAnimations = function(isSlow) { + useSlowAnimations = isSlow; + }; + + this.$get = [function() { + return function(opts) { + opts.useSlowAnimations = useSlowAnimations; + return ionic.Animation.create(opts); + } + }] +}); + /** * @ngdoc service * @name $ionicBackdrop @@ -534,6 +596,7 @@ function($cacheFactory, $parse) { this.transcludeParent[0].appendChild(item.element[0]); } reconnectScope(item.scope); + !item.scope.$$phase && item.scope.$digest(); }, getLength: function() { return this.data && this.data.length || 0; @@ -808,7 +871,7 @@ function($rootScope, $timeout) { this.renderItem(i, rect.primaryPos - startPos, rect.secondaryPos); i++; } - var bufferEndIndex = i -1; + var bufferEndIndex = i - 1; for (i in this.renderedItems) { if (i < bufferStartIndex || i > bufferEndIndex) { @@ -827,9 +890,6 @@ function($rootScope, $timeout) { primaryPos, secondaryPos, secondaryPos ); this.renderedItems[dataIndex] = item; - if (item.scope && !item.scope.$$phase) { - item.scope.$digest(); - } } else { delete this.renderedItems[dataIndex]; } @@ -1035,10 +1095,12 @@ IonicModule '$q', '$log', '$compile', -function($document, $ionicTemplateLoader, $ionicBackdrop, $timeout, $q, $log, $compile) { + '$ionicPlatform', +function($document, $ionicTemplateLoader, $ionicBackdrop, $timeout, $q, $log, $compile, $ionicPlatform) { var loaderInstance; - //default value + //default values + var deregisterBackAction = angular.noop; var loadingShowDelay = $q.when(); return { @@ -1075,7 +1137,6 @@ function($document, $ionicTemplateLoader, $ionicBackdrop, $timeout, $q, $log, $c appendTo: $document[0].body }) .then(function(loader) { - var self = loader; loader.show = function(options) { @@ -1132,10 +1193,11 @@ function($document, $ionicTemplateLoader, $ionicBackdrop, $timeout, $q, $log, $c $timeout.cancel(this.durationTimeout); this.isShown = false; }; + return loader; }); } - return $q.when(loaderInstance); + return loaderInstance; } function showLoader(options) { @@ -1143,10 +1205,16 @@ function($document, $ionicTemplateLoader, $ionicBackdrop, $timeout, $q, $log, $c var delay = options.delay || options.showDelay || 0; //If loading.show() was called previously, cancel it and show with our new options - $timeout.cancel(loadingShowDelay); + loadingShowDelay && $timeout.cancel(loadingShowDelay); loadingShowDelay = $timeout(angular.noop, delay); loadingShowDelay.then(getLoader).then(function(loader) { + deregisterBackAction(); + //Disable hardware back button while loading + deregisterBackAction = $ionicPlatform.registerBackButtonAction( + angular.noop, + PLATFORM_BACK_BUTTON_PRIORITY_LOADING + ); return loader.show(options); }); @@ -1164,6 +1232,7 @@ function($document, $ionicTemplateLoader, $ionicBackdrop, $timeout, $q, $log, $c } function hideLoader() { + deregisterBackAction(); $timeout.cancel(loadingShowDelay); getLoader().then(function(loader) { loader.hide(); @@ -1267,7 +1336,10 @@ function($rootScope, $document, $compile, $timeout, $ionicPlatform, $ionicTempla var modalEl = angular.element(self.modalEl); self.el.classList.remove('hide'); - $document[0].body.classList.add('modal-open'); + $timeout(function(){ + $document[0].body.classList.add('modal-open'); + }, 400) + if(!self.el.parentElement) { modalEl.addClass(self.animation); @@ -1291,7 +1363,14 @@ function($rootScope, $document, $compile, $timeout, $ionicPlatform, $ionicTempla self.el.classList.add('active'); }, 20); - return $timeout(angular.noop, 400); + return $timeout(function() { + //After animating in, allow hide on backdrop click + self.$el.on('click', function(e) { + if (e.target === self.el) { + self.hide(); + } + }); + }, 400); }, /** @@ -1312,6 +1391,7 @@ function($rootScope, $document, $compile, $timeout, $ionicPlatform, $ionicTempla .removeClass('ng-enter ng-enter-active active'); }, 20); + self.$el.off('click'); self._isShown = false; self.scope.$parent && self.scope.$parent.$broadcast('modal.hidden', self); self._deregisterBackButton && self._deregisterBackButton(); @@ -1336,7 +1416,7 @@ function($rootScope, $document, $compile, $timeout, $ionicPlatform, $ionicTempla return self.hide().then(function() { self.scope.$destroy(); - angular.element(self.el).remove(); + self.$el.remove(); }); }, @@ -1366,6 +1446,7 @@ function($rootScope, $document, $compile, $timeout, $ionicPlatform, $ionicTempla // Compile the template var element = $compile('' + templateString + '')(scope); + options.$el = element; options.el = element[0]; options.modalEl = options.el.querySelector('.modal'); var modal = new ModalView(options); @@ -1525,8 +1606,10 @@ IonicModule ])); var PLATFORM_BACK_BUTTON_PRIORITY_VIEW = 100; +var PLATFORM_BACK_BUTTON_PRIORITY_SIDE_MENU = 150; var PLATFORM_BACK_BUTTON_PRIORITY_ACTION_SHEET = 300; -var PLATFORM_BACK_BUTTON_PRIORITY_POPUP = 500; +var PLATFORM_BACK_BUTTON_PRIORITY_POPUP = 400; +var PLATFORM_BACK_BUTTON_PRIORITY_LOADING = 500; /** * @ngdoc service * @name $ionicPlatform @@ -3602,15 +3685,17 @@ function($scope, scrollViewOptions, $timeout, $window, $$scrollValueCache, $loca var viewId = historyData && historyData.viewId; if (viewId) { - self.rememberScrollPosition(viewId); - self.scrollToRememberedPosition(); + $timeout(function() { + self.rememberScrollPosition(viewId); + self.scrollToRememberedPosition(); - backListenDone = $rootScope.$on('$viewHistory.viewBack', function(e, fromViewId, toViewId) { - //When going back from this view, forget its saved scroll position - if (viewId === fromViewId) { - self.forgetScrollPosition(); - } - }); + backListenDone = $rootScope.$on('$viewHistory.viewBack', function(e, fromViewId, toViewId) { + //When going back from this view, forget its saved scroll position + if (viewId === fromViewId) { + self.forgetScrollPosition(); + } + }); + }, 1, false); } }); @@ -3716,9 +3801,13 @@ IonicModule '$scope', '$attrs', '$ionicSideMenuDelegate', -function($scope, $attrs, $ionicSideMenuDelegate) { + '$ionicPlatform', +function($scope, $attrs, $ionicSideMenuDelegate, $ionicPlatform) { + var self = this; angular.extend(this, ionic.controllers.SideMenuController.prototype); + this.$scope = $scope; + ionic.controllers.SideMenuController.call(this, { left: { width: 275 }, right: { width: 275 } @@ -3741,10 +3830,28 @@ function($scope, $attrs, $ionicSideMenuDelegate) { $scope.sideMenuContentTranslateX = 0; + + var deregisterBackButtonAction = angular.noop; + var closeSideMenu = angular.bind(this, this.close); + $scope.$watch(function() { + return self.getOpenAmount() !== 0; + }, function(isOpen) { + deregisterBackButtonAction(); + if (isOpen) { + deregisterBackButtonAction = $ionicPlatform.registerBackButtonAction( + closeSideMenu, + PLATFORM_BACK_BUTTON_PRIORITY_SIDE_MENU + ); + } + }); + var deregisterInstance = $ionicSideMenuDelegate._registerInstance( this, $attrs.delegateHandle ); - $scope.$on('$destroy', deregisterInstance); + $scope.$on('$destroy', function() { + deregisterInstance(); + deregisterBackButtonAction(); + }); }]); IonicModule @@ -3996,20 +4103,20 @@ IonicModule * Here are a few things to keep in mind while using collection-repeat: * * 1. The data supplied to collection-repeat must be an array. - * 2. You must explicitly tell the directive what size your items will be in the DOM - * (pixel amount or percentage), using directive attributes (see below). - * 3. The elements rendered will be absolutely positioned: be sure to let your CSS work with this (see below). - * 4. Keep the HTML of your repeated elements as simple as possible. As the user scrolls down, elements - * will be lazily compiled. Resultingly, the more complicated your elements, the more likely it is that - * the on-demand compilation will cause jankiness in the user's scrolling. - * 5. The more elements you render on the screen at a time, the slower the scrolling will be. - * It is recommended to keep grids of collection-repeat list elements at 3-wide or less. + * 2. You must explicitly tell the directive what size your items will be in the DOM, using directive attributes. Pixel amounts or percentages are allowed (see below). + * 3. The elements rendered will be absolutely positioned: be sure to let your CSS work with + * this (see below). + * 4. Keep the HTML of your repeated elements as simple as possible. As the user scrolls down, + * elements will be lazily compiled. Resultingly, the more complicated your elements, the more + * likely it is that the on-demand compilation will cause some jerkiness in the user's scrolling. + * 5. The more elements you render on the screen per row, the more likelihood for scrolling to + * slow down. It is recommended to keep grids of collection-repeat list elements at 3-wide or less. + * For example, if you have a gallery of images just set their width to 33%. * 6. Each collection-repeat list will take up all of its parent scrollView's space. * If you wish to have multiple lists on one page, put each list within its own * {@link ionic.directive:ionScroll ionScroll} container. * * - * * @usage * * #### Basic Usage (single rows of items) @@ -4105,6 +4212,11 @@ IonicModule * @param {expression} collection-item-height The height of the repeated element. Can be a number (in pixels), or a percentage. * */ +var COLLECTION_REPEAT_SCROLLVIEW_XY_ERROR = "Cannot create a collection-repeat within a scrollView that is scrollable on both x and y axis. Choose either x direction or y direction."; +var COLLECTION_REPEAT_ATTR_HEIGHT_ERROR = "collection-repeat expected attribute collection-item-height to be a an expression that returns a number (in pixels) or percentage."; +var COLLECTION_REPEAT_ATTR_WIDTH_ERROR = "collection-repeat expected attribute collection-item-width to be a an expression that returns a number (in pixels) or percentage."; +var COLLECTION_REPEAT_ATTR_REPEAT_ERROR = "collection-repeat expected expression in form of '_item_ in _collection_[ track by _id_]' but got '%'"; + IonicModule .directive('collectionRepeat', [ '$collectionRepeatManager', @@ -4120,14 +4232,14 @@ function($collectionRepeatManager, $collectionDataSource, $parse) { link: function($scope, $element, $attr, scrollCtrl, $transclude) { var scrollView = scrollCtrl.scrollView; if (scrollView.options.scrollingX && scrollView.options.scrollingY) { - throw new Error("Cannot create a collection-repeat within a scrollView that is scrollable on both x and y axis. Choose either x direction or y direction."); + throw new Error(COLLECTION_REPEAT_SCROLLVIEW_XY_ERROR); } var isVertical = !!scrollView.options.scrollingY; if (isVertical && !$attr.collectionItemHeight) { - throw new Error("collection-repeat expected attribute collection-item-height to be a an expression that returns a number."); + throw new Error(COLLECTION_REPEAT_ATTR_HEIGHT_ERROR); } else if (!isVertical && !$attr.collectionItemWidth) { - throw new Error("collection-repeat expected attribute collection-item-width to be a an expression that returns a number."); + throw new Error(COLLECTION_REPEAT_ATTR_WIDTH_ERROR); } $attr.collectionItemHeight = $attr.collectionItemHeight || '"100%"'; $attr.collectionItemWidth = $attr.collectionItemWidth || '"100%"'; @@ -4156,16 +4268,20 @@ function($collectionRepeatManager, $collectionDataSource, $parse) { var match = $attr.collectionRepeat.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/); if (!match) { - throw new Error("collection-repeat expected expression in form of '_item_ in _collection_[ track by _id_]' but got '" + $attr.collectionRepeat + "'."); + throw new Error(COLLECTION_REPEAT_ATTR_REPEAT_ERROR + .replace('%', $attr.collectionRepeat)); } + var keyExpr = match[1]; + var listExpr = match[2]; + var trackByExpr = match[3]; var dataSource = new $collectionDataSource({ scope: $scope, transcludeFn: $transclude, transcludeParent: $element.parent(), - keyExpr: match[1], - listExpr: match[2], - trackByExpr: match[3], + keyExpr: keyExpr, + listExpr: listExpr, + trackByExpr: trackByExpr, heightGetter: heightGetter, widthGetter: widthGetter }); @@ -4175,7 +4291,7 @@ function($collectionRepeatManager, $collectionDataSource, $parse) { scrollView: scrollCtrl.scrollView, }); - $scope.$watchCollection(dataSource.listExpr, function(value) { + $scope.$watchCollection(listExpr, function(value) { if (value && !angular.isArray(value)) { throw new Error("collection-repeat expects an array to repeat over, but instead got '" + typeof value + "'."); } @@ -4187,15 +4303,16 @@ function($collectionRepeatManager, $collectionDataSource, $parse) { dataSource.setData(value); collectionRepeatManager.resize(); } - var resize = angular.bind(collectionRepeatManager, collectionRepeatManager.resize); - ionic.on('resize', function() { - rerender($scope.$eval(dataSource.listExpr)); - }, window); + function onWindowResize() { + rerender($scope.$eval(listExpr)); + } + + ionic.on('resize', onWindowResize, window); $scope.$on('$destroy', function() { collectionRepeatManager.destroy(); dataSource.destroy(); - ionic.off('resize', resize, window); + ionic.off('resize', onWindowResize, window); }); } }; @@ -4665,8 +4782,6 @@ function($animate, $compile) { this.$scope = $scope; this.$element = $element; }], - priorty: Number.MAX_VALUE, - require: ['ionItem', '^ionList'], scope: true, compile: function($element, $attrs) { var isAnchor = angular.isDefined($attrs.href) || angular.isDefined($attrs.ngHref); @@ -5143,7 +5258,7 @@ IonicModule replace: true, template: '' + '' }; }]); @@ -5212,7 +5327,14 @@ IonicModule IonicModule .directive('ionNavBackButton', [ '$animate', -function($animate) { + '$rootScope', +function($animate, $rootScope) { + var backIsShown = false; + //If the current viewstate does not allow a back button, + //always hide it. + $rootScope.$on('$viewHistory.historyChange', function(e, data) { + backIsShown = !!data.showBack; + }); return { restrict: 'E', require: '^ionNavBar', @@ -5228,19 +5350,11 @@ function($animate) { }); } - //If the current viewstate does not allow a back button, - //always hide it. - var deregisterListener = $scope.$parent.$on( - '$viewHistory.historyChange', - function(e, data) { - $scope.hasBackButton = !!data.showBack; - } - ); - $scope.$on('$destroy', deregisterListener); - //Make sure both that a backButton is allowed in the first place, //and that it is shown by the current view. - $scope.$watch('!!(backButtonShown && hasBackButton)', ionic.animationFrameThrottle(function(show) { + $scope.$watch(function() { + return !!(backIsShown && $scope.backButtonShown); + }, ionic.animationFrameThrottle(function(show) { if (show) $animate.removeClass($element, 'ng-hide'); else $animate.addClass($element, 'ng-hide'); })); @@ -5286,6 +5400,33 @@ function($animate) { * with {@link ionic.service:$ionicNavBarDelegate}. * @param align-title {string=} Where to align the title of the navbar. * Available: 'left', 'right', 'center'. Defaults to 'center'. + * + *
+ * + * ### Alternative Usage + * + * Alternatively, you may put ion-nav-bar inside of each individual view's ion-view element. + * This will allow you to have the whole navbar, not just its contents, transition every view change. + * + * This is similar to using a header bar inside your ion-view, except it will has all the power of a navbar. + * + * If you do this, simply put nav buttons inside the navbar itself; do not use ``. + * + * + * ```html + * + * + * Back + * + *
+ * + *
+ *
+ * + * + * ``` */ IonicModule .directive('ionNavBar', [ @@ -5428,13 +5569,16 @@ IonicModule * @restrict AC * * @description - * Disables any transition animations between views, along with removing the back - * button which would normally show on the next view. This directive is useful for - * links within a sideMenu. + * nav-clear is an attribute directive which should be used with an element that changes + * the view on click, for example an `` or a `';c.factory("$ionicPopup",["$ionicTemplateLoader","$ionicBackdrop","$q","$timeout","$rootScope","$document","$compile","$ionicPlatform",function(e,t,n,i,r,o,a,s){function c(t){t=angular.extend({scope:null,title:"",buttons:[]},t||{});var r=e.compile({template:g,scope:t.scope&&t.scope.$new(),appendTo:o[0].body}),s=t.templateUrl?e.load(t.templateUrl):n.when(t.template||t.content||"");return n.all([r,s]).then(function(e){var r=e[0],o=e[1],s=n.defer();r.responseDeferred=s;var c=angular.element(r.element[0].querySelector(".popup-body"));return o?(c.html(o),a(c.contents())(r.scope)):c.remove(),angular.extend(r.scope,{title:t.title,buttons:t.buttons,subTitle:t.subTitle,$buttonTapped:function(e,t){var n=(e.onTap||angular.noop)(t);t=t.originalEvent||t,t.defaultPrevented||s.resolve(n)}}),r.show=function(){r.isShown||(r.isShown=!0,ionic.requestAnimationFrame(function(){r.isShown&&(r.element.removeClass("popup-hidden"),r.element.addClass("popup-showing active"),ionic.DomUtil.centerElementByMarginTwice(r.element[0]),d(r.element))}))},r.hide=function(e){return e=e||angular.noop,r.isShown?(r.isShown=!1,r.element.removeClass("active"),r.element.addClass("popup-hidden"),void i(e,250)):e()},r.remove=function(){r.removed||(r.hide(function(){r.element.remove(),r.scope.$destroy()}),r.removed=!0)},r})}function l(){$[0]&&$[0].responseDeferred.resolve()}function u(e){function n(e){r.then(function(t){t.removed||t.responseDeferred.resolve(e)})}var r=w._createPopup(e),o=$[0];o&&o.hide();var a=i(angular.noop,o?m.stackPushDelay:0).then(function(){return r}).then(function(e){return o||(document.body.classList.add("popup-open"),t.retain(),w._backButtonActionDone=s.registerBackButtonAction(l,v)),$.unshift(e),e.show(),e.responseDeferred.notify({close:a.close}),e.responseDeferred.promise.then(function(n){var i=$.indexOf(e);-1!==i&&$.splice(i,1),e.remove();var r=$[0];return r?r.show():(document.body.classList.remove("popup-open"),t.release(),(w._backButtonActionDone||angular.noop)()),n})});return a.close=n,a}function d(e){var t=e[0].querySelectorAll("input");t.length||(t=e[0].querySelectorAll("button"));var n=t[t.length-1];n&&n.focus()}function h(e){return u(angular.extend({buttons:[{text:e.okText||"OK",type:e.okType||"button-positive",onTap:function(){return!0}}]},e||{}))}function f(e){return u(angular.extend({buttons:[{text:e.cancelText||"Cancel",type:e.cancelType||"button-default",onTap:function(){return!1}},{text:e.okText||"OK",type:e.okType||"button-positive",onTap:function(){return!0}}]},e||{}))}function p(e){var t=r.$new(!0);return t.data={},u(angular.extend({template:'',scope:t,buttons:[{text:e.cancelText||"Cancel",type:e.cancelType||"button-default",onTap:function(){}},{text:e.okText||"OK",type:e.okType||"button-positive",onTap:function(){return t.data.response||""}}]},e||{}))}var m={stackPushDelay:50},$=[],w={show:u,alert:h,confirm:f,prompt:p,_createPopup:c,_popupStack:$};return w}]),c.service("$ionicScrollDelegate",i(["resize","scrollTop","scrollBottom","scrollTo","scrollBy","getScrollPosition","anchorScroll","getScrollView","rememberScrollPosition","forgetScrollPosition","scrollToRememberedPosition"])),c.service("$ionicSideMenuDelegate",i(["toggleLeft","toggleRight","getOpenRatio","isOpen","isOpenLeft","isOpenRight","canDragContent"])),c.service("$ionicSlideBoxDelegate",i(["update","slide","enableSlide","previous","next","stop","currentIndex","slidesCount"])),c.service("$ionicTabsDelegate",i(["select","selectedIndex"])),c.factory("$ionicTemplateLoader",["$compile","$controller","$http","$q","$rootScope","$templateCache",function(e,t,n,i,r,o){function a(e){return n.get(e,{cache:o}).then(function(e){return e.data&&e.data.trim()})}function s(n){n=angular.extend({template:"",templateUrl:"",scope:null,controller:null,locals:{},appendTo:null},n||{});var o=n.templateUrl?this.load(n.templateUrl):i.when(n.template);return o.then(function(i){var o,a=n.scope||r.$new(),s=angular.element("
").html(i).contents();return n.controller&&(o=t(n.controller,angular.extend(n.locals,{$scope:a})),s.children().data("$ngControllerController",o)),n.appendTo&&angular.element(n.appendTo).append(s),e(s)(a),{element:s,scope:a}})}return{load:a,compile:s}}]),c.run(["$rootScope","$state","$location","$document","$animate","$ionicPlatform","$ionicViewService",function(e,t,n,i,r,o,a){function s(t){return e.$viewHistory.backView?e.$viewHistory.backView.go():ionic.Platform.exitApp(),t.preventDefault(),!1}e.$viewHistory={histories:{root:{historyId:"root",parentHistoryId:null,stack:[],cursor:-1}},views:{},backView:null,forwardView:null,currentView:null,disabledRegistrableTagNames:[]},a.disableRegisterByTagName&&(a.disableRegisterByTagName("ion-tabs"),a.disableRegisterByTagName("ion-side-menus")),e.$on("viewState.changeHistory",function(i,r){if(r){var o=r.historyId?e.$viewHistory.histories[r.historyId]:null;if(o&&o.cursor>-1&&o.cursor-1&&s.stack.length>0&&s.cursor=u.index;v--)p.stack[v].destroy(),p.stack.splice(v)}}else h.navAction="initialView";r.views[h.viewId]=this.createView({viewId:h.viewId,index:s.stack.length,historyId:s.historyId,backViewId:c&&c.viewId?c.viewId:null,forwardViewId:null,stateId:o,stateName:this.getCurrentStateName(),stateParams:this.getCurrentStateParams(),url:n.url()}),"moveBack"==h.navAction&&e.$emit("$viewHistory.viewBack",c.viewId,h.viewId),s.stack.push(r.views[h.viewId])}return d&&(d.disableAnimate&&(h.navDirection=null),d.disableBack&&(r.views[h.viewId].backViewId=null),this.nextViewOptions(null)),this.setNavViews(h.viewId),s.cursor=r.currentView.index,h},setNavViews:function(t){var n=e.$viewHistory;n.currentView=this._getViewById(t),n.backView=this._getBackView(n.currentView),n.forwardView=this._getForwardView(n.currentView),e.$broadcast("$viewHistory.historyChange",{showBack:n.backView&&n.backView.historyId===n.currentView.historyId})},registerHistory:function(e){e.$historyId=ionic.Utils.nextUid()},createView:function(e){var t=new s;return t.initialize(e)},getCurrentView:function(){return e.$viewHistory.currentView},getBackView:function(){return e.$viewHistory.backView},getForwardView:function(){return e.$viewHistory.forwardView},getNavDirection:function(){return e.$viewHistory.navDirection},getCurrentStateName:function(){return t&&t.current?t.current.name:null},isCurrentStateNavView:function(e){return t&&t.current&&t.current.views&&t.current.views[e]?!0:!1},getCurrentStateParams:function(){var e;if(t&&t.params)for(var n in t.params)t.params.hasOwnProperty(n)&&(e=e||{},e[n]=t.params[n]);return e},getCurrentStateId:function(){var e;if(t&&t.current&&t.current.name){if(e=t.current.name,t.params)for(var n in t.params)t.params.hasOwnProperty(n)&&t.params[n]&&(e+="_"+n+"="+t.params[n]);return e}return ionic.Utils.nextUid()},goToHistoryRoot:function(t){if(t){var n=e.$viewHistory.histories[t];if(n&&n.stack.length){if(e.$viewHistory.currentView&&e.$viewHistory.currentView.viewId===n.stack[0].viewId)return;e.$viewHistory.forcedNav={viewId:n.stack[0].viewId,navAction:"moveBack",navDirection:"back"},n.stack[0].go()}}},_getViewById:function(t){return t?e.$viewHistory.views[t]:null},_getBackView:function(e){return e?this._getViewById(e.backViewId):null},_getForwardView:function(e){return e?this._getViewById(e.forwardViewId):null},_getHistoryById:function(t){return t?e.$viewHistory.histories[t]:null},_getHistory:function(t){var n=this._getParentHistoryObj(t);return e.$viewHistory.histories[n.historyId]||(e.$viewHistory.histories[n.historyId]={historyId:n.historyId,parentHistoryId:this._getParentHistoryObj(n.scope.$parent).historyId,stack:[],cursor:-1}),e.$viewHistory.histories[n.historyId]},_getParentHistoryObj:function(t){for(var n=t;n;){if(n.hasOwnProperty("$historyId"))return{historyId:n.$historyId,scope:n};n=n.$parent}return{historyId:"root",scope:e}},nextViewOptions:function(e){return arguments.length?void(this._nextOpts=e):this._nextOpts},getRenderer:function(e,t,n){function i(e){for(var t="";!t&&e;)t=e.getAttribute("animation"),e=e.parentElement;return t}function r(){l&&e[0].classList.add(l),"back"===a.navDirection?e[0].classList.add("reverse"):e[0].classList.remove("reverse")}var a,s,c=this,l=i(e[0]);return function(t){return{enter:function(n){return s&&t?(r(),n.addClass("ng-enter"),document.body.classList.add("disable-pointer-events"),void o.enter(n,e,null,function(){document.body.classList.remove("disable-pointer-events"),l&&e[0].classList.remove(l)})):void e.append(n)},leave:function(){var n=e.contents();return s&&t?(r(),void o.leave(n,function(){n.remove()})):void n.remove()},register:function(e){return a=c.register(n,e),s=null!==l&&null!==a.navDirection,a}}}},disableRegisterByTagName:function(t){e.$viewHistory.disabledRegistrableTagNames.push(t.toUpperCase())},isTagNameRegistrable:function(t){var n,i,r=e.$viewHistory.disabledRegistrableTagNames;for(n=0;n')(e),angular.element(a[0]).replaceWith(n)),i=o('

')(e),ionic.requestAnimationFrame(function(){n&&r.leave(angular.element(n)); -var o=n&&angular.element(n)||null;r.enter(i,t,o,function(){c._headerBarView.align()}),angular.forEach(a,function(e){e&&e.parentNode&&angular.element(e).remove()}),e.$digest(),ionic.requestAnimationFrame(function(){i[0].classList.remove("invisible")})})}}]),c.factory("$$scrollValueCache",function(){return{}}).controller("$ionicScroll",["$scope","scrollViewOptions","$timeout","$window","$$scrollValueCache","$location","$rootScope","$document","$ionicScrollDelegate",function(e,t,n,i,r,o,a,s,c){var l=this;this._scrollViewOptions=t;var u=this.element=t.el,d=this.$element=angular.element(u),h=this.scrollView=new ionic.views.Scroll(t);(d.parent().length?d.parent():d).data("$$ionicScrollController",this);var f=c._registerInstance(this,t.delegateHandle);angular.isDefined(t.bouncing)||ionic.Platform.ready(function(){h.options.bouncing=!ionic.Platform.isAndroid()});var p=angular.bind(h,h.resize);ionic.on("resize",p,i);var v=angular.noop;e.$on("$destroy",function(){f(),ionic.off("resize",p,i),i.removeEventListener("resize",p),v(),l._rememberScrollId&&(r[l._rememberScrollId]=h.getValues())}),d.on("scroll",function(t){var n=(t.originalEvent||t).detail||{};e.$onScroll&&e.$onScroll({event:t,scrollTop:n.scrollTop||0,scrollLeft:n.scrollLeft||0})}),e.$on("$viewContentLoaded",function(e,t){if(!e.defaultPrevented){e.preventDefault();var n=t&&t.viewId;n&&(l.rememberScrollPosition(n),l.scrollToRememberedPosition(),v=a.$on("$viewHistory.viewBack",function(e,t){n===t&&l.forgetScrollPosition()}))}}),n(function(){h.run()}),this._rememberScrollId=null,this.getScrollView=function(){return this.scrollView},this.getScrollPosition=function(){return this.scrollView.getValues()},this.resize=function(){return n(p)},this.scrollTop=function(e){this.resize().then(function(){h.scrollTo(0,0,!!e)})},this.scrollBottom=function(e){this.resize().then(function(){var t=h.getScrollMax();h.scrollTo(t.left,t.top,!!e)})},this.scrollTo=function(e,t,n){this.resize().then(function(){h.scrollTo(e,t,!!n)})},this.scrollBy=function(e,t,n){this.resize().then(function(){h.scrollBy(e,t,!!n)})},this.anchorScroll=function(e){this.resize().then(function(){var t=o.hash(),n=t&&s[0].getElementById(t);if(t&&n){var i=ionic.DomUtil.getPositionInParent(n,l.$element);h.scrollTo(i.left,i.top,!!e)}else h.scrollTo(0,0,!!e)})},this.rememberScrollPosition=function(e){if(!e)throw new Error("Must supply an id to remember the scroll by!");this._rememberScrollId=e},this.forgetScrollPosition=function(){delete r[this._rememberScrollId],this._rememberScrollId=null},this.scrollToRememberedPosition=function(e){var t=r[this._rememberScrollId];t&&this.resize().then(function(){h.scrollTo(+t.left,+t.top,e)})},this._setRefresher=function(e,t){var n=this.refresher=t,i=l.refresher.clientHeight||0;h.activatePullToRefresh(i,function(){n.classList.add("active"),e.$onPulling()},function(){n.classList.remove("refreshing"),n.classList.remove("active")},function(){n.classList.add("refreshing"),e.$onRefresh()})}}]),c.controller("$ionicSideMenus",["$scope","$attrs","$ionicSideMenuDelegate",function(e,t,n){angular.extend(this,ionic.controllers.SideMenuController.prototype),ionic.controllers.SideMenuController.call(this,{left:{width:275},right:{width:275}}),this.canDragContent=function(t){return arguments.length&&(e.dragContent=!!t),e.dragContent},this.isDraggableTarget=function(t){return e.dragContent&&!t.gesture.srcEvent.defaultPrevented&&!t.target.tagName.match(/input|textarea|select|object|embed/i)&&!t.target.isContentEditable&&!(t.target.dataset?t.target.dataset.preventScroll:"true"==t.target.getAttribute("data-prevent-default"))},e.sideMenuContentTranslateX=0;var i=n._registerInstance(this,t.delegateHandle);e.$on("$destroy",i)}]),c.controller("$ionicTab",["$scope","$ionicViewService","$attrs","$location","$state",function(e,t,n,i,r){this.$scope=e,this.hrefMatchesState=function(){return n.href&&0===i.path().indexOf(n.href.replace(/^#/,"").replace(/\/$/,""))},this.srefMatchesState=function(){return n.uiSref&&r.includes(n.uiSref.split("(")[0])},this.navNameMatchesState=function(){return this.navViewName&&t.isCurrentStateNavView(this.navViewName)},this.tabMatchesState=function(){return this.hrefMatchesState()||this.srefMatchesState()||this.navNameMatchesState()}}]),c.controller("$ionicTabs",["$scope","$ionicViewService","$element",function(e,t){var n=null,i=this;i.tabs=[],i.selectedIndex=function(){return i.tabs.indexOf(n)},i.selectedTab=function(){return n},i.add=function(e){t.registerHistory(e),i.tabs.push(e),1===i.tabs.length&&i.select(e)},i.remove=function(e){var t=i.tabs.indexOf(e);if(-1!==t){if(e.$tabSelected)if(i.deselect(e),1===i.tabs.length);else{var n=t===i.tabs.length-1?t-1:t+1;i.select(i.tabs[n])}i.tabs.splice(t,1)}},i.deselect=function(e){e.$tabSelected&&(n=null,e.$tabSelected=!1,(e.onDeselect||angular.noop)())},i.select=function(r,o){var a;if(angular.isNumber(r)?(a=r,r=i.tabs[a]):a=i.tabs.indexOf(r),!r||-1==a)throw new Error('Cannot select tab "'+a+'"!');if(n&&n.$historyId==r.$historyId)o&&t.goToHistoryRoot(r.$historyId);else if(angular.forEach(i.tabs,function(e){i.deselect(e)}),n=r,r.$tabSelected=!0,(r.onSelect||angular.noop)(),o){var s={type:"tab",tabIndex:a,historyId:r.$historyId,navViewName:r.navViewName,hasNavView:!!r.navViewName,title:r.title,url:r.href,uiSref:r.uiSref};e.$emit("viewState.changeHistory",s)}}}]),c.directive("ionActionSheet",["$document",function(e){return{restrict:"E",scope:!0,replace:!0,link:function(t,n){var i=function(e){27==e.which&&(t.cancel(),t.$apply())},r=function(e){e.target==n[0]&&(t.cancel(),t.$apply())};t.$on("$destroy",function(){n.remove(),e.unbind("keyup",i)}),e.bind("keyup",i),n.bind("click",r)},template:'
'}}]),c.directive("ionCheckbox",function(){return{restrict:"E",replace:!0,require:"?ngModel",scope:{ngModel:"=?",ngValue:"=?",ngChecked:"=?",ngDisabled:"=?",ngChange:"&"},transclude:!0,template:'',compile:function(e,t){var n=e.find("input");t.name&&n.attr("name",t.name),t.ngChecked&&n.attr("ng-checked",t.ngChecked),t.ngDisabled&&n.attr("ng-disabled",t.ngDisabled),t.ngTrueValue&&n.attr("ng-true-value",t.ngTrueValue),t.ngFalseValue&&n.attr("ng-false-value",t.ngFalseValue)}}}),c.directive("collectionRepeat",["$collectionRepeatManager","$collectionDataSource","$parse",function(e,t,n){return{priority:1e3,transclude:"element",terminal:!0,$$tlb:!0,require:"^$ionicScroll",link:function(i,r,o,a,s){function c(e){l.resize(),g.setData(e),m.resize()}var l=a.scrollView;if(l.options.scrollingX&&l.options.scrollingY)throw new Error("Cannot create a collection-repeat within a scrollView that is scrollable on both x and y axis. Choose either x direction or y direction.");var u=!!l.options.scrollingY;if(u&&!o.collectionItemHeight)throw new Error("collection-repeat expected attribute collection-item-height to be a an expression that returns a number.");if(!u&&!o.collectionItemWidth)throw new Error("collection-repeat expected attribute collection-item-width to be a an expression that returns a number.");o.collectionItemHeight=o.collectionItemHeight||'"100%"',o.collectionItemWidth=o.collectionItemWidth||'"100%"';var d=o.collectionItemHeight?n(o.collectionItemHeight):function(){return l.__clientHeight},h=o.collectionItemWidth?n(o.collectionItemWidth):function(){return l.__clientWidth},f=function(e,t){var n=d(e,t);return angular.isString(n)&&n.indexOf("%")>-1?Math.floor(parseInt(n,10)/100*l.__clientHeight):n},p=function(e,t){var n=h(e,t);return angular.isString(n)&&n.indexOf("%")>-1?Math.floor(parseInt(n,10)/100*l.__clientWidth):n},v=o.collectionRepeat.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);if(!v)throw new Error("collection-repeat expected expression in form of '_item_ in _collection_[ track by _id_]' but got '"+o.collectionRepeat+"'.");var g=new t({scope:i,transcludeFn:s,transcludeParent:r.parent(),keyExpr:v[1],listExpr:v[2],trackByExpr:v[3],heightGetter:f,widthGetter:p}),m=new e({dataSource:g,element:a.$element,scrollView:a.scrollView});i.$watchCollection(g.listExpr,function(e){if(e&&!angular.isArray(e))throw new Error("collection-repeat expects an array to repeat over, but instead got '"+typeof e+"'.");c(e)});var $=angular.bind(m,m.resize);ionic.on("resize",function(){c(i.$eval(g.listExpr))},window),i.$on("$destroy",function(){m.destroy(),g.destroy(),ionic.off("resize",$,window)})}}}]),c.directive("ionContent",["$timeout","$controller","$ionicBind",function(e,t,n){return{restrict:"E",require:"^?ionNavView",scope:!0,priority:800,compile:function(e,i){function r(e,r,a){var s=e.$parent;e.$watch(function(){return(s.$hasHeader?" has-header":"")+(s.$hasSubheader?" has-subheader":"")+(s.$hasFooter?" has-footer":"")+(s.$hasSubfooter?" has-subfooter":"")+(s.$hasTabs?" has-tabs":"")+(s.$hasTabsTop?" has-tabs-top":"")},function(e,t){r.removeClass(t),r.addClass(e)}),e.$hasHeader=e.$hasSubheader=e.$hasFooter=e.$hasSubfooter=e.$hasTabs=e.$hasTabsTop=!1,n(e,a,{$onScroll:"&onScroll",$onScrollComplete:"&onScrollComplete",hasBouncing:"@",scroll:"@",padding:"@",hasScrollX:"@",hasScrollY:"@",scrollbarX:"@",scrollbarY:"@",startX:"@",startY:"@",scrollEventInterval:"@"}),angular.isDefined(a.padding)&&e.$watch(a.padding,function(e){(o||r).toggleClass("padding",!!e)}),"false"===e.scroll||("true"===i.overflowScroll?r.addClass("overflow-scroll"):t("$ionicScroll",{$scope:e,scrollViewOptions:{el:r[0],delegateHandle:i.delegateHandle,bouncing:e.$eval(e.hasBouncing),startX:e.$eval(e.startX)||0,startY:e.$eval(e.startY)||0,scrollbarX:e.$eval(e.scrollbarX)!==!1,scrollbarY:e.$eval(e.scrollbarY)!==!1,scrollingX:e.$eval(e.hasScrollX)===!0,scrollingY:e.$eval(e.hasScrollY)!==!1,scrollEventInterval:parseInt(e.scrollEventInterval,10)||10,scrollingComplete:function(){e.$onScrollComplete({scrollTop:this.__scrollTop,scrollLeft:this.__scrollLeft})}}}))}var o;return e.addClass("scroll-content"),"false"!=i.scroll&&(o=angular.element('
'),o.append(e.contents()),e.append(o)),{pre:r}}}}]),c.directive("ionNavBar",r()).directive("ionHeaderBar",r()).directive("ionHeaderBar",o(!0)).directive("ionFooterBar",o(!1)),c.directive("ionInfiniteScroll",["$timeout",function(e){function t(e,t,n){return n?t*(1-parseInt(e,10)/100):t-parseInt(e,10)}return{restrict:"E",require:["^$ionicScroll","ionInfiniteScroll"],template:'
',scope:!0,controller:["$scope","$attrs",function(e,n){this.isLoading=!1,this.scrollView=null,this.getMaxScroll=function(){var e=(n.distance||"1%").trim(),i=-1!==e.indexOf("%"),r=this.scrollView.getScrollMax();return{left:this.scrollView.options.scrollingX?t(e,r.left,i):-1,top:this.scrollView.options.scrollingY?t(e,r.top,i):-1}}}],link:function(t,n,i,r){function o(){if(!s.isLoading){var e=c.getValues(),t=s.getMaxScroll();(-1!==t.left&&e.left>=t.left||-1!==t.top&&e.top>=t.top)&&l()}}var a=r[0],s=r[1],c=s.scrollView=a.scrollView;t.icon=function(){return angular.isDefined(i.icon)?i.icon:"ion-loading-d"};var l=function(){n[0].classList.add("active"),s.isLoading=!0,t.$parent&&t.$parent.$apply(i.onInfinite||"")},u=function(){n[0].classList.remove("active"),e(function(){c.resize()},0,!1),s.isLoading=!1};t.$on("scroll.infiniteScrollComplete",function(){u()}),t.$on("$destroy",function(){a.$element.off("scroll",d)});var d=ionic.animationFrameThrottle(o);setTimeout(d),a.$element.on("scroll",d)}}}]);var m='',$='
';c.directive("ionItem",["$animate","$compile",function(){return{restrict:"E",controller:["$scope","$element",function(e,t){this.$scope=e,this.$element=t}],priorty:Number.MAX_VALUE,require:["ionItem","^ionList"],scope:!0,compile:function(e,t){var n=angular.isDefined(t.href)||angular.isDefined(t.ngHref),i=n||/ion-(delete|option|reorder)-button/i.test(e.html());if(i){var r=angular.element(n?m:$);r.append(e.contents()),e.append(r),e.addClass("item item-complex")}else e.addClass("item");return function(e,t,n){e.$href=function(){return n.href||n.ngHref}}}}}]);var w='
';c.directive("ionDeleteButton",["$animate",function(e){return{restrict:"E",require:["^ionItem","^ionList"],priority:Number.MAX_VALUE,compile:function(t,n){return n.$set("class",(n["class"]||"")+" button icon button-icon",!0),function(t,n,i,r){var o=r[0],a=r[1],s=angular.element(w);s.append(n),o.$element.append(s).addClass("item-left-editable"),a.showDelete()&&e.removeClass(s,"ng-hide")}}}}]);var b='';c.directive("ionOptionButton",["$compile",function(){return{restrict:"E",require:"^ionItem",priority:Number.MAX_VALUE,compile:function(e,t){return t.$set("class",(t["class"]||"")+" button",!0),function(e,t,n,i){i.optionsContainer||(i.optionsContainer=angular.element(b),i.$element.append(i.optionsContainer)),i.optionsContainer.append(t),t.on("click",a)}}}}]);var y='
';c.directive("ionReorderButton",["$animate",function(e){return{restrict:"E",require:["^ionItem","^ionList"],priority:Number.MAX_VALUE,compile:function(t,n){return n.$set("class",(n["class"]||"")+" button icon button-icon",!0),t[0].setAttribute("data-prevent-scroll",!0),function(t,n,i,r){var o=r[0],a=r[1];t.$onReorder=function(e,n){t.$eval(i.onReorder,{$fromIndex:e,$toIndex:n})};var s=angular.element(y);s.append(n),o.$element.append(s).addClass("item-right-editable"),a.showReorder()&&e.removeClass(s,"ng-hide")}}}}]),c.directive("ionList",["$animate","$timeout",function(e,t){return{restrict:"E",require:["ionList","^?$ionicScroll"],controller:"$ionicList",compile:function(n,i){var r=angular.element('
').append(n.contents());return n.append(r),function(n,r,o,a){function s(){function t(t,n){angular.forEach(r[0].querySelectorAll(t),function(t){n?e.removeClass(angular.element(t),"ng-hide"):e.addClass(angular.element(t),"ng-hide")})}function o(e,t){var n=angular.element(r[0].querySelectorAll(e));t?n.attr("data-tap-disabled","true"):n.removeAttr("data-tap-disabled")}c.listView=new ionic.views.ListView({el:r[0],listEl:r.children()[0],scrollEl:l&&l.element,scrollView:l&&l.scrollView,onReorder:function(e,t,n){var i=angular.element(e).scope();i&&i.$onReorder&&i.$onReorder(t,n)},canSwipe:function(){return c.canSwipeItems()}});angular.isDefined(i.canSwipe)&&n.$watch("!!("+i.canSwipe+")",function(e){c.canSwipeItems(e)}),angular.isDefined(i.showDelete)&&n.$watch("!!("+i.showDelete+")",function(e){c.showDelete(e)}),angular.isDefined(i.showReorder)&&n.$watch("!!("+i.showReorder+")",function(e){c.showReorder(e)}),n.$watch(function(){return c.showDelete()},function(e,n){(e||n)&&(e&&c.closeOptionButtons(),c.canSwipeItems(!e),r.children().toggleClass("list-left-editing",e),t(".item-delete.item-left-edit",e),o(".item-content",e))}),n.$watch(function(){return c.showReorder()},function(e,n){(e||n)&&(e&&c.closeOptionButtons(),c.canSwipeItems(!e),r.children().toggleClass("list-right-editing",e),t(".item-reorder.item-right-edit",e),o(".item-content",e))})}var c=a[0],l=a[1];t(s)}}}}]),c.directive("menuClose",["$ionicViewService",function(){return{restrict:"AC",require:"^ionSideMenus",link:function(e,t,n,i){t.bind("click",function(){i.close()})}}}]),c.directive("menuToggle",["$ionicViewService",function(){return{restrict:"AC",require:"^ionSideMenus",link:function(e,t,n,i){var r=n.menuToggle||"left";t.bind("click",function(){"left"===r?i.toggleLeft():"right"===r&&i.toggleRight()})}}}]),c.directive("ionModal",[function(){return{restrict:"E",transclude:!0,replace:!0,template:''}}]),c.directive("ionNavBackButton",["$animate",function(e){return{restrict:"E",require:"^ionNavBar",compile:function(t){return t.addClass("button back-button ng-hide"),function(t,n,i,r){i.ngClick||(t.$navBack=r.back,n.on("click",function(e){t.$apply(function(){t.$navBack(e)})}));var o=t.$parent.$on("$viewHistory.historyChange",function(e,n){t.hasBackButton=!!n.showBack});t.$on("$destroy",o),t.$watch("!!(backButtonShown && hasBackButton)",ionic.animationFrameThrottle(function(t){t?e.removeClass(n,"ng-hide"):e.addClass(n,"ng-hide")}))}}}}]),c.directive("ionNavBar",["$ionicViewService","$rootScope","$animate","$compile",function(){return{restrict:"E",controller:"$ionicNavBar",scope:!0,compile:function(e){function t(e,t,n,i){i._headerBarView=new ionic.views.HeaderBar({el:t[0],alignTitle:n.alignTitle||"center"}),e.backButtonShown=!1,e.shouldAnimate=!0,e.isReverse=!1,e.isInvisible=!0,e.$on("$destroy",function(){e.$parent.$hasHeader=!1}),e.$watch(function(){return(e.isReverse?" reverse":"")+(e.isInvisible?" invisible":"")+(e.shouldAnimate?"":" no-animation")},function(e,n){t.removeClass(n),t.addClass(e)})}return e.addClass("bar bar-header nav-bar").append('

'),{pre:t}}}}]),c.directive("ionNavButtons",["$compile","$animate",function(e,t){return{require:"^ionNavBar",restrict:"E",compile:function(n){var i=n.contents().remove();return function(n,r,o,a){var s="right"===o.side?a.rightButtonsElement:a.leftButtonsElement,c=angular.element("").append(i);r.append(c),e(c)(n),ionic.requestAnimationFrame(function(){t.enter(c,s)}),n.$on("$destroy",function(){t.leave(c)}),r.css("display","none")}}}}]),c.directive("navClear",["$ionicViewService","$state","$location","$window","$rootScope",function(e,t,n,i,r){return r.$on("$stateChangeError",function(){e.nextViewOptions(null)}),{priority:100,restrict:"AC",compile:function(){function t(t,n){function r(){o=t.$on("$stateChangeStart",function(){e.nextViewOptions({disableAnimate:!0,disableBack:!0}),o()}),i.setTimeout(o,300)}var o;n.on("click",r)}return{pre:t}}}}]),c.directive("ionNavView",["$ionicViewService","$state","$compile","$controller","$animate",function(e,t,n,i,r){var o=!1,a={restrict:"E",terminal:!0,priority:2e3,transclude:!0,controller:function(){},compile:function(s,c,l){return function(s,c,u){function d(o){r.enabled()===!1&&(o=!1);var a=t.$current&&t.$current.locals[p];if(a!==f){var l=e.getRenderer(c,u,s);if(h&&(h.$destroy(),h=null),!a)return f=null,$.state=null,c.append(g);var d=angular.element("
").html(a.$template).contents(),m=l().register(d);l(o).leave(),f=a,$.state=a.$$state,l(o).enter(d);var w=n(d);if(h=s.$new(),h.$navDirection=m.navDirection,a.$$controller){a.$scope=h;var b=i(a.$$controller,a);c.children().data("$ngControllerController",b)}w(h);var y=e._getViewById(m.viewId)||{};h.$broadcast("$viewContentLoaded",y),v&&h.$eval(v),d=null}}var h,f,p=u[a.name]||u.name||"",v=u.onload||"",g=l(s);c.append(g);var m=c.parent().inheritedData("$uiView");p.indexOf("@")<0&&(p=p+"@"+(m?m.state.name:""));var $={name:p,state:null};c.data("$uiView",$);var w=function(){if(!o){o=!0;try{d(!0)}catch(e){throw o=!1,e}o=!1}};s.$on("$stateChangeSuccess",w),d(!1)}}};return a}]),c.config(["$provide",function(e){e.decorator("ngClickDirective",["$delegate",function(e){return e.shift(),e}])}]).factory("$ionicNgClick",["$parse",function(e){return function(t,n,i){var r=e(i);n.on("click",function(e){t.$apply(function(){r(t,{$event:e})})}),n.onclick=function(){}}}]).directive("ngClick",["$ionicNgClick",function(e){return function(t,n,i){e(t,n,i.ngClick)}}]).directive("ionStopEvent",function(){return{restrict:"A",link:function(e,t,n){t.bind(n.ionStopEvent,a)}}}),c.directive("ionPane",function(){return{restrict:"E",link:function(e,t){t.addClass("pane")}}}),c.directive("ionRadio",function(){return{restrict:"E",replace:!0,require:"?ngModel",scope:{ngModel:"=?",ngValue:"=?",ngChange:"&",icon:"@",name:"@"},transclude:!0,template:'',compile:function(e,t){t.name&&e.children().eq(0).attr("name",t.name),t.icon&&e.children().eq(2).removeClass("ion-checkmark").addClass(t.icon)}}}),c.directive("ionRefresher",["$ionicBind",function(e){return{restrict:"E",replace:!0,require:"^$ionicScroll",template:'
',compile:function(t,n){return angular.isUndefined(n.pullingIcon)&&n.$set("pullingIcon","ion-arrow-down-c"),angular.isUndefined(n.refreshingIcon)&&n.$set("refreshingIcon","ion-loading-d"),function(t,n,i,r){e(t,i,{pullingIcon:"@",pullingText:"@",refreshingIcon:"@",refreshingText:"@",$onRefresh:"&onRefresh",$onPulling:"&onPulling"}),r._setRefresher(t,n[0]),t.$on("scroll.refreshComplete",function(){n[0].classList.remove("active"),r.scrollView.finishPullToRefresh()})}}}}]),c.directive("ionScroll",["$timeout","$controller","$ionicBind",function(e,t,n){return{restrict:"E",scope:!0,controller:function(){},compile:function(e){function i(e,i,o){var a,s;n(e,o,{direction:"@",paging:"@",$onScroll:"&onScroll",scroll:"@",scrollbarX:"@",scrollbarY:"@",zooming:"@",minZoom:"@",maxZoom:"@"}),angular.isDefined(o.padding)&&e.$watch(o.padding,function(e){r.toggleClass("padding",!!e)}),e.$eval(e.paging)===!0&&r.addClass("scroll-paging"),e.direction||(e.direction="y");var c=e.$eval(e.paging)===!0,l={el:i[0],delegateHandle:o.delegateHandle,paging:c,scrollbarX:e.$eval(e.scrollbarX)!==!1,scrollbarY:e.$eval(e.scrollbarY)!==!1,scrollingX:e.direction.indexOf("x")>=0,scrollingY:e.direction.indexOf("y")>=0,zooming:e.$eval(e.zooming)===!0,maxZoom:e.$eval(e.maxZoom)||3,minZoom:e.$eval(e.minZoom)||.5};c&&(l.speedMultiplier=.8,l.bouncing=!1),s=t("$ionicScroll",{$scope:e,scrollViewOptions:l}),a=e.$parent.scrollView=s.scrollView}e.addClass("scroll-view");var r=angular.element('
');return r.append(e.contents()),e.append(r),{pre:i}}}}]),c.directive("ionSideMenu",function(){return{restrict:"E",require:"^ionSideMenus",scope:!0,compile:function(e,t){return angular.isUndefined(t.isEnabled)&&t.$set("isEnabled","true"),angular.isUndefined(t.width)&&t.$set("width","275"),e.addClass("menu menu-"+t.side),function(e,t,n,i){e.side=n.side||"left";var r=i[e.side]=new ionic.views.SideMenu({width:275,el:t[0],isEnabled:!0});e.$watch(n.width,function(e){var t=+e;t&&t==e&&r.setWidth(+e)}),e.$watch(n.isEnabled,function(e){r.setIsEnabled(!!e)})}}}}),c.directive("ionSideMenuContent",["$timeout","$ionicGesture",function(e,t){return{restrict:"EA",require:"^ionSideMenus",scope:!0,compile:function(n,i){function r(n,r,o,a){function s(e){0!==a.getOpenAmount()&&(a.close(),e.gesture.srcEvent.preventDefault())}r.addClass("menu-content pane"),angular.isDefined(i.dragContent)?n.$watch(i.dragContent,function(e){a.canDragContent(e)}):a.canDragContent(!0);var c=!1,l=!1;ionic.on("tap",s,r[0]);var u=function(e){!c&&a.isDraggableTarget(e)&&(l=!0,a._handleDrag(e),e.gesture.srcEvent.preventDefault())},d=function(e){l&&e.gesture.srcEvent.preventDefault()},h=t.on("dragright",u,r),f=t.on("dragleft",u,r),p=t.on("dragup",d,r),v=t.on("dragdown",d,r),g=function(e){l=!1,c||a._endDrag(e),c=!1},m=t.on("release",g,r);a.setContent({onDrag:function(){},endDrag:function(){},getTranslateX:function(){return n.sideMenuContentTranslateX||0},setTranslateX:ionic.animationFrameThrottle(function(t){r[0].style[ionic.CSS.TRANSFORM]="translate3d("+t+"px, 0, 0)",e(function(){n.sideMenuContentTranslateX=t})}),enableAnimation:function(){n.animationEnabled=!0,r[0].classList.add("menu-animated")},disableAnimation:function(){n.animationEnabled=!1,r[0].classList.remove("menu-animated")}}),n.$on("$destroy",function(){t.off(f,"dragleft",u),t.off(h,"dragright",u),t.off(p,"dragup",u),t.off(v,"dragdown",u),t.off(m,"release",g),ionic.off("tap",s,r[0])})}return{pre:r}}}}]),c.directive("ionSideMenus",[function(){return{restrict:"ECA",replace:!0,transclude:!0,controller:"$ionicSideMenus",template:'
'}}]),c.directive("ionSlideBox",["$timeout","$compile","$ionicSlideBoxDelegate",function(e,t,n){return{restrict:"E",replace:!0,transclude:!0,scope:{doesContinue:"@",slideInterval:"@",showPager:"@",pagerClick:"&",disableScroll:"@",onSlideChanged:"&",activeSlide:"=?"},controller:["$scope","$element","$attrs",function(t,i,r){var o=t.$eval(t.doesContinue)===!0,a=o?t.$eval(t.slideInterval)||4e3:0,s=new ionic.views.Slider({el:i[0],auto:a,disableScroll:t.$eval(t.disableScroll)===!0||!1,continuous:o,startSlide:t.activeSlide,slidesChanged:function(){t.currentSlide=s.currentIndex(),e(function(){})},callback:function(n){t.currentSlide=n,t.onSlideChanged({index:t.currentSlide}),t.$parent.$broadcast("slideBox.slideChanged",n),t.activeSlide=n,e(function(){})}});t.$watch("activeSlide",function(e){angular.isDefined(e)&&s.slide(e)}),t.$on("slideBox.nextSlide",function(){s.next()}),t.$on("slideBox.prevSlide",function(){s.prev()}),t.$on("slideBox.setSlide",function(e,t){s.slide(t)}),this.__slider=s;var c=n._registerInstance(s,r.delegateHandle);t.$on("$destroy",c),this.slidesCount=function(){return s.slidesCount()},this.onPagerClick=function(e){t.pagerClick({index:e})},e(function(){s.load()})}],template:'
',link:function(e,n){if(e.$eval(e.showPager)!==!1){var i=e.$new(),r=angular.element("");n.append(r),t(r)(i)}}}}]).directive("ionSlide",function(){return{restrict:"E",require:"^ionSlideBox",compile:function(e){return e.addClass("slider-slide"),function(){}}}}).directive("ionPager",function(){return{restrict:"E",replace:!0,require:"^ionSlideBox",template:'
',link:function(e,t,n,i){var r=function(e){for(var n=t[0].children,i=n.length,r=0;i>r;r++)r==e?n[r].classList.add("active"):n[r].classList.remove("active")};e.pagerClick=function(e){i.onPagerClick(e)},e.numSlides=function(){return new Array(i.slidesCount())},e.$watch("currentSlide",function(e){r(e)})}}}),c.directive("ionTab",["$rootScope","$animate","$ionicBind","$compile",function(e,t,n,i){function r(e,t){return angular.isDefined(t)?" "+e+'="'+t+'"':""}return{restrict:"E",require:["^ionTabs","ionTab"],replace:!0,controller:"$ionicTab",scope:!0,compile:function(e,o){var a="",s=angular.element('
').append(e.contents().remove());return function(e,r,o,c){function l(){f.tabMatchesState()&&h.select(e)}var u,d,h=c[0],f=c[1],p=s[0].querySelector("ion-nav-view")||s[0].querySelector("data-ion-nav-view"),v=p&&p.getAttribute("name");n(e,o,{animate:"=",onSelect:"&",onDeselect:"&",title:"@",uiSref:"@",href:"@"}),h.add(e),e.$on("$destroy",function(){h.remove(e),g.isolateScope().$destroy(),g.remove()}),r[0].removeAttribute("title"),v&&(f.navViewName=v),e.$on("$stateChangeSuccess",l),l();var g=angular.element(a);g.data("$ionTabsController",h),g.data("$ionTabController",f),h.$tabsElement.append(i(g)(e)),e.$watch("$tabSelected",function(n){u&&u.$destroy(),u=null,d&&t.leave(d),d=null,n&&(u=e.$new(),d=s.clone(),t.enter(d,h.$element),i(d)(u))})}}}}]),c.directive("ionTabNav",[function(){return{restrict:"E",replace:!0,require:["^ionTabs","^ionTab"],template:'{{badge}}',scope:{title:"@",icon:"@",iconOn:"@",iconOff:"@",badge:"=",badgeStyle:"@"},compile:function(){return function(e,t,n,i){var r=i[0],o=i[1];t[0].removeAttribute("title"),e.selectTab=function(e){e.preventDefault(),r.select(o.$scope,!0)},n.ngClick||t.on("click",function(t){e.$apply(function(){e.selectTab(t)})}),e.getIconOn=function(){return e.iconOn||e.icon},e.getIconOff=function(){return e.iconOff||e.icon},e.isTabActive=function(){return r.selectedTab()===o.$scope}}}}}]),c.directive("ionTabs",["$ionicViewService","$ionicTabsDelegate",function(e,t){return{restrict:"E",scope:!0,controller:"$ionicTabs",compile:function(e){function n(e,n,i,r){var o=t._registerInstance(r,i.delegateHandle);e.$on("$destroy",o),r.$scope=e,r.$element=n,r.$tabsElement=angular.element(n[0].querySelector(".tabs"));var a=n[0];e.$watch(function(){return a.className},function(t){var n=-1!==t.indexOf("tabs-top"),i=-1!==t.indexOf("tabs-item-hide");e.$hasTabs=!n&&!i,e.$hasTabsTop=n&&!i}),e.$on("$destroy",function(){delete e.$hasTabs,delete e.$hasTabsTop})}e.addClass("view");var i=angular.element('
');return i.append(e.contents()),e.append(i),{pre:n}}}}]),c.directive("ionToggle",["$ionicGesture","$timeout",function(){return{restrict:"E",replace:!0,require:"?ngModel",scope:{ngModel:"=?",ngValue:"=?",ngChecked:"=?",ngChange:"&",ngDisabled:"=?"},transclude:!0,template:'
',compile:function(e,t){var n=e.find("input");return t.name&&n.attr("name",t.name),t.ngChecked&&n.attr("ng-checked","ngChecked"),t.ngTrueValue&&n.attr("ng-true-value",t.ngTrueValue),t.ngFalseValue&&n.attr("ng-false-value",t.ngFalseValue),function(e,t){var n,i,r,o;n=t[0].getElementsByTagName("label")[0],i=n.children[0],r=n.children[1],o=r.children[0];var a=angular.element(i).controller("ngModel");e.toggle=new ionic.views.Toggle({el:n,track:r,checkbox:i,handle:o,onChange:function(){a.$setViewValue(i.checked?!0:!1),e.$apply()}}),e.$on("$destroy",function(){e.toggle.destroy()})}}}}]),c.directive("ionView",["$ionicViewService","$rootScope","$animate",function(){return{restrict:"EA",priority:1e3,require:"^?ionNavBar",compile:function(e){return e.addClass("pane"),e[0].removeAttribute("title"),function(e,t,n,i){if(i){if(angular.isDefined(n.title)){var r=n.title;i.changeTitle(r,e.$navDirection),n.$observe("title",function(e){e!==r&&i.setTitle(e)})}var o=angular.isDefined(n.hideBackButton)?n.hideBackButton:"false";e.$watch(o,function(e){i.showBackButton(!e)});var a=angular.isDefined(n.hideNavBar)?n.hideNavBar:"false";e.$watch(a,function(e){i.showBar(!e)})}}}}}])}(); \ No newline at end of file +!function(){function e(e){var t,n=typeof e;return"object"==n&&null!==e?"function"==typeof(t=e.$$hashKey)?t=e.$$hashKey():void 0===t&&(t=e.$$hashKey=ionic.Utils.nextUid()):t=e,n+":"+t}function t(e){if(e.$root!==e){var t=e.$parent;e.$$disconnected=!0,t.$$childHead===e&&(t.$$childHead=e.$$nextSibling),t.$$childTail===e&&(t.$$childTail=e.$$prevSibling),e.$$prevSibling&&(e.$$prevSibling.$$nextSibling=e.$$nextSibling),e.$$nextSibling&&(e.$$nextSibling.$$prevSibling=e.$$prevSibling),e.$$nextSibling=e.$$prevSibling=null}}function n(e){if(e.$root!==e&&e.$$disconnected){var t=e.$parent;e.$$disconnected=!1,e.$$prevSibling=t.$$childTail,t.$$childHead?(t.$$childTail.$$nextSibling=e,t.$$childTail=e):t.$$childHead=t.$$childTail=e}}function i(e){return["$log",function(t){function n(e){this.handle=e}var i=this,r=this._instances=[];this._registerInstance=function(e,t){return e.$$delegateHandle=t,r.push(e),function(){var t=r.indexOf(e);-1!==t&&r.splice(t,1)}},this.$getByHandle=function(e){return e?new n(e):i},e.forEach(function(e){n.prototype[e]=function(){var n,i,o=this.handle,a=arguments,s=0;return r.forEach(function(t){t.$$delegateHandle===o&&(s++,i=t[e].apply(t,a),1===s&&(n=i))}),s?n:t.warn('Delegate for handle "'+this.handle+'" could not find a corresponding element with delegate-handle="'+this.handle+'"! '+e+"() was not called!\nPossible cause: If you are calling "+e+'() immediately, and your element with delegate-handle="'+this.handle+'" is a child of your controller, then your element may not be compiled yet. Put a $timeout around your call to '+e+"() and try again.")},i[e]=function(){var t,n,i=arguments;return r.forEach(function(r,o){n=r[e].apply(r,i),0===o&&(t=n)}),t}})}]}function r(){return["$ionicScrollDelegate",function(e){return{restrict:"E",link:function(t,n){function i(t){for(var i=3,r=t.target;i--&&r;){if(r.classList.contains("button")||r.tagName.match(/input|textarea|select/i)||r.isContentEditable)return;r=r.parentNode}var o=t.gesture&&t.gesture.touches[0]||t.detail.touches[0],a=n[0].getBoundingClientRect();ionic.DomUtil.rectContains(o.pageX,o.pageY,a.left,a.top-20,a.left+a.width,a.top+a.height)&&e.scrollTop(!0)}ionic.on("tap",i,n[0]),t.$on("$destroy",function(){ionic.off("tap",i,n[0])})}}}]}function o(e){return[function(){return{restrict:"E",compile:function(t){function n(t,n,i){var r=(new ionic.views.HeaderBar({el:n[0],alignTitle:i.alignTitle||"center"}),n[0]);e?(t.$watch(function(){return r.className},function(e){var n=-1!==e.indexOf("bar-subheader");t.$hasHeader=!n,t.$hasSubheader=n}),t.$on("$destroy",function(){delete t.$hasHeader,delete t.$hasSubheader})):(t.$watch(function(){return r.className},function(e){var n=-1!==e.indexOf("bar-subfooter");t.$hasFooter=!n,t.$hasSubfooter=n}),t.$on("$destroy",function(){delete t.$hasFooter,delete t.$hasSubfooter}),t.$watch("$hasTabs",function(e){n.toggleClass("has-tabs",!!e)}))}return t.addClass(e?"bar bar-header":"bar bar-footer"),{pre:n}}}}]}function a(e){e.stopPropagation()}var s={method:function(e,t,n){var i=!1;return function(){return i||(i=!0,t(e)),n.apply(this,arguments)}},field:function(e,t,n,i,r){var o=!1,a=function(){return o||(o=!0,t(e)),r},s=function(n){return o||(o=!0,t(e)),r=n,n};Object.defineProperty(n,i,{get:a,set:s,enumerable:!0})}},c=angular.module("ionic",["ngAnimate","ngSanitize","ui.router"]);c.factory("$ionicActionSheet",["$rootScope","$document","$compile","$animate","$timeout","$ionicTemplateLoader","$ionicPlatform",function(e,t,n,i,r,o,a){return{show:function(o){var s=e.$new(!0);angular.extend(s,{cancel:angular.noop,buttonClicked:angular.noop,destructiveButtonClicked:angular.noop},o);var c=n('')(s),l=angular.element(c[0].querySelector(".action-sheet-wrapper")),u=function(e){l.removeClass("action-sheet-up"),e&&r(function(){o.cancel()},200),i.removeClass(c,"active",function(){s.$destroy()}),t[0].body.classList.remove("action-sheet-open"),s.$deregisterBackButton&&s.$deregisterBackButton()};s.$deregisterBackButton=a.registerBackButtonAction(function(){u()},v),s.cancel=function(){u(!0)},s.buttonClicked=function(e){(o.buttonClicked&&o.buttonClicked(e))===!0&&u(!1)},s.destructiveButtonClicked=function(){(o.destructiveButtonClicked&&o.destructiveButtonClicked())===!0&&u(!1)},t[0].body.appendChild(c[0]),t[0].body.classList.add("action-sheet-open");var d=new ionic.views.ActionSheet({el:c[0]});return s.sheet=d,i.addClass(c,"active"),r(function(){l.addClass("action-sheet-up")},20),d}}}]),angular.element.prototype.addClass=function(e){var t,n,i,r,o,a;if(e&&"ng-scope"!=e&&"ng-isolate-scope"!=e)for(t=0;t'),r=0;return e[0].body.appendChild(i[0]),{retain:t,release:n,_element:i}}]),c.factory("$ionicBind",["$parse","$interpolate",function(e,t){var n=/^\s*([@=&])(\??)\s*(\w*)\s*$/;return function(i,r,o){angular.forEach(o||{},function(o,a){var s,c,l=o.match(n)||[],u=l[3]||a,d=l[1];switch(d){case"@":if(!r[u])return;r.$observe(u,function(e){i[a]=e}),r[u]&&(i[a]=t(r[u])(i));break;case"=":if(!r[u])return;c=i.$watch(r[u],function(e){i[a]=e}),i.$on("$destroy",c);break;case"&":if(r[u]&&r[u].match(RegExp(a+"(.*?)")))throw new Error('& expression binding "'+a+'" looks like it will recursively call "'+r[u]+'" and cause a stack overflow! Please choose a different scopeName.');s=e(r[u]),i[a]=function(e){return s(i,e)}}})}}]),c.factory("$collectionDataSource",["$cacheFactory","$parse",function(i,r){function o(t){var n=this;if(this.scope=t.scope,this.transcludeFn=t.transcludeFn,this.transcludeParent=t.transcludeParent,this.keyExpr=t.keyExpr,this.listExpr=t.listExpr,this.trackByExpr=t.trackByExpr,this.heightGetter=t.heightGetter,this.widthGetter=t.widthGetter,this.dimensions=[],this.data=[],this.trackByExpr){var o=r(this.trackByExpr),s={$id:e};this.itemHashGetter=function(e,t){return s[n.keyExpr]=t,s.$index=e,o(n.scope,s)}}else this.itemHashGetter=function(t,n){return e(n)};var c={};this.itemCache=i(a++,{size:500});var l=this.itemCache.put;this.itemCache.put=function(e,t){return c[e]=!0,l(e,t)};var u=this.itemCache.remove;this.itemCache.remove=function(e){return delete c[e],u(e)},this.itemCache.keys=function(){return Object.keys(c)}}var a=0;return o.prototype={destroy:function(){this.dimensions.length=0,this.itemCache.keys().forEach(function(e){var t=this.itemCache.get(e);t.element.remove(),t.scope.$destroy()},this),this.itemCache.removeAll()},calculateDataDimensions:function(){var e={};this.dimensions=this.data.map(function(t,n){return e[this.keyExpr]=t,e.$index=n,{width:this.widthGetter(this.scope,e),height:this.heightGetter(this.scope,e)}},this)},compileItem:function(e,t){var n=this.itemHashGetter(e,t),i=this.itemCache.get(n);if(i)return i;var r={};return r.scope=this.scope.$new(),r.scope[this.keyExpr]=t,this.transcludeFn(r.scope,function(e){r.element=e,r.element[0].style.position="absolute"}),this.itemCache.put(n,r)},getItem:function(e){var t=this.data[e],n=this.compileItem(e,t);return n.scope.$index!==e&&(n.scope.$index=e,n.scope.$first=0===e,n.scope.$last=e===this.getLength()-1,n.scope.$middle=!(n.scope.$first||n.scope.$last),n.scope.$odd=!(n.scope.$even=0===(1&e))),n},detachItem:function(e){var n,i,r;for(n=0;ni&&(n=0,t+=e.primarySize)),o.primaryPos=t,o.secondaryPos=n,e=o,o},this)},resize:function(){this.dimensions=this.calculateDimensions();var e=this.dimensions[this.dimensions.length-1];this.viewportSize=e?e.primaryPos+e.primarySize:0,this.setCurrentIndex(0),this.render(!0)},setCurrentIndex:function(e){this.currentIndex=e,this.hasPrevIndex=e>0,this.hasPrevIndex&&(this.previousPos=this.dimensions[e-1].primaryPos),this.hasNextIndex=e+1=this.nextPos||this.hasPrevIndex&&e100)&&this.render(),e-this.lastRenderScrollValue},getIndexForScrollValue:function(e,t){var n;if(t<=this.dimensions[e].primaryPos)for(;(n=this.dimensions[e-1])&&n.primaryPos>t;)e--;else for(;(n=this.dimensions[e+1])&&n.primaryPos=this.dataSource.getLength()||e){for(t in this.renderedItems)this.removeItem(t);if(this.currentIndex>=this.dataSource.getLength())return null}for(var n,i=this.scrollValue(),r=(i-this.lastRenderScrollValue,this.scrollSize()),o=r+i,a=this.getIndexForScrollValue(this.currentIndex,i),s=Math.max(a-1,0);s>0&&(n=this.dimensions[s])&&n.primaryPos===this.dimensions[a-1].primaryPos;)s--;var c=this.dimensions[s].primaryPos;for(t=s;(n=this.dimensions[t])&&n.primaryPos-n.primarySizet||t>l)&&this.removeItem(t);this.setCurrentIndex(a),this.lastRenderScrollValue=c},renderItem:function(e,t,n){var i=this.dataSource.getItem(e);i?(this.dataSource.attachItem(i),i.element[0].style[ionic.CSS.TRANSFORM]=this.transformString(t,n,n),this.renderedItems[e]=i):delete this.renderedItems[e]},removeItem:function(e){var t=this.renderedItems[e];t&&(this.dataSource.detachItem(t),delete this.renderedItems[e])}},e}]),c.factory("$ionicGesture",[function(){return{on:function(e,t,n){return window.ionic.onGesture(e,t,n[0])},off:function(e,t,n){return window.ionic.offGesture(e,t,n)}}}]);var l='
',u="$ionicLoading instance.hide() has been deprecated. Use $ionicLoading.hide().",d="$ionicLoading instance.show() has been deprecated. Use $ionicLoading.show().",h="$ionicLoading instance.setContent() has been deprecated. Use $ionicLoading.show({ template: 'my content' }).";c.factory("$ionicLoading",["$document","$ionicTemplateLoader","$ionicBackdrop","$timeout","$q","$log","$compile","$ionicPlatform",function(e,t,n,i,r,o,a,c){function f(){return g||(g=t.compile({template:l,appendTo:e[0].body}).then(function(e){var o=e;return e.show=function(e){var s=e.templateUrl?t.load(e.templateUrl):r.when(e.template||e.content||"");this.isShown||(this.hasBackdrop=!e.noBackdrop&&e.showBackdrop!==!1,this.hasBackdrop&&n.retain()),e.duration&&(i.cancel(this.durationTimeout),this.durationTimeout=i(angular.bind(this,this.hide),+e.duration)),s.then(function(e){e&&(o.element.html(e),a(o.element.contents())(o.scope)),o.isShown&&(o.element.addClass("visible"),ionic.DomUtil.centerElementByMarginTwice(o.element[0]),ionic.requestAnimationFrame(function(){o.isShown&&o.element.addClass("active")}))}),this.isShown=!0},e.hide=function(){this.isShown&&(this.hasBackdrop&&n.release(),o.element.removeClass("active"),setTimeout(function(){!o.isShown&&o.element.removeClass("visible")},200)),i.cancel(this.durationTimeout),this.isShown=!1},e})),g}function p(e){e||(e={});var t=e.delay||e.showDelay||0;return w&&i.cancel(w),w=i(angular.noop,t),w.then(f).then(function(t){return $(),$=c.registerBackButtonAction(angular.noop,m),t.show(e)}),{hide:s.method(u,o.error,v),show:s.method(d,o.error,function(){p(e)}),setContent:s.method(h,o.error,function(e){f().then(function(t){t.show({template:e})})})}}function v(){$(),i.cancel(w),f().then(function(e){e.hide()})}var g,$=angular.noop,w=r.when();return{show:p,hide:v,_getLoader:f}}]),c.factory("$ionicModal",["$rootScope","$document","$compile","$timeout","$ionicPlatform","$ionicTemplateLoader","$q",function(e,t,n,i,r,o,a){var s=ionic.views.Modal.inherit({initialize:function(e){ionic.views.Modal.prototype.initialize.call(this,e),this.animation=e.animation||"slide-in-up"},show:function(){var e=this,n=angular.element(e.modalEl);return e.el.classList.remove("hide"),i(function(){t[0].body.classList.add("modal-open")},400),e.el.parentElement||(n.addClass(e.animation),t[0].body.appendChild(e.el)),n.addClass("ng-enter active").removeClass("ng-leave ng-leave-active"),e._isShown=!0,e._deregisterBackButton=r.registerBackButtonAction(function(){e.hide()},200),e._isOpenPromise=a.defer(),ionic.views.Modal.prototype.show.call(e),i(function(){n.addClass("ng-enter-active"),e.scope.$parent&&e.scope.$parent.$broadcast("modal.shown",e),e.el.classList.add("active")},20),i(function(){e.$el.on("click",function(t){t.target===e.el&&e.hide()})},400)},hide:function(){var e=this,n=angular.element(e.modalEl);return e.el.classList.remove("active"),n.addClass("ng-leave"),i(function(){n.addClass("ng-leave-active").removeClass("ng-enter ng-enter-active active")},20),e.$el.off("click"),e._isShown=!1,e.scope.$parent&&e.scope.$parent.$broadcast("modal.hidden",e),e._deregisterBackButton&&e._deregisterBackButton(),ionic.views.Modal.prototype.hide.call(e),i(function(){t[0].body.classList.remove("modal-open"),e.el.classList.add("hide")},500)},remove:function(){var e=this;return e.scope.$parent&&e.scope.$parent.$broadcast("modal.removed",e),e.hide().then(function(){e.scope.$destroy(),e.$el.remove()})},isShown:function(){return!!this._isShown}}),c=function(t,i){var r=i.scope&&i.scope.$new()||e.$new(!0);angular.extend(r,{$hasHeader:!1,$hasSubheader:!1,$hasFooter:!1,$hasSubfooter:!1,$hasTabs:!1,$hasTabsTop:!1});var o=n(""+t+"")(r);i.$el=o,i.el=o[0],i.modalEl=i.el.querySelector(".modal");var a=new s(i);return a.scope=r,i.scope||(r.modal=a),a};return{fromTemplate:function(e,t){var n=c(e,t||{});return n},fromTemplateUrl:function(e,t,n){var i;return angular.isFunction(t)&&(i=t,t=n),o.load(e).then(function(e){var n=c(e,t||{});return i&&i(n),n})}}}]),c.service("$ionicNavBarDelegate",i(["back","align","showBackButton","showBar","setTitle","changeTitle","getTitle","getPreviousTitle"]));var f=100,p=150,v=300,g=400,m=500;c.provider("$ionicPlatform",function(){return{$get:["$q","$rootScope",function(e){var t={onHardwareBackButton:function(e){ionic.Platform.ready(function(){document.addEventListener("backbutton",e,!1)})},offHardwareBackButton:function(e){ionic.Platform.ready(function(){document.removeEventListener("backbutton",e)})},$backButtonActions:{},registerBackButtonAction:function(e,n,i){t._hasBackButtonHandler||(t.$backButtonActions={},t.onHardwareBackButton(t.hardwareBackButtonClick),t._hasBackButtonHandler=!0);var r={id:i?i:ionic.Utils.nextUid(),priority:n?n:0,fn:e};return t.$backButtonActions[r.id]=r,function(){delete t.$backButtonActions[r.id]}},hardwareBackButtonClick:function(e){var n,i;for(i in t.$backButtonActions)(!n||t.$backButtonActions[i].priority>=n.priority)&&(n=t.$backButtonActions[i]);return n?(n.fn(e),n):void 0},is:function(e){return ionic.Platform.is(e)},ready:function(t){var n=e.defer();return ionic.Platform.ready(function(){n.resolve(),t&&t()}),n.promise}};return t}]}});var $='';c.factory("$ionicPopup",["$ionicTemplateLoader","$ionicBackdrop","$q","$timeout","$rootScope","$document","$compile","$ionicPlatform",function(e,t,n,i,r,o,a,s){function c(t){t=angular.extend({scope:null,title:"",buttons:[]},t||{});var r=e.compile({template:$,scope:t.scope&&t.scope.$new(),appendTo:o[0].body}),s=t.templateUrl?e.load(t.templateUrl):n.when(t.template||t.content||"");return n.all([r,s]).then(function(e){var r=e[0],o=e[1],s=n.defer();r.responseDeferred=s;var c=angular.element(r.element[0].querySelector(".popup-body"));return o?(c.html(o),a(c.contents())(r.scope)):c.remove(),angular.extend(r.scope,{title:t.title,buttons:t.buttons,subTitle:t.subTitle,$buttonTapped:function(e,t){var n=(e.onTap||angular.noop)(t);t=t.originalEvent||t,t.defaultPrevented||s.resolve(n)}}),r.show=function(){r.isShown||(r.isShown=!0,ionic.requestAnimationFrame(function(){r.isShown&&(r.element.removeClass("popup-hidden"),r.element.addClass("popup-showing active"),ionic.DomUtil.centerElementByMarginTwice(r.element[0]),d(r.element))}))},r.hide=function(e){return e=e||angular.noop,r.isShown?(r.isShown=!1,r.element.removeClass("active"),r.element.addClass("popup-hidden"),void i(e,250)):e()},r.remove=function(){r.removed||(r.hide(function(){r.element.remove(),r.scope.$destroy()}),r.removed=!0)},r})}function l(){m[0]&&m[0].responseDeferred.resolve()}function u(e){function n(e){r.then(function(t){t.removed||t.responseDeferred.resolve(e)})}var r=w._createPopup(e),o=m[0];o&&o.hide();var a=i(angular.noop,o?v.stackPushDelay:0).then(function(){return r}).then(function(e){return o||(document.body.classList.add("popup-open"),t.retain(),w._backButtonActionDone=s.registerBackButtonAction(l,g)),m.unshift(e),e.show(),e.responseDeferred.notify({close:a.close}),e.responseDeferred.promise.then(function(n){var i=m.indexOf(e);-1!==i&&m.splice(i,1),e.remove();var r=m[0];return r?r.show():(document.body.classList.remove("popup-open"),t.release(),(w._backButtonActionDone||angular.noop)()),n})});return a.close=n,a}function d(e){var t=e[0].querySelectorAll("input");t.length||(t=e[0].querySelectorAll("button"));var n=t[t.length-1];n&&n.focus()}function h(e){return u(angular.extend({buttons:[{text:e.okText||"OK",type:e.okType||"button-positive",onTap:function(){return!0}}]},e||{}))}function f(e){return u(angular.extend({buttons:[{text:e.cancelText||"Cancel",type:e.cancelType||"button-default",onTap:function(){return!1}},{text:e.okText||"OK",type:e.okType||"button-positive",onTap:function(){return!0}}]},e||{}))}function p(e){var t=r.$new(!0);return t.data={},u(angular.extend({template:'',scope:t,buttons:[{text:e.cancelText||"Cancel",type:e.cancelType||"button-default",onTap:function(){}},{text:e.okText||"OK",type:e.okType||"button-positive",onTap:function(){return t.data.response||""}}]},e||{}))}var v={stackPushDelay:50},m=[],w={show:u,alert:h,confirm:f,prompt:p,_createPopup:c,_popupStack:m};return w}]),c.service("$ionicScrollDelegate",i(["resize","scrollTop","scrollBottom","scrollTo","scrollBy","getScrollPosition","anchorScroll","getScrollView","rememberScrollPosition","forgetScrollPosition","scrollToRememberedPosition"])),c.service("$ionicSideMenuDelegate",i(["toggleLeft","toggleRight","getOpenRatio","isOpen","isOpenLeft","isOpenRight","canDragContent"])),c.service("$ionicSlideBoxDelegate",i(["update","slide","enableSlide","previous","next","stop","currentIndex","slidesCount"])),c.service("$ionicTabsDelegate",i(["select","selectedIndex"])),c.factory("$ionicTemplateLoader",["$compile","$controller","$http","$q","$rootScope","$templateCache",function(e,t,n,i,r,o){function a(e){return n.get(e,{cache:o}).then(function(e){return e.data&&e.data.trim()})}function s(n){n=angular.extend({template:"",templateUrl:"",scope:null,controller:null,locals:{},appendTo:null},n||{});var o=n.templateUrl?this.load(n.templateUrl):i.when(n.template);return o.then(function(i){var o,a=n.scope||r.$new(),s=angular.element("
").html(i).contents();return n.controller&&(o=t(n.controller,angular.extend(n.locals,{$scope:a})),s.children().data("$ngControllerController",o)),n.appendTo&&angular.element(n.appendTo).append(s),e(s)(a),{element:s,scope:a}})}return{load:a,compile:s}}]),c.run(["$rootScope","$state","$location","$document","$animate","$ionicPlatform","$ionicViewService",function(e,t,n,i,r,o,a){function s(t){return e.$viewHistory.backView?e.$viewHistory.backView.go():ionic.Platform.exitApp(),t.preventDefault(),!1}e.$viewHistory={histories:{root:{historyId:"root",parentHistoryId:null,stack:[],cursor:-1}},views:{},backView:null,forwardView:null,currentView:null,disabledRegistrableTagNames:[]},a.disableRegisterByTagName&&(a.disableRegisterByTagName("ion-tabs"),a.disableRegisterByTagName("ion-side-menus")),e.$on("viewState.changeHistory",function(i,r){if(r){var o=r.historyId?e.$viewHistory.histories[r.historyId]:null;if(o&&o.cursor>-1&&o.cursor-1&&s.stack.length>0&&s.cursor=u.index;v--)p.stack[v].destroy(),p.stack.splice(v)}}else h.navAction="initialView";r.views[h.viewId]=this.createView({viewId:h.viewId,index:s.stack.length,historyId:s.historyId,backViewId:c&&c.viewId?c.viewId:null,forwardViewId:null,stateId:o,stateName:this.getCurrentStateName(),stateParams:this.getCurrentStateParams(),url:n.url()}),"moveBack"==h.navAction&&e.$emit("$viewHistory.viewBack",c.viewId,h.viewId),s.stack.push(r.views[h.viewId])}return d&&(d.disableAnimate&&(h.navDirection=null),d.disableBack&&(r.views[h.viewId].backViewId=null),this.nextViewOptions(null)),this.setNavViews(h.viewId),s.cursor=r.currentView.index,h},setNavViews:function(t){var n=e.$viewHistory;n.currentView=this._getViewById(t),n.backView=this._getBackView(n.currentView),n.forwardView=this._getForwardView(n.currentView),e.$broadcast("$viewHistory.historyChange",{showBack:n.backView&&n.backView.historyId===n.currentView.historyId})},registerHistory:function(e){e.$historyId=ionic.Utils.nextUid()},createView:function(e){var t=new s;return t.initialize(e)},getCurrentView:function(){return e.$viewHistory.currentView},getBackView:function(){return e.$viewHistory.backView},getForwardView:function(){return e.$viewHistory.forwardView},getNavDirection:function(){return e.$viewHistory.navDirection},getCurrentStateName:function(){return t&&t.current?t.current.name:null},isCurrentStateNavView:function(e){return t&&t.current&&t.current.views&&t.current.views[e]?!0:!1},getCurrentStateParams:function(){var e;if(t&&t.params)for(var n in t.params)t.params.hasOwnProperty(n)&&(e=e||{},e[n]=t.params[n]);return e},getCurrentStateId:function(){var e;if(t&&t.current&&t.current.name){if(e=t.current.name,t.params)for(var n in t.params)t.params.hasOwnProperty(n)&&t.params[n]&&(e+="_"+n+"="+t.params[n]);return e}return ionic.Utils.nextUid()},goToHistoryRoot:function(t){if(t){var n=e.$viewHistory.histories[t];if(n&&n.stack.length){if(e.$viewHistory.currentView&&e.$viewHistory.currentView.viewId===n.stack[0].viewId)return;e.$viewHistory.forcedNav={viewId:n.stack[0].viewId,navAction:"moveBack",navDirection:"back"},n.stack[0].go()}}},_getViewById:function(t){return t?e.$viewHistory.views[t]:null},_getBackView:function(e){return e?this._getViewById(e.backViewId):null},_getForwardView:function(e){return e?this._getViewById(e.forwardViewId):null},_getHistoryById:function(t){return t?e.$viewHistory.histories[t]:null},_getHistory:function(t){var n=this._getParentHistoryObj(t);return e.$viewHistory.histories[n.historyId]||(e.$viewHistory.histories[n.historyId]={historyId:n.historyId,parentHistoryId:this._getParentHistoryObj(n.scope.$parent).historyId,stack:[],cursor:-1}),e.$viewHistory.histories[n.historyId]},_getParentHistoryObj:function(t){for(var n=t;n;){if(n.hasOwnProperty("$historyId"))return{historyId:n.$historyId,scope:n};n=n.$parent}return{historyId:"root",scope:e}},nextViewOptions:function(e){return arguments.length?void(this._nextOpts=e):this._nextOpts},getRenderer:function(e,t,n){function i(e){for(var t="";!t&&e;)t=e.getAttribute("animation"),e=e.parentElement;return t}function r(){l&&e[0].classList.add(l),"back"===a.navDirection?e[0].classList.add("reverse"):e[0].classList.remove("reverse")}var a,s,c=this,l=i(e[0]);return function(t){return{enter:function(n){return s&&t?(r(),n.addClass("ng-enter"),document.body.classList.add("disable-pointer-events"),void o.enter(n,e,null,function(){document.body.classList.remove("disable-pointer-events"),l&&e[0].classList.remove(l)})):void e.append(n)},leave:function(){var n=e.contents();return s&&t?(r(),void o.leave(n,function(){n.remove()})):void n.remove()},register:function(e){return a=c.register(n,e),s=null!==l&&null!==a.navDirection,a}}}},disableRegisterByTagName:function(t){e.$viewHistory.disabledRegistrableTagNames.push(t.toUpperCase())},isTagNameRegistrable:function(t){var n,i,r=e.$viewHistory.disabledRegistrableTagNames;for(n=0;n')(e),angular.element(a[0]).replaceWith(n)),i=o('

')(e),ionic.requestAnimationFrame(function(){n&&r.leave(angular.element(n));var o=n&&angular.element(n)||null;r.enter(i,t,o,function(){c._headerBarView.align()}),angular.forEach(a,function(e){e&&e.parentNode&&angular.element(e).remove()}),e.$digest(),ionic.requestAnimationFrame(function(){i[0].classList.remove("invisible")})})}}]),c.factory("$$scrollValueCache",function(){return{}}).controller("$ionicScroll",["$scope","scrollViewOptions","$timeout","$window","$$scrollValueCache","$location","$rootScope","$document","$ionicScrollDelegate",function(e,t,n,i,r,o,a,s,c){var l=this;this._scrollViewOptions=t;var u=this.element=t.el,d=this.$element=angular.element(u),h=this.scrollView=new ionic.views.Scroll(t);(d.parent().length?d.parent():d).data("$$ionicScrollController",this);var f=c._registerInstance(this,t.delegateHandle);angular.isDefined(t.bouncing)||ionic.Platform.ready(function(){h.options.bouncing=!ionic.Platform.isAndroid()});var p=angular.bind(h,h.resize);ionic.on("resize",p,i);var v=angular.noop;e.$on("$destroy",function(){f(),ionic.off("resize",p,i),i.removeEventListener("resize",p),v(),l._rememberScrollId&&(r[l._rememberScrollId]=h.getValues())}),d.on("scroll",function(t){var n=(t.originalEvent||t).detail||{};e.$onScroll&&e.$onScroll({event:t,scrollTop:n.scrollTop||0,scrollLeft:n.scrollLeft||0})}),e.$on("$viewContentLoaded",function(e,t){if(!e.defaultPrevented){e.preventDefault();var i=t&&t.viewId;i&&n(function(){l.rememberScrollPosition(i),l.scrollToRememberedPosition(),v=a.$on("$viewHistory.viewBack",function(e,t){i===t&&l.forgetScrollPosition()})},1,!1)}}),n(function(){h.run()}),this._rememberScrollId=null,this.getScrollView=function(){return this.scrollView},this.getScrollPosition=function(){return this.scrollView.getValues()},this.resize=function(){return n(p)},this.scrollTop=function(e){this.resize().then(function(){h.scrollTo(0,0,!!e)})},this.scrollBottom=function(e){this.resize().then(function(){var t=h.getScrollMax();h.scrollTo(t.left,t.top,!!e)})},this.scrollTo=function(e,t,n){this.resize().then(function(){h.scrollTo(e,t,!!n)})},this.scrollBy=function(e,t,n){this.resize().then(function(){h.scrollBy(e,t,!!n)})},this.anchorScroll=function(e){this.resize().then(function(){var t=o.hash(),n=t&&s[0].getElementById(t);if(t&&n){var i=ionic.DomUtil.getPositionInParent(n,l.$element);h.scrollTo(i.left,i.top,!!e)}else h.scrollTo(0,0,!!e)})},this.rememberScrollPosition=function(e){if(!e)throw new Error("Must supply an id to remember the scroll by!");this._rememberScrollId=e},this.forgetScrollPosition=function(){delete r[this._rememberScrollId],this._rememberScrollId=null},this.scrollToRememberedPosition=function(e){var t=r[this._rememberScrollId];t&&this.resize().then(function(){h.scrollTo(+t.left,+t.top,e)})},this._setRefresher=function(e,t){var n=this.refresher=t,i=l.refresher.clientHeight||0;h.activatePullToRefresh(i,function(){n.classList.add("active"),e.$onPulling()},function(){n.classList.remove("refreshing"),n.classList.remove("active")},function(){n.classList.add("refreshing"),e.$onRefresh()})}}]),c.controller("$ionicSideMenus",["$scope","$attrs","$ionicSideMenuDelegate","$ionicPlatform",function(e,t,n,i){var r=this;angular.extend(this,ionic.controllers.SideMenuController.prototype),this.$scope=e,ionic.controllers.SideMenuController.call(this,{left:{width:275},right:{width:275}}),this.canDragContent=function(t){return arguments.length&&(e.dragContent=!!t),e.dragContent},this.isDraggableTarget=function(t){return e.dragContent&&!t.gesture.srcEvent.defaultPrevented&&!t.target.tagName.match(/input|textarea|select|object|embed/i)&&!t.target.isContentEditable&&!(t.target.dataset?t.target.dataset.preventScroll:"true"==t.target.getAttribute("data-prevent-default"))},e.sideMenuContentTranslateX=0;var o=angular.noop,a=angular.bind(this,this.close);e.$watch(function(){return 0!==r.getOpenAmount()},function(e){o(),e&&(o=i.registerBackButtonAction(a,p))});var s=n._registerInstance(this,t.delegateHandle);e.$on("$destroy",function(){s(),o()})}]),c.controller("$ionicTab",["$scope","$ionicViewService","$attrs","$location","$state",function(e,t,n,i,r){this.$scope=e,this.hrefMatchesState=function(){return n.href&&0===i.path().indexOf(n.href.replace(/^#/,"").replace(/\/$/,""))},this.srefMatchesState=function(){return n.uiSref&&r.includes(n.uiSref.split("(")[0])},this.navNameMatchesState=function(){return this.navViewName&&t.isCurrentStateNavView(this.navViewName)},this.tabMatchesState=function(){return this.hrefMatchesState()||this.srefMatchesState()||this.navNameMatchesState()}}]),c.controller("$ionicTabs",["$scope","$ionicViewService","$element",function(e,t){var n=null,i=this;i.tabs=[],i.selectedIndex=function(){return i.tabs.indexOf(n)},i.selectedTab=function(){return n},i.add=function(e){t.registerHistory(e),i.tabs.push(e),1===i.tabs.length&&i.select(e)},i.remove=function(e){var t=i.tabs.indexOf(e);if(-1!==t){if(e.$tabSelected)if(i.deselect(e),1===i.tabs.length);else{var n=t===i.tabs.length-1?t-1:t+1;i.select(i.tabs[n])}i.tabs.splice(t,1)}},i.deselect=function(e){e.$tabSelected&&(n=null,e.$tabSelected=!1,(e.onDeselect||angular.noop)())},i.select=function(r,o){var a;if(angular.isNumber(r)?(a=r,r=i.tabs[a]):a=i.tabs.indexOf(r),!r||-1==a)throw new Error('Cannot select tab "'+a+'"!');if(n&&n.$historyId==r.$historyId)o&&t.goToHistoryRoot(r.$historyId);else if(angular.forEach(i.tabs,function(e){i.deselect(e)}),n=r,r.$tabSelected=!0,(r.onSelect||angular.noop)(),o){var s={type:"tab",tabIndex:a,historyId:r.$historyId,navViewName:r.navViewName,hasNavView:!!r.navViewName,title:r.title,url:r.href,uiSref:r.uiSref};e.$emit("viewState.changeHistory",s)}}}]),c.directive("ionActionSheet",["$document",function(e){return{restrict:"E",scope:!0,replace:!0,link:function(t,n){var i=function(e){27==e.which&&(t.cancel(),t.$apply())},r=function(e){e.target==n[0]&&(t.cancel(),t.$apply())};t.$on("$destroy",function(){n.remove(),e.unbind("keyup",i)}),e.bind("keyup",i),n.bind("click",r)},template:'
'}}]),c.directive("ionCheckbox",function(){return{restrict:"E",replace:!0,require:"?ngModel",scope:{ngModel:"=?",ngValue:"=?",ngChecked:"=?",ngDisabled:"=?",ngChange:"&"},transclude:!0,template:'',compile:function(e,t){var n=e.find("input");t.name&&n.attr("name",t.name),t.ngChecked&&n.attr("ng-checked",t.ngChecked),t.ngDisabled&&n.attr("ng-disabled",t.ngDisabled),t.ngTrueValue&&n.attr("ng-true-value",t.ngTrueValue),t.ngFalseValue&&n.attr("ng-false-value",t.ngFalseValue)}}});var w="Cannot create a collection-repeat within a scrollView that is scrollable on both x and y axis. Choose either x direction or y direction.",b="collection-repeat expected attribute collection-item-height to be a an expression that returns a number (in pixels) or percentage.",y="collection-repeat expected attribute collection-item-width to be a an expression that returns a number (in pixels) or percentage.",S="collection-repeat expected expression in form of '_item_ in _collection_[ track by _id_]' but got '%'";c.directive("collectionRepeat",["$collectionRepeatManager","$collectionDataSource","$parse",function(e,t,n){return{priority:1e3,transclude:"element",terminal:!0,$$tlb:!0,require:"^$ionicScroll",link:function(i,r,o,a,s){function c(e){u.resize(),I.setData(e),C.resize()}function l(){c(i.$eval($))}var u=a.scrollView;if(u.options.scrollingX&&u.options.scrollingY)throw new Error(w);var d=!!u.options.scrollingY;if(d&&!o.collectionItemHeight)throw new Error(b);if(!d&&!o.collectionItemWidth)throw new Error(y);o.collectionItemHeight=o.collectionItemHeight||'"100%"',o.collectionItemWidth=o.collectionItemWidth||'"100%"';var h=o.collectionItemHeight?n(o.collectionItemHeight):function(){return u.__clientHeight},f=o.collectionItemWidth?n(o.collectionItemWidth):function(){return u.__clientWidth},p=function(e,t){var n=h(e,t);return angular.isString(n)&&n.indexOf("%")>-1?Math.floor(parseInt(n,10)/100*u.__clientHeight):n},v=function(e,t){var n=f(e,t);return angular.isString(n)&&n.indexOf("%")>-1?Math.floor(parseInt(n,10)/100*u.__clientWidth):n},g=o.collectionRepeat.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);if(!g)throw new Error(S.replace("%",o.collectionRepeat));var m=g[1],$=g[2],k=g[3],I=new t({scope:i,transcludeFn:s,transcludeParent:r.parent(),keyExpr:m,listExpr:$,trackByExpr:k,heightGetter:p,widthGetter:v}),C=new e({dataSource:I,element:a.$element,scrollView:a.scrollView});i.$watchCollection($,function(e){if(e&&!angular.isArray(e))throw new Error("collection-repeat expects an array to repeat over, but instead got '"+typeof e+"'.");c(e)}),ionic.on("resize",l,window),i.$on("$destroy",function(){C.destroy(),I.destroy(),ionic.off("resize",l,window)})}}}]),c.directive("ionContent",["$timeout","$controller","$ionicBind",function(e,t,n){return{restrict:"E",require:"^?ionNavView",scope:!0,priority:800,compile:function(e,i){function r(e,r,a){var s=e.$parent;e.$watch(function(){return(s.$hasHeader?" has-header":"")+(s.$hasSubheader?" has-subheader":"")+(s.$hasFooter?" has-footer":"")+(s.$hasSubfooter?" has-subfooter":"")+(s.$hasTabs?" has-tabs":"")+(s.$hasTabsTop?" has-tabs-top":"")},function(e,t){r.removeClass(t),r.addClass(e)}),e.$hasHeader=e.$hasSubheader=e.$hasFooter=e.$hasSubfooter=e.$hasTabs=e.$hasTabsTop=!1,n(e,a,{$onScroll:"&onScroll",$onScrollComplete:"&onScrollComplete",hasBouncing:"@",scroll:"@",padding:"@",hasScrollX:"@",hasScrollY:"@",scrollbarX:"@",scrollbarY:"@",startX:"@",startY:"@",scrollEventInterval:"@"}),angular.isDefined(a.padding)&&e.$watch(a.padding,function(e){(o||r).toggleClass("padding",!!e)}),"false"===e.scroll||("true"===i.overflowScroll?r.addClass("overflow-scroll"):t("$ionicScroll",{$scope:e,scrollViewOptions:{el:r[0],delegateHandle:i.delegateHandle,bouncing:e.$eval(e.hasBouncing),startX:e.$eval(e.startX)||0,startY:e.$eval(e.startY)||0,scrollbarX:e.$eval(e.scrollbarX)!==!1,scrollbarY:e.$eval(e.scrollbarY)!==!1,scrollingX:e.$eval(e.hasScrollX)===!0,scrollingY:e.$eval(e.hasScrollY)!==!1,scrollEventInterval:parseInt(e.scrollEventInterval,10)||10,scrollingComplete:function(){e.$onScrollComplete({scrollTop:this.__scrollTop,scrollLeft:this.__scrollLeft})}}}))}var o;return e.addClass("scroll-content"),"false"!=i.scroll&&(o=angular.element('
'),o.append(e.contents()),e.append(o)),{pre:r}}}}]),c.directive("ionNavBar",r()).directive("ionHeaderBar",r()).directive("ionHeaderBar",o(!0)).directive("ionFooterBar",o(!1)),c.directive("ionInfiniteScroll",["$timeout",function(e){function t(e,t,n){return n?t*(1-parseInt(e,10)/100):t-parseInt(e,10)}return{restrict:"E",require:["^$ionicScroll","ionInfiniteScroll"],template:'
',scope:!0,controller:["$scope","$attrs",function(e,n){this.isLoading=!1,this.scrollView=null,this.getMaxScroll=function(){var e=(n.distance||"1%").trim(),i=-1!==e.indexOf("%"),r=this.scrollView.getScrollMax();return{left:this.scrollView.options.scrollingX?t(e,r.left,i):-1,top:this.scrollView.options.scrollingY?t(e,r.top,i):-1}}}],link:function(t,n,i,r){function o(){if(!s.isLoading){var e=c.getValues(),t=s.getMaxScroll();(-1!==t.left&&e.left>=t.left||-1!==t.top&&e.top>=t.top)&&l()}}var a=r[0],s=r[1],c=s.scrollView=a.scrollView;t.icon=function(){return angular.isDefined(i.icon)?i.icon:"ion-loading-d"};var l=function(){n[0].classList.add("active"),s.isLoading=!0,t.$parent&&t.$parent.$apply(i.onInfinite||"")},u=function(){n[0].classList.remove("active"),e(function(){c.resize()},0,!1),s.isLoading=!1};t.$on("scroll.infiniteScrollComplete",function(){u()}),t.$on("$destroy",function(){a.$element.off("scroll",d)});var d=ionic.animationFrameThrottle(o);setTimeout(d),a.$element.on("scroll",d)}}}]);var k='',I='
';c.directive("ionItem",["$animate","$compile",function(){return{restrict:"E",controller:["$scope","$element",function(e,t){this.$scope=e,this.$element=t}],scope:!0,compile:function(e,t){var n=angular.isDefined(t.href)||angular.isDefined(t.ngHref),i=n||/ion-(delete|option|reorder)-button/i.test(e.html());if(i){var r=angular.element(n?k:I);r.append(e.contents()),e.append(r),e.addClass("item item-complex")}else e.addClass("item");return function(e,t,n){e.$href=function(){return n.href||n.ngHref}}}}}]);var C='
';c.directive("ionDeleteButton",["$animate",function(e){return{restrict:"E",require:["^ionItem","^ionList"],priority:Number.MAX_VALUE,compile:function(t,n){return n.$set("class",(n["class"]||"")+" button icon button-icon",!0),function(t,n,i,r){var o=r[0],a=r[1],s=angular.element(C);s.append(n),o.$element.append(s).addClass("item-left-editable"),a.showDelete()&&e.removeClass(s,"ng-hide")}}}}]);var x='';c.directive("ionOptionButton",["$compile",function(){return{restrict:"E",require:"^ionItem",priority:Number.MAX_VALUE,compile:function(e,t){return t.$set("class",(t["class"]||"")+" button",!0),function(e,t,n,i){i.optionsContainer||(i.optionsContainer=angular.element(x),i.$element.append(i.optionsContainer)),i.optionsContainer.append(t),t.on("click",a)}}}}]);var T='
';c.directive("ionReorderButton",["$animate",function(e){return{restrict:"E",require:["^ionItem","^ionList"],priority:Number.MAX_VALUE,compile:function(t,n){return n.$set("class",(n["class"]||"")+" button icon button-icon",!0),t[0].setAttribute("data-prevent-scroll",!0),function(t,n,i,r){var o=r[0],a=r[1];t.$onReorder=function(e,n){t.$eval(i.onReorder,{$fromIndex:e,$toIndex:n})};var s=angular.element(T);s.append(n),o.$element.append(s).addClass("item-right-editable"),a.showReorder()&&e.removeClass(s,"ng-hide")}}}}]),c.directive("ionList",["$animate","$timeout",function(e,t){return{restrict:"E",require:["ionList","^?$ionicScroll"],controller:"$ionicList",compile:function(n,i){var r=angular.element('
').append(n.contents());return n.append(r),function(n,r,o,a){function s(){function t(t,n){angular.forEach(r[0].querySelectorAll(t),function(t){n?e.removeClass(angular.element(t),"ng-hide"):e.addClass(angular.element(t),"ng-hide")})}function o(e,t){var n=angular.element(r[0].querySelectorAll(e));t?n.attr("data-tap-disabled","true"):n.removeAttr("data-tap-disabled")}c.listView=new ionic.views.ListView({el:r[0],listEl:r.children()[0],scrollEl:l&&l.element,scrollView:l&&l.scrollView,onReorder:function(e,t,n){var i=angular.element(e).scope();i&&i.$onReorder&&i.$onReorder(t,n)},canSwipe:function(){return c.canSwipeItems()}});angular.isDefined(i.canSwipe)&&n.$watch("!!("+i.canSwipe+")",function(e){c.canSwipeItems(e)}),angular.isDefined(i.showDelete)&&n.$watch("!!("+i.showDelete+")",function(e){c.showDelete(e)}),angular.isDefined(i.showReorder)&&n.$watch("!!("+i.showReorder+")",function(e){c.showReorder(e)}),n.$watch(function(){return c.showDelete()},function(e,n){(e||n)&&(e&&c.closeOptionButtons(),c.canSwipeItems(!e),r.children().toggleClass("list-left-editing",e),t(".item-delete.item-left-edit",e),o(".item-content",e))}),n.$watch(function(){return c.showReorder()},function(e,n){(e||n)&&(e&&c.closeOptionButtons(),c.canSwipeItems(!e),r.children().toggleClass("list-right-editing",e),t(".item-reorder.item-right-edit",e),o(".item-content",e))})}var c=a[0],l=a[1];t(s)}}}}]),c.directive("menuClose",["$ionicViewService",function(){return{restrict:"AC",require:"^ionSideMenus",link:function(e,t,n,i){t.bind("click",function(){i.close()})}}}]),c.directive("menuToggle",["$ionicViewService",function(){return{restrict:"AC",require:"^ionSideMenus",link:function(e,t,n,i){var r=n.menuToggle||"left";t.bind("click",function(){"left"===r?i.toggleLeft():"right"===r&&i.toggleRight()})}}}]),c.directive("ionModal",[function(){return{restrict:"E",transclude:!0,replace:!0,template:''}}]),c.directive("ionNavBackButton",["$animate","$rootScope",function(e,t){var n=!1;return t.$on("$viewHistory.historyChange",function(e,t){n=!!t.showBack}),{restrict:"E",require:"^ionNavBar",compile:function(t){return t.addClass("button back-button ng-hide"),function(t,i,r,o){r.ngClick||(t.$navBack=o.back,i.on("click",function(e){t.$apply(function(){t.$navBack(e)})})),t.$watch(function(){return!(!n||!t.backButtonShown)},ionic.animationFrameThrottle(function(t){t?e.removeClass(i,"ng-hide"):e.addClass(i,"ng-hide")}))}}}}]),c.directive("ionNavBar",["$ionicViewService","$rootScope","$animate","$compile",function(){return{restrict:"E",controller:"$ionicNavBar",scope:!0,compile:function(e){function t(e,t,n,i){i._headerBarView=new ionic.views.HeaderBar({el:t[0],alignTitle:n.alignTitle||"center"}),e.backButtonShown=!1,e.shouldAnimate=!0,e.isReverse=!1,e.isInvisible=!0,e.$on("$destroy",function(){e.$parent.$hasHeader=!1}),e.$watch(function(){return(e.isReverse?" reverse":"")+(e.isInvisible?" invisible":"")+(e.shouldAnimate?"":" no-animation")},function(e,n){t.removeClass(n),t.addClass(e)})}return e.addClass("bar bar-header nav-bar").append('

'),{pre:t}}}}]),c.directive("ionNavButtons",["$compile","$animate",function(e,t){return{require:"^ionNavBar",restrict:"E",compile:function(n){var i=n.contents().remove();return function(n,r,o,a){var s="right"===o.side?a.rightButtonsElement:a.leftButtonsElement,c=angular.element("").append(i);r.append(c),e(c)(n),ionic.requestAnimationFrame(function(){t.enter(c,s)}),n.$on("$destroy",function(){t.leave(c)}),r.css("display","none")}}}}]),c.directive("navClear",["$ionicViewService","$state","$location","$window","$rootScope",function(e,t,n,i,r){return r.$on("$stateChangeError",function(){e.nextViewOptions(null)}),{priority:100,restrict:"AC",compile:function(){function t(t,n){function r(){o=t.$on("$stateChangeStart",function(){e.nextViewOptions({disableAnimate:!0,disableBack:!0}),o()}),i.setTimeout(o,300)}var o;n.on("click",r)}return{pre:t}}}}]),c.directive("ionNavView",["$ionicViewService","$state","$compile","$controller","$animate",function(e,t,n,i,r){var o=!1,a={restrict:"E",terminal:!0,priority:2e3,transclude:!0,controller:function(){},compile:function(s,c,l){return function(s,c,u){function d(o){r.enabled()===!1&&(o=!1);var a=t.$current&&t.$current.locals[p];if(a!==f){var l=e.getRenderer(c,u,s);if(h&&(h.$destroy(),h=null),!a)return f=null,$.state=null,c.append(g);var d=angular.element("
").html(a.$template).contents(),m=l().register(d);l(o).leave(),f=a,$.state=a.$$state,l(o).enter(d);var w=n(d);if(h=s.$new(),h.$navDirection=m.navDirection,a.$$controller){a.$scope=h;var b=i(a.$$controller,a);c.children().data("$ngControllerController",b)}w(h);var y=e._getViewById(m.viewId)||{};h.$broadcast("$viewContentLoaded",y),v&&h.$eval(v),d=null}}var h,f,p=u[a.name]||u.name||"",v=u.onload||"",g=l(s);c.append(g);var m=c.parent().inheritedData("$uiView");p.indexOf("@")<0&&(p=p+"@"+(m?m.state.name:""));var $={name:p,state:null};c.data("$uiView",$);var w=function(){if(!o){o=!0;try{d(!0)}catch(e){throw o=!1,e}o=!1}};s.$on("$stateChangeSuccess",w),d(!1)}}};return a}]),c.config(["$provide",function(e){e.decorator("ngClickDirective",["$delegate",function(e){return e.shift(),e}])}]).factory("$ionicNgClick",["$parse",function(e){return function(t,n,i){var r=e(i);n.on("click",function(e){t.$apply(function(){r(t,{$event:e})})}),n.onclick=function(){}}}]).directive("ngClick",["$ionicNgClick",function(e){return function(t,n,i){e(t,n,i.ngClick)}}]).directive("ionStopEvent",function(){return{restrict:"A",link:function(e,t,n){t.bind(n.ionStopEvent,a)}}}),c.directive("ionPane",function(){return{restrict:"E",link:function(e,t){t.addClass("pane")}}}),c.directive("ionRadio",function(){return{restrict:"E",replace:!0,require:"?ngModel",scope:{ngModel:"=?",ngValue:"=?",ngChange:"&",icon:"@",name:"@"},transclude:!0,template:'',compile:function(e,t){t.name&&e.children().eq(0).attr("name",t.name),t.icon&&e.children().eq(2).removeClass("ion-checkmark").addClass(t.icon)}}}),c.directive("ionRefresher",["$ionicBind",function(e){return{restrict:"E",replace:!0,require:"^$ionicScroll",template:'
',compile:function(t,n){return angular.isUndefined(n.pullingIcon)&&n.$set("pullingIcon","ion-arrow-down-c"),angular.isUndefined(n.refreshingIcon)&&n.$set("refreshingIcon","ion-loading-d"),function(t,n,i,r){e(t,i,{pullingIcon:"@",pullingText:"@",refreshingIcon:"@",refreshingText:"@",$onRefresh:"&onRefresh",$onPulling:"&onPulling"}),r._setRefresher(t,n[0]),t.$on("scroll.refreshComplete",function(){n[0].classList.remove("active"),r.scrollView.finishPullToRefresh()})}}}}]),c.directive("ionScroll",["$timeout","$controller","$ionicBind",function(e,t,n){return{restrict:"E",scope:!0,controller:function(){},compile:function(e){function i(e,i,o){var a,s;n(e,o,{direction:"@",paging:"@",$onScroll:"&onScroll",scroll:"@",scrollbarX:"@",scrollbarY:"@",zooming:"@",minZoom:"@",maxZoom:"@"}),angular.isDefined(o.padding)&&e.$watch(o.padding,function(e){r.toggleClass("padding",!!e)}),e.$eval(e.paging)===!0&&r.addClass("scroll-paging"),e.direction||(e.direction="y");var c=e.$eval(e.paging)===!0,l={el:i[0],delegateHandle:o.delegateHandle,paging:c,scrollbarX:e.$eval(e.scrollbarX)!==!1,scrollbarY:e.$eval(e.scrollbarY)!==!1,scrollingX:e.direction.indexOf("x")>=0,scrollingY:e.direction.indexOf("y")>=0,zooming:e.$eval(e.zooming)===!0,maxZoom:e.$eval(e.maxZoom)||3,minZoom:e.$eval(e.minZoom)||.5};c&&(l.speedMultiplier=.8,l.bouncing=!1),s=t("$ionicScroll",{$scope:e,scrollViewOptions:l}),a=e.$parent.scrollView=s.scrollView}e.addClass("scroll-view");var r=angular.element('
');return r.append(e.contents()),e.append(r),{pre:i}}}}]),c.directive("ionSideMenu",function(){return{restrict:"E",require:"^ionSideMenus",scope:!0,compile:function(e,t){return angular.isUndefined(t.isEnabled)&&t.$set("isEnabled","true"),angular.isUndefined(t.width)&&t.$set("width","275"),e.addClass("menu menu-"+t.side),function(e,t,n,i){e.side=n.side||"left";var r=i[e.side]=new ionic.views.SideMenu({width:275,el:t[0],isEnabled:!0});e.$watch(n.width,function(e){var t=+e;t&&t==e&&r.setWidth(+e)}),e.$watch(n.isEnabled,function(e){r.setIsEnabled(!!e)})}}}}),c.directive("ionSideMenuContent",["$timeout","$ionicGesture",function(e,t){return{restrict:"EA",require:"^ionSideMenus",scope:!0,compile:function(n,i){function r(n,r,o,a){function s(e){0!==a.getOpenAmount()&&(a.close(),e.gesture.srcEvent.preventDefault())}r.addClass("menu-content pane"),angular.isDefined(i.dragContent)?n.$watch(i.dragContent,function(e){a.canDragContent(e)}):a.canDragContent(!0);var c=!1,l=!1;ionic.on("tap",s,r[0]);var u=function(e){!c&&a.isDraggableTarget(e)&&(l=!0,a._handleDrag(e),e.gesture.srcEvent.preventDefault())},d=function(e){l&&e.gesture.srcEvent.preventDefault()},h=t.on("dragright",u,r),f=t.on("dragleft",u,r),p=t.on("dragup",d,r),v=t.on("dragdown",d,r),g=function(e){l=!1,c||a._endDrag(e),c=!1},m=t.on("release",g,r);a.setContent({onDrag:function(){},endDrag:function(){},getTranslateX:function(){return n.sideMenuContentTranslateX||0},setTranslateX:ionic.animationFrameThrottle(function(t){r[0].style[ionic.CSS.TRANSFORM]="translate3d("+t+"px, 0, 0)",e(function(){n.sideMenuContentTranslateX=t})}),enableAnimation:function(){n.animationEnabled=!0,r[0].classList.add("menu-animated")},disableAnimation:function(){n.animationEnabled=!1,r[0].classList.remove("menu-animated")}}),n.$on("$destroy",function(){t.off(f,"dragleft",u),t.off(h,"dragright",u),t.off(p,"dragup",u),t.off(v,"dragdown",u),t.off(m,"release",g),ionic.off("tap",s,r[0])})}return{pre:r}}}}]),c.directive("ionSideMenus",[function(){return{restrict:"ECA",replace:!0,transclude:!0,controller:"$ionicSideMenus",template:'
'}}]),c.directive("ionSlideBox",["$timeout","$compile","$ionicSlideBoxDelegate",function(e,t,n){return{restrict:"E",replace:!0,transclude:!0,scope:{doesContinue:"@",slideInterval:"@",showPager:"@",pagerClick:"&",disableScroll:"@",onSlideChanged:"&",activeSlide:"=?"},controller:["$scope","$element","$attrs",function(t,i,r){var o=t.$eval(t.doesContinue)===!0,a=o?t.$eval(t.slideInterval)||4e3:0,s=new ionic.views.Slider({el:i[0],auto:a,continuous:o,startSlide:t.activeSlide,slidesChanged:function(){t.currentSlide=s.currentIndex(),e(function(){})},callback:function(n){t.currentSlide=n,t.onSlideChanged({index:t.currentSlide}),t.$parent.$broadcast("slideBox.slideChanged",n),t.activeSlide=n,e(function(){})}});s.enableSlide(t.$eval(r.disableScroll)!==!0),t.$watch("activeSlide",function(e){angular.isDefined(e)&&s.slide(e)}),t.$on("slideBox.nextSlide",function(){s.next()}),t.$on("slideBox.prevSlide",function(){s.prev()}),t.$on("slideBox.setSlide",function(e,t){s.slide(t)}),this.__slider=s;var c=n._registerInstance(s,r.delegateHandle);t.$on("$destroy",c),this.slidesCount=function(){return s.slidesCount()},this.onPagerClick=function(e){t.pagerClick({index:e})},e(function(){s.load()})}],template:'
',link:function(e,n){if(e.$eval(e.showPager)!==!1){var i=e.$new(),r=angular.element("");n.append(r),t(r)(i)}}}}]).directive("ionSlide",function(){return{restrict:"E",require:"^ionSlideBox",compile:function(e){return e.addClass("slider-slide"),function(){}}}}).directive("ionPager",function(){return{restrict:"E",replace:!0,require:"^ionSlideBox",template:'
',link:function(e,t,n,i){var r=function(e){for(var n=t[0].children,i=n.length,r=0;i>r;r++)r==e?n[r].classList.add("active"):n[r].classList.remove("active")};e.pagerClick=function(e){i.onPagerClick(e)},e.numSlides=function(){return new Array(i.slidesCount())},e.$watch("currentSlide",function(e){r(e)})}}}),c.directive("ionTab",["$rootScope","$animate","$ionicBind","$compile",function(e,t,n,i){function r(e,t){return angular.isDefined(t)?" "+e+'="'+t+'"':""}return{restrict:"E",require:["^ionTabs","ionTab"],replace:!0,controller:"$ionicTab",scope:!0,compile:function(e,o){var a="",s=angular.element('
').append(e.contents().remove());return function(e,r,o,c){function l(){f.tabMatchesState()&&h.select(e)}var u,d,h=c[0],f=c[1],p=s[0].querySelector("ion-nav-view")||s[0].querySelector("data-ion-nav-view"),v=p&&p.getAttribute("name");n(e,o,{animate:"=",onSelect:"&",onDeselect:"&",title:"@",uiSref:"@",href:"@"}),h.add(e),e.$on("$destroy",function(){h.remove(e),g.isolateScope().$destroy(),g.remove()}),r[0].removeAttribute("title"),v&&(f.navViewName=v),e.$on("$stateChangeSuccess",l),l();var g=angular.element(a);g.data("$ionTabsController",h),g.data("$ionTabController",f),h.$tabsElement.append(i(g)(e)),e.$watch("$tabSelected",function(n){u&&u.$destroy(),u=null,d&&t.leave(d),d=null,n&&(u=e.$new(),d=s.clone(),t.enter(d,h.$element),i(d)(u))})}}}}]),c.directive("ionTabNav",[function(){return{restrict:"E",replace:!0,require:["^ionTabs","^ionTab"],template:'{{badge}}',scope:{title:"@",icon:"@",iconOn:"@",iconOff:"@",badge:"=",badgeStyle:"@"},compile:function(){return function(e,t,n,i){var r=i[0],o=i[1];t[0].removeAttribute("title"),e.selectTab=function(e){e.preventDefault(),r.select(o.$scope,!0)},n.ngClick||t.on("click",function(t){e.$apply(function(){e.selectTab(t)})}),e.getIconOn=function(){return e.iconOn||e.icon},e.getIconOff=function(){return e.iconOff||e.icon},e.isTabActive=function(){return r.selectedTab()===o.$scope}}}}}]),c.directive("ionTabs",["$ionicViewService","$ionicTabsDelegate",function(e,t){return{restrict:"E",scope:!0,controller:"$ionicTabs",compile:function(e){function n(e,n,i,r){var o=t._registerInstance(r,i.delegateHandle);e.$on("$destroy",o),r.$scope=e,r.$element=n,r.$tabsElement=angular.element(n[0].querySelector(".tabs"));var a=n[0];e.$watch(function(){return a.className},function(t){var n=-1!==t.indexOf("tabs-top"),i=-1!==t.indexOf("tabs-item-hide");e.$hasTabs=!n&&!i,e.$hasTabsTop=n&&!i}),e.$on("$destroy",function(){delete e.$hasTabs,delete e.$hasTabsTop})}e.addClass("view");var i=angular.element('
');return i.append(e.contents()),e.append(i),{pre:n}}}}]),c.directive("ionToggle",["$ionicGesture","$timeout",function(){return{restrict:"E",replace:!0,require:"?ngModel",scope:{ngModel:"=?",ngValue:"=?",ngChecked:"=?",ngChange:"&",ngDisabled:"=?"},transclude:!0,template:'
',compile:function(e,t){var n=e.find("input");return t.name&&n.attr("name",t.name),t.ngChecked&&n.attr("ng-checked","ngChecked"),t.ngTrueValue&&n.attr("ng-true-value",t.ngTrueValue),t.ngFalseValue&&n.attr("ng-false-value",t.ngFalseValue),t.toggleClass&&e[0].getElementsByTagName("label")[0].classList.add(t.toggleClass),function(e,t){var n,i,r,o;n=t[0].getElementsByTagName("label")[0],i=n.children[0],r=n.children[1],o=r.children[0];var a=angular.element(i).controller("ngModel");e.toggle=new ionic.views.Toggle({el:n,track:r,checkbox:i,handle:o,onChange:function(){a.$setViewValue(i.checked?!0:!1),e.$apply()}}),e.$on("$destroy",function(){e.toggle.destroy() +})}}}}]),c.directive("ionView",["$ionicViewService","$rootScope","$animate",function(){return{restrict:"EA",priority:1e3,require:"^?ionNavBar",compile:function(e){return e.addClass("pane"),e[0].removeAttribute("title"),function(e,t,n,i){if(i){if(angular.isDefined(n.title)){var r=n.title;i.changeTitle(r,e.$navDirection),n.$observe("title",function(e){e!==r&&i.setTitle(e)})}var o=angular.isDefined(n.hideBackButton)?n.hideBackButton:"false";e.$watch(o,function(e){i.showBackButton(!e)});var a=angular.isDefined(n.hideNavBar)?n.hideNavBar:"false";e.$watch(a,function(e){i.showBar(!e)})}}}}}])}(); \ No newline at end of file diff --git a/release/js/ionic.bundle.js b/release/js/ionic.bundle.js index 2e2b9c220bc..c5fd0185a43 100644 --- a/release/js/ionic.bundle.js +++ b/release/js/ionic.bundle.js @@ -9,7 +9,7 @@ * Copyright 2014 Drifty Co. * http://drifty.com/ * - * Ionic, v1.0.0-beta.3 + * Ionic, v1.0.0-beta.4 * A powerful HTML5 mobile app framework. * http://ionicframework.com/ * @@ -26,7 +26,7 @@ window.ionic = { controllers: {}, views: {}, - version: '1.0.0-beta.3' + version: '1.0.0-beta.4' }; (function(ionic) { @@ -419,36 +419,31 @@ window.ionic = { (function(ionic) { // Custom event polyfill - if(!window.CustomEvent) { - (function() { - var CustomEvent; - - CustomEvent = function(event, params) { - var evt; - params = params || { - bubbles: false, - cancelable: false, - detail: undefined - }; - try { - evt = document.createEvent("CustomEvent"); - evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); - } catch (error) { - // fallback for browsers that don't support createEvent('CustomEvent') - evt = document.createEvent("Event"); - for (var param in params) { - evt[param] = params[param]; - } - evt.initEvent(event, params.bubbles, params.cancelable); - } - return evt; + ionic.CustomEvent = window.CustomEvent || (function() { + var CustomEvent; + CustomEvent = function(event, params) { + var evt; + params = params || { + bubbles: false, + cancelable: false, + detail: undefined }; - - CustomEvent.prototype = window.Event.prototype; - - window.CustomEvent = CustomEvent; - })(); - } + try { + evt = document.createEvent("CustomEvent"); + evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); + } catch (error) { + // fallback for browsers that don't support createEvent('CustomEvent') + evt = document.createEvent("Event"); + for (var param in params) { + evt[param] = params[param]; + } + evt.initEvent(event, params.bubbles, params.cancelable); + } + return evt; + } + CustomEvent.prototype = window.Event.prototype; + return CustomEvent; + })(); /** @@ -471,7 +466,7 @@ window.ionic = { */ // Trigger a new event trigger: function(eventType, data, bubbles, cancelable) { - var event = new CustomEvent(eventType, { + var event = new ionic.CustomEvent(eventType, { detail: data, bubbles: !!bubbles, cancelable: !!cancelable @@ -2060,6 +2055,8 @@ window.ionic = { if(this.isWebView()) { this.platforms.push('webview'); this.platforms.push('cordova'); + } else { + this.platforms.push('browser'); } if(this.isIPad()) this.platforms.push('ipad'); @@ -2099,7 +2096,10 @@ window.ionic = { * @returns {boolean} Whether we are running on iPad. */ isIPad: function() { - return this.ua.toLowerCase().indexOf('ipad') >= 0; + if( /iPad/i.test(window.navigator.platform) ) { + return true; + } + return /iPad/i.test(this.ua); }, /** * @ngdoc method @@ -2140,7 +2140,7 @@ window.ionic = { } else if(this.ua.indexOf('iPhone') > -1 || this.ua.indexOf('iPad') > -1 || this.ua.indexOf('iPod') > -1) { platformName = 'ios'; } else { - platformName = ''; + platformName = window.navigator.platform && window.navigator.platform.toLowerCase().split(' ')[0] || ''; } }, @@ -2382,34 +2382,64 @@ window.ionic = { })(document, ionic); +/** + * @ngdoc page + * @name tap + * @module ionic + * @description + * On touch devices such as a phone or tablet, some browsers implement a 300ms delay between + * the time the user stops touching the display and the moment the browser executes the + * click. This delay was initially introduced so the browser can know whether the user wants to + * double-tap to zoom in on the webpage. Basically, the browser waits roughly 300ms to see if + * the user is double-tapping, or just tapping on the display once. + * + * Out of the box, Ionic automatically removes the 300ms delay in order to make Ionic apps + * feel more "native" like. Resultingly, other solutions such as + * [fastclick](https://github.com/ftlabs/fastclick) and Angular's + * [ngTouch](https://docs.angularjs.org/api/ngTouch) should not be included, to avoid conflicts. + * + * In some cases, third-party libraries may also be working with touch events which can interfere + * with the tap system. For example, mapping libraries like Google or Leaflet Maps often implement + * a touch detection system which conflicts with Ionic's tap system. + * + * ### Disabling the tap system + * + * To disable the tap for an element and all of its children elements, + * add the attribute `data-tap-disabled="true"`. + * + * ```html + *
+ *
+ *
+ * ``` + * + * ### Additional Notes: + * + * - Ionic tap works with Ionic's JavaScript scrolling + * - Elements can come and go from the DOM and Ionic tap doesn't keep adding and removing + * listeners + * - No "tap delay" after the first "tap" (you can tap as fast as you want, they all click) + * - Minimal events listeners, only being added to document + * - Correct focus in/out on each input type (select, textearea, range) on each platform/device + * - Shows and hides virtual keyboard correctly for each platform/device + * - Works with labels surrounding inputs + * - Does not fire off a click if the user moves the pointer too far + * - Adds and removes an 'activated' css class + * - Multiple [unit tests](https://github.com/driftyco/ionic/blob/master/test/unit/utils/tap.unit.js) for each scenario + * + */ /* IONIC TAP --------------- - Both touch and mouse events are added to the document.body on DOM ready - - If a touch event happens, it removes the mouse event listeners (temporarily) - - Remembers the last touchstart event + - If a touch event happens, it does not use mouse event listeners - On touchend, if the distance between start and end was small, trigger a click - In the triggered click event, add a 'isIonicTap' property - The triggered click receives the same x,y coordinates as as the end event - On document.body click listener (with useCapture=true), only allow clicks with 'isIonicTap' - - After XXms, bring back the mouse event listeners incase they switch from touch and mouse - - If no touch events and only mouse, then touch events never fire, only mouse - Triggering clicks with mouse events work the same as touch, except with mousedown/mouseup - Tapping inputs is disabled during scrolling - - - Does not require other libraries to hook into ionic.tap, it just works - - Elements can come and go from the DOM and it doesn't have to keep adding and removing listeners - - No "tap delay" after the first "tap" (you can tap as fast as you want, they all click) - - Minimal events listeners, only being added to document.body - - Correct focus in/out on each input type on each platform/device - - Shows and hides virtual keyboard correctly for each platform/device - - No user-agent sniffing - - Works with labels surrounding inputs - - Does not fire off a click if the user moves the pointer too far - - Adds and removes an 'activated' css class - - Multiple unit tests for each scenario - */ var tapDoc; // the element which the listeners are on (document.body) @@ -2467,7 +2497,7 @@ ionic.tap = { ignoreScrollStart: function(e) { return (e.defaultPrevented) || // defaultPrevented has been assigned by another component handling the event (e.target.isContentEditable) || - (e.target.type === 'range') || + (/file|range/i).test(e.target.type) || (e.target.dataset ? e.target.dataset.preventScroll : e.target.getAttribute('data-prevent-default')) == 'true' || // manually set within an elements attributes (!!(/object|embed/i).test(e.target.tagName)); // flash/movie/object touches should not try to scroll }, @@ -2532,6 +2562,22 @@ ionic.tap = { previousInputFocus[x].focus(); } }); + }, + + requiresNativeClick: function(ele) { + if(!ele || ele.disabled || (/file|range/i).test(ele.type) || (/object|video/i).test(ele.tagName) ) { + return true; + } + if(ele.nodeType === 1) { + var element = ele; + while(element) { + if( (element.dataset ? element.dataset.tapDisabled : element.getAttribute('data-tap-disabled')) == 'true' ) { + return true; + } + element = element.parentElement; + } + } + return false; } }; @@ -2549,7 +2595,7 @@ function tapClick(e) { var container = tapContainingElement(e.target); var ele = tapTargetElement(container); - if( tapRequiresNativeClick(ele) || tapPointerMoved ) return false; + if( ionic.tap.requiresNativeClick(ele) || tapPointerMoved ) return false; var c = getPointerCoordinates(e); @@ -2576,7 +2622,7 @@ function tapClickGateKeeper(e) { // do not allow through any click events that were not created by ionic.tap if( (ionic.scroll.isScrolling && ionic.tap.containsOrIsTextInput(e.target) ) || - (!e.isIonicTap && !tapRequiresNativeClick(e.target)) ) { + (!e.isIonicTap && !ionic.tap.requiresNativeClick(e.target)) ) { void 0; e.stopPropagation(); @@ -2588,22 +2634,6 @@ function tapClickGateKeeper(e) { } } -function tapRequiresNativeClick(ele) { - if(!ele || ele.disabled || (/file|range/i).test(ele.type) || (/object|video/i).test(ele.tagName) ) { - return true; - } - if(ele.nodeType === 1) { - var element = ele; - while(element) { - if( (element.dataset ? element.dataset.tapDisabled : element.getAttribute('data-tap-disabled')) == 'true' ) { - return true; - } - element = element.parentElement; - } - } - return false; -} - // MOUSE function tapMouseDown(e) { if(e.isIonicTap || tapIgnoreEvent(e)) return; @@ -2637,7 +2667,7 @@ function tapMouseUp(e) { return false; } - if( tapIgnoreEvent(e) ) return; + if( tapIgnoreEvent(e) || e.target.tagName === 'SELECT' ) return false; if( !tapHasPointerMoved(e) ) { tapClick(e); @@ -2871,7 +2901,7 @@ ionic.DomUtil.ready(function(){ // when an element is touched/clicked, it climbs up a few // parents to see if it is an .item or .button element ionic.requestAnimationFrame(function(){ - if (tapRequiresNativeClick(e.target)) return; + if ( ionic.tap.requiresNativeClick(e.target) ) return; var ele = e.target; var eleToActivate; @@ -2925,7 +2955,6 @@ ionic.DomUtil.ready(function(){ } function activateElements() { - // console.log('ACTIVATING'); // activate all elements in the queue for(var key in queueElements) { if(queueElements[key]) { @@ -3145,30 +3174,36 @@ var keyboardIsOpen; var keyboardActiveElement; var keyboardFocusOutTimer; var keyboardFocusInTimer; +var keyboardLastShow = 0; var KEYBOARD_OPEN_CSS = 'keyboard-open'; var SCROLL_CONTAINER_CSS = 'scroll'; ionic.keyboard = { isOpen: false, - height: null + height: null, + landscape: false, }; function keyboardInit() { if( keyboardHasPlugin() ) { window.addEventListener('native.showkeyboard', keyboardNativeShow); + window.addEventListener('native.hidekeyboard', keyboardFocusOut); + } + else { + document.body.addEventListener('focusout', keyboardFocusOut); } document.body.addEventListener('ionic.focusin', keyboardBrowserFocusIn); document.body.addEventListener('focusin', keyboardBrowserFocusIn); - document.body.addEventListener('focusout', keyboardFocusOut); document.body.addEventListener('orientationchange', keyboardOrientationChange); document.removeEventListener('touchstart', keyboardInit); } function keyboardNativeShow(e) { + clearTimeout(keyboardFocusOutTimer); ionic.keyboard.height = e.keyboardHeight; } @@ -3190,10 +3225,27 @@ function keyboardSetShow(e) { clearTimeout(keyboardFocusOutTimer); keyboardFocusInTimer = setTimeout(function(){ - var keyboardHeight = keyboardGetHeight(); + if ( keyboardLastShow + 350 > Date.now() ) return; + keyboardLastShow = Date.now(); + var keyboardHeight; var elementBounds = keyboardActiveElement.getBoundingClientRect(); + var count = 0; + + var pollKeyboardHeight = setInterval(function(){ - keyboardShow(e.target, elementBounds.top, elementBounds.bottom, keyboardViewportHeight, keyboardHeight); + keyboardHeight = keyboardGetHeight(); + if (count > 10){ + clearInterval(pollKeyboardHeight); + //waited long enough, just guess + keyboardHeight = 275; + } + if (keyboardHeight){ + keyboardShow(e.target, elementBounds.top, elementBounds.bottom, keyboardViewportHeight, keyboardHeight); + clearInterval(pollKeyboardHeight); + } + count++; + + }, 100); }, 32); } @@ -3205,15 +3257,9 @@ function keyboardShow(element, elementTop, elementBottom, viewportHeight, keyboa keyboardHeight: keyboardHeight }; - if( keyboardIsOverWebView() ) { - // keyboard sits on top of the view, but doesn't adjust the view's height - // lower the content height by subtracting the keyboard height from the view height - details.contentHeight = viewportHeight - keyboardHeight; - } else { - // view's height was shrunk down and the keyboard takes up the space the view doesn't fill - // do not add extra padding at the bottom of the scroll view, native already did that - details.contentHeight = viewportHeight; - } + details.hasPlugin = keyboardHasPlugin(); + + details.contentHeight = viewportHeight - keyboardHeight; void 0; @@ -3284,32 +3330,70 @@ function keyboardPreventDefault(e) { } function keyboardOrientationChange() { - keyboardViewportHeight = window.innerHeight; - setTimeout(function(){ - keyboardViewportHeight = window.innerHeight; - }, 999); + var updatedViewportHeight = window.innerHeight; + + //too slow, have to wait for updated height + if (updatedViewportHeight === keyboardViewportHeight){ + var count = 0; + var pollViewportHeight = setInterval(function(){ + //give up + if (count > 10){ + clearInterval(pollViewportHeight); + } + + updatedViewportHeight = window.innerHeight; + + if (updatedViewportHeight !== keyboardViewportHeight){ + if (updatedViewportHeight < keyboardViewportHeight){ + ionic.keyboard.landscape = true; + } + else { + ionic.keyboard.landscape = false; + } + keyboardViewportHeight = updatedViewportHeight; + clearInterval(pollViewportHeight); + } + count++; + + }, 50); + } + else { + keyboardViewportHeight = updatedViewportHeight; + } } function keyboardGetHeight() { // check if we are already have a keyboard height from the plugin - if (ionic.keyboard.height ) { + if ( ionic.keyboard.height ) { return ionic.keyboard.height; } + if ( ionic.Platform.isAndroid() ){ + //should be using the plugin, no way to know how big the keyboard is, so guess + if ( ionic.Platform.isFullScreen ){ + return 275; + } + //otherwise, wait for the screen to resize + if ( window.innerHeight < keyboardViewportHeight ){ + return keyboardViewportHeight - window.innerHeight; + } + else { + return 0; + } + } + // fallback for when its the webview without the plugin // or for just the standard web browser if( ionic.Platform.isIOS() ) { - if( ionic.Platform.isWebView() ) { - return 260; - } - return 216; - } else if( ionic.Platform.isAndroid() ) { - if( ionic.Platform.isWebView() ) { - return 220; + if ( ionic.keyboard.landscape ){ + return 206; } - if( ionic.Platform.version() <= 4.3) { - return 230; + + if (!ionic.Platform.isWebView()){ + return 216; } + + return 260; } // safe guess @@ -3326,11 +3410,6 @@ function keyboardIsWithinScroll(ele) { return false; } -function keyboardIsOverWebView() { - return ( ionic.Platform.isIOS() ) || - ( ionic.Platform.isAndroid() && !ionic.Platform.isWebView() ); -} - function keyboardHasPlugin() { return !!(window.cordova && cordova.plugins && cordova.plugins.Keyboard); } @@ -3352,6 +3431,14 @@ ionic.Platform.ready(function() { var viewportTag; var viewportProperties = {}; +ionic.viewport = { + orientation: function() { + // 0 = Portrait + // 90 = Landscape + // not using window.orientation because each device has a different implementation + return (window.innerWidth > window.innerHeight ? 90 : 0); + } +}; function viewportLoadTag() { var x; @@ -3367,43 +3454,112 @@ function viewportLoadTag() { var props = viewportTag.content.toLowerCase().replace(/\s+/g, '').split(','); var keyValue; for(x=0; x 1 ? keyValue[1] : '_'); + } } - viewportInitWebView(); + viewportUpdate(); } } -function viewportInitWebView() { - var hasViewportChange = false; +function viewportUpdate() { + // unit tests in viewport.unit.js + + var initWidth = viewportProperties.width; + var initHeight = viewportProperties.height; + var p = ionic.Platform; + var version = p.version(); + var DEVICE_WIDTH = 'device-width'; + var DEVICE_HEIGHT = 'device-height'; + var orientation = ionic.viewport.orientation(); + + // Most times we're removing the height and adding the width + // So this is the default to start with, then modify per platform/version/oreintation + delete viewportProperties.height; + viewportProperties.width = DEVICE_WIDTH; + + if( p.isIPad() ) { + // iPad + + if( version > 7 ) { + // iPad >= 7.1 + // https://issues.apache.org/jira/browse/CB-4323 + delete viewportProperties.width; + + } else { + // iPad <= 7.0 + + if( p.isWebView() ) { + // iPad <= 7.0 WebView - if( ionic.Platform.isWebView() ) { - if( viewportProperties.height != 'device-height' ) { - viewportProperties.height = 'device-height'; - hasViewportChange = true; + if( orientation == 90 ) { + // iPad <= 7.0 WebView Landscape + viewportProperties.height = '0'; + + } else if(version == 7) { + // iPad <= 7.0 WebView Portait + viewportProperties.height = DEVICE_HEIGHT; + } + } else { + // iPad <= 6.1 Browser + if(version < 7) { + viewportProperties.height = '0'; + } + } + } + + } else if( p.isIOS() ) { + // iPhone + + if( p.isWebView() ) { + // iPhone WebView + + if(version > 7) { + // iPhone >= 7.1 WebView + delete viewportProperties.width; + + } else if(version < 7) { + // iPhone <= 6.1 WebView + // if height was set it needs to get removed with this hack for <= 6.1 + if( initHeight ) viewportProperties.height = '0'; + } + + } else { + // iPhone Browser + + if (version < 7) { + // iPhone <= 6.1 Browser + // if height was set it needs to get removed with this hack for <= 6.1 + if( initHeight ) viewportProperties.height = '0'; + } } - } else if( viewportProperties.height ) { - delete viewportProperties.height; - hasViewportChange = true; - } - if(hasViewportChange) viewportUpdate(); -} -function viewportUpdate(updates) { - if(!viewportTag) return; + } - ionic.Utils.extend(viewportProperties, updates); + // only update the viewport tag if there was a change + if(initWidth !== viewportProperties.width || initHeight !== viewportProperties.height) { + viewportTagUpdate(); + } +} +function viewportTagUpdate() { var key, props = []; for(key in viewportProperties) { - if(viewportProperties[key]) props.push(key + '=' + viewportProperties[key]); + if( viewportProperties[key] ) { + props.push(key + (viewportProperties[key] == '_' ? '' : '=' + viewportProperties[key]) ); + } } - viewportTag.content = props.join(','); + viewportTag.content = props.join(', '); } -ionic.DomUtil.ready(function() { +ionic.Platform.ready(function() { viewportLoadTag(); + + window.addEventListener("orientationchange", function(){ + setTimeout(viewportUpdate, 1000); + }, false); }); (function(ionic) { @@ -3802,7 +3958,7 @@ ionic.views.Scroll = ionic.views.View.inherit({ self.resize(); }, 1000, true); - this.onScroll = function(scrollTop) { + this.onScroll = function() { if(!ionic.scroll.isScrolling) { setTimeout(self.setScrollStart, 50); @@ -3825,6 +3981,7 @@ ionic.views.Scroll = ionic.views.View.inherit({ }; this.triggerScrollEvent = ionic.throttle(function() { + self.onScroll(); ionic.trigger('scroll', { scrollTop: self.__scrollTop, scrollLeft: self.__scrollLeft, @@ -4044,15 +4201,26 @@ ionic.views.Scroll = ionic.views.View.inherit({ if( !self.isScrolledIntoView ) { // shrink scrollview so we can actually scroll if the input is hidden // if it isn't shrink so we can scroll to inputs under the keyboard - container.style.height = (container.clientHeight - e.detail.keyboardHeight) + "px"; - container.style.overflow = "visible"; + if (ionic.Platform.isIOS() || ionic.Platform.isFullScreen){ + container.style.height = (container.clientHeight - e.detail.keyboardHeight) + "px"; + container.style.overflow = "visible"; + //update scroll view + self.resize(); + } self.isScrolledIntoView = true; - //update scroll view - self.resize(); } //If the element is positioned under the keyboard... if( e.detail.isElementUnderKeyboard ) { + var delay; + // Wait on android for scroll view to resize + if ( !ionic.Platform.isFullScreen && e.detail.hasPlugin ) { + delay = 350; + } + else { + delay = 80; + } + //Put element in middle of visible screen //Wait for resize() to reset scroll position ionic.scroll.isScrolling = true; @@ -4064,9 +4232,7 @@ ionic.views.Scroll = ionic.views.View.inherit({ ionic.tap.cloneFocusedInput(container, self); self.scrollBy(0, scrollTop, true); self.onScroll(); - }, - (ionic.Platform.isIOS() ? 80 : 350) - ); + }, delay); } //Only the first scrollView parent of the element that broadcasted this event @@ -4215,11 +4381,14 @@ ionic.views.Scroll = ionic.views.View.inherit({ self.__fadeScrollbars('out'); }, 100, false); - document.addEventListener("mousewheel", function(e) { + //For Firefox + document.addEventListener('mousewheel', onMouseWheel); + function onMouseWheel(e) { + self.hintResize(); wheelShowBarFn(); self.scrollBy(e.wheelDeltaX/self.options.wheelDampen, -e.wheelDeltaY/self.options.wheelDampen); wheelHideBarFn(); - }); + } } }, @@ -5698,6 +5867,9 @@ ionic.scroll = { var margin = Math.max(leftWidth, rightWidth) + 10; + //Reset left and right before setting again + titleEl.style.left = titleEl.style.right = ''; + // Size and align the header titleEl based on the sizes of the left and // right children, and the desired alignment mode if(align == 'center') { @@ -6169,7 +6341,7 @@ ionic.scroll = { // Return the list item from the given target _getItem: function(target) { while(target) { - if(target.classList.contains(ITEM_CLASS)) { + if(target.classList && target.classList.contains(ITEM_CLASS)) { return target; } target = target.parentNode; @@ -7097,362 +7269,5402 @@ ionic.views.Slider = ionic.views.View.inherit({ }, - setOpenPercent: function(openPercent) { - // only make a change if the new open percent has changed - if(this.openPercent < 0 || (openPercent < (this.openPercent - 3) || openPercent > (this.openPercent + 3) ) ) { - this.openPercent = openPercent; + setOpenPercent: function(openPercent) { + // only make a change if the new open percent has changed + if(this.openPercent < 0 || (openPercent < (this.openPercent - 3) || openPercent > (this.openPercent + 3) ) ) { + this.openPercent = openPercent; + + if(openPercent === 0) { + this.val(false); + } else if(openPercent === 100) { + this.val(true); + } else { + var openPixel = Math.round( (openPercent / 100) * this.track.offsetWidth - (this.handle.offsetWidth) ); + openPixel = (openPixel < 1 ? 0 : openPixel); + this.handle.style[ionic.CSS.TRANSFORM] = 'translate3d(' + openPixel + 'px,0,0)'; + } + } + }, + + val: function(value) { + if(value === true || value === false) { + if(this.handle.style[ionic.CSS.TRANSFORM] !== "") { + this.handle.style[ionic.CSS.TRANSFORM] = ""; + } + this.checkbox.checked = value; + this.openPercent = (value ? 100 : 0); + this.onChange && this.onChange(); + } + return this.checkbox.checked; + } + + }); + +})(ionic); + +(function(ionic) { +'use strict'; + ionic.controllers.ViewController = function(options) { + this.initialize.apply(this, arguments); + }; + + ionic.controllers.ViewController.inherit = ionic.inherit; + + ionic.extend(ionic.controllers.ViewController.prototype, { + initialize: function() {}, + // Destroy this view controller, including all child views + destroy: function() { + } + }); + +})(window.ionic); + +(function(ionic) { +'use strict'; + + /** + * The SideMenuController is a controller with a left and/or right menu that + * can be slid out and toggled. Seen on many an app. + * + * The right or left menu can be disabled or not used at all, if desired. + */ + ionic.controllers.SideMenuController = ionic.controllers.ViewController.inherit({ + initialize: function(options) { + var self = this; + + this.left = options.left; + this.right = options.right; + this.content = options.content; + this.dragThresholdX = options.dragThresholdX || 10; + + this._rightShowing = false; + this._leftShowing = false; + this._isDragging = false; + + if(this.content) { + this.content.onDrag = function(e) { + self._handleDrag(e); + }; + + this.content.onEndDrag =function(e) { + self._endDrag(e); + }; + } + }, + /** + * Set the content view controller if not passed in the constructor options. + * + * @param {object} content + */ + setContent: function(content) { + var self = this; + + this.content = content; + + this.content.onDrag = function(e) { + self._handleDrag(e); + }; + + this.content.endDrag = function(e) { + self._endDrag(e); + }; + }, + + isOpenLeft: function() { + return this.getOpenAmount() > 0; + }, + + isOpenRight: function() { + return this.getOpenAmount() < 0; + }, + + /** + * Toggle the left menu to open 100% + */ + toggleLeft: function(shouldOpen) { + var openAmount = this.getOpenAmount(); + if (arguments.length === 0) { + shouldOpen = openAmount <= 0; + } + this.content.enableAnimation(); + if(!shouldOpen) { + this.openPercentage(0); + } else { + this.openPercentage(100); + } + }, + + /** + * Toggle the right menu to open 100% + */ + toggleRight: function(shouldOpen) { + var openAmount = this.getOpenAmount(); + if (arguments.length === 0) { + shouldOpen = openAmount >= 0; + } + this.content.enableAnimation(); + if(!shouldOpen) { + this.openPercentage(0); + } else { + this.openPercentage(-100); + } + }, + + /** + * Close all menus. + */ + close: function() { + this.openPercentage(0); + }, + + /** + * @return {float} The amount the side menu is open, either positive or negative for left (positive), or right (negative) + */ + getOpenAmount: function() { + return this.content && this.content.getTranslateX() || 0; + }, + + /** + * @return {float} The ratio of open amount over menu width. For example, a + * menu of width 100 open 50 pixels would be open 50% or a ratio of 0.5. Value is negative + * for right menu. + */ + getOpenRatio: function() { + var amount = this.getOpenAmount(); + if(amount >= 0) { + return amount / this.left.width; + } + return amount / this.right.width; + }, + + isOpen: function() { + return this.getOpenAmount() !== 0; + }, + + /** + * @return {float} The percentage of open amount over menu width. For example, a + * menu of width 100 open 50 pixels would be open 50%. Value is negative + * for right menu. + */ + getOpenPercentage: function() { + return this.getOpenRatio() * 100; + }, + + /** + * Open the menu with a given percentage amount. + * @param {float} percentage The percentage (positive or negative for left/right) to open the menu. + */ + openPercentage: function(percentage) { + var p = percentage / 100; + + if(this.left && percentage >= 0) { + this.openAmount(this.left.width * p); + } else if(this.right && percentage < 0) { + var maxRight = this.right.width; + this.openAmount(this.right.width * p); + } + }, + + /** + * Open the menu the given pixel amount. + * @param {float} amount the pixel amount to open the menu. Positive value for left menu, + * negative value for right menu (only one menu will be visible at a time). + */ + openAmount: function(amount) { + var maxLeft = this.left && this.left.width || 0; + var maxRight = this.right && this.right.width || 0; + + // Check if we can move to that side, depending if the left/right panel is enabled + if(!(this.left && this.left.isEnabled) && amount > 0) { + this.content.setTranslateX(0); + return; + } + + if(!(this.right && this.right.isEnabled) && amount < 0) { + this.content.setTranslateX(0); + return; + } + + if(this._leftShowing && amount > maxLeft) { + this.content.setTranslateX(maxLeft); + return; + } + + if(this._rightShowing && amount < -maxRight) { + this.content.setTranslateX(-maxRight); + return; + } + + this.content.setTranslateX(amount); + + if(amount >= 0) { + this._leftShowing = true; + this._rightShowing = false; + + if(amount > 0) { + // Push the z-index of the right menu down + this.right && this.right.pushDown && this.right.pushDown(); + // Bring the z-index of the left menu up + this.left && this.left.bringUp && this.left.bringUp(); + } + } else { + this._rightShowing = true; + this._leftShowing = false; + + // Bring the z-index of the right menu up + this.right && this.right.bringUp && this.right.bringUp(); + // Push the z-index of the left menu down + this.left && this.left.pushDown && this.left.pushDown(); + } + }, + + /** + * Given an event object, find the final resting position of this side + * menu. For example, if the user "throws" the content to the right and + * releases the touch, the left menu should snap open (animated, of course). + * + * @param {Event} e the gesture event to use for snapping + */ + snapToRest: function(e) { + // We want to animate at the end of this + this.content.enableAnimation(); + this._isDragging = false; + + // Check how much the panel is open after the drag, and + // what the drag velocity is + var ratio = this.getOpenRatio(); + + if(ratio === 0) { + // Just to be safe + this.openPercentage(0); + return; + } + + var velocityThreshold = 0.3; + var velocityX = e.gesture.velocityX; + var direction = e.gesture.direction; + + // Less than half, going left + //if(ratio > 0 && ratio < 0.5 && direction == 'left' && velocityX < velocityThreshold) { + //this.openPercentage(0); + //} + + // Going right, less than half, too slow (snap back) + if(ratio > 0 && ratio < 0.5 && direction == 'right' && velocityX < velocityThreshold) { + this.openPercentage(0); + } + + // Going left, more than half, too slow (snap back) + else if(ratio > 0.5 && direction == 'left' && velocityX < velocityThreshold) { + this.openPercentage(100); + } + + // Going left, less than half, too slow (snap back) + else if(ratio < 0 && ratio > -0.5 && direction == 'left' && velocityX < velocityThreshold) { + this.openPercentage(0); + } + + // Going right, more than half, too slow (snap back) + else if(ratio < 0.5 && direction == 'right' && velocityX < velocityThreshold) { + this.openPercentage(-100); + } + + // Going right, more than half, or quickly (snap open) + else if(direction == 'right' && ratio >= 0 && (ratio >= 0.5 || velocityX > velocityThreshold)) { + this.openPercentage(100); + } + + // Going left, more than half, or quickly (span open) + else if(direction == 'left' && ratio <= 0 && (ratio <= -0.5 || velocityX > velocityThreshold)) { + this.openPercentage(-100); + } + + // Snap back for safety + else { + this.openPercentage(0); + } + }, + + // End a drag with the given event + _endDrag: function(e) { + if(this._isDragging) { + this.snapToRest(e); + } + this._startX = null; + this._lastX = null; + this._offsetX = null; + }, + + // Handle a drag event + _handleDrag: function(e) { + // If we don't have start coords, grab and store them + if(!this._startX) { + this._startX = e.gesture.touches[0].pageX; + this._lastX = this._startX; + } else { + // Grab the current tap coords + this._lastX = e.gesture.touches[0].pageX; + } + + // Calculate difference from the tap points + if(!this._isDragging && Math.abs(this._lastX - this._startX) > this.dragThresholdX) { + // if the difference is greater than threshold, start dragging using the current + // point as the starting point + this._startX = this._lastX; + + this._isDragging = true; + // Initialize dragging + this.content.disableAnimation(); + this._offsetX = this.getOpenAmount(); + } + + if(this._isDragging) { + this.openAmount(this._offsetX + (this._lastX - this._startX)); + } + } + }); + +})(ionic); + +(function(window) { + var time = Date.now || function() { + return +new Date(); + }; + var desiredFrames = 60; + var millisecondsPerSecond = 1000; + var running = {}; + var counter = 1; + + // Namespace + ionic.Animation = {}; + + /** + * The main animation system manager. Treated as a singleton. + */ + ionic.Animation = { + create: function(opts) { + return new ionic.Animation.Animation(opts); + }, + + animationStarted: function(instance) { + var id = counter++; + + // Compacting running db automatically every few new animations + if (id % 20 === 0) { + var newRunning = {}; + for (var usedId in running) { + newRunning[usedId] = true; + } + running = newRunning; + } + + // Mark as running + running[id] = true; + + instance.isRunning = true; + instance._animationId = id; + + // Return unique animation ID + return id; + }, + + animationStopped: function(instance) { + instance.isRunning = false; + } + + /* TODO: Move animation set management here instead of instance + anims: [], + add: function(animation) { + this.anims.push(animation); + }, + remove: function(animation) { + var i, j; + for(i = 0, j = this.anims.length; i < j; i++) { + if(this.anims[i] === animation) { + return this.anims.splice(i, 1); + } + } + }, + clear: function(shouldStop) { + while(this.anims.length) { + var anim = this.anims.pop(); + if(shouldStop === true) { + anim.stop(); + } + } + }, + */ + + /** + * Stops the given animation. + * + * @param id {Integer} Unique animation ID + * @return {Boolean} Whether the animation was stopped (aka, was running before) + * TODO: Requires above fix + stop: function(id) { + var cleared = running[id] != null; + if (cleared) { + running[id] = null; + } + + return cleared; + }, + */ + + + /** + * Whether the given animation is still running. + * + * @param id {Integer} Unique animation ID + * @return {Boolean} Whether the animation is still running + isRunning: function(id) { + return running[id] != null; + }, + */ + + }; + + /** + * Animation instance + */ + ionic.Animation.Animation = function(opts) { + ionic.extend(this, opts); + + if(opts.useSlowAnimations) { + void 0; + this.delay *= 3; + this.duration *= 3; + } + }; + + ionic.Animation.Animation.prototype = { + el: null, + curve: 'linear', + duration: 500, + delay: 0, + repeat: -1, + reverse: false, + autoReverse: false, + + step: function(percent) {}, + + stop: function() { + this.isRunning = false; + this.shouldEnd = true; + }, + play: function() { + this.isPaused = false; + this.start(); + }, + pause: function() { + this.isPaused = true; + }, + _saveState: function(percent, iteration, reverse) { + this._pauseState = { + percent: percent, + iteration: iteration, + reverse: reverse + } + }, + restart: function() { + }, + + start: function() { + var self = this; + + var tf; + + void 0; + + + // Grab the timing function + if(typeof this.curve === 'string') { + tf = ionic.Animation.TimingFn[this.curve] || ionic.Animation.TimingFn['linear']; + } else { + tf = this.curve; + } + + // Get back a timing function for the given duration (used for precision) + tf = tf(this.duration); + + // Set up the initial animation state + var animState = { + startPercent: this.reverse === true ? 1 : 0, + endPercent: this.reverse === true ? 0 : 1, + duration: this.duration, + easingMethod: tf, + delay: this.delay, + reverse: this.reverse, + repeat: this.repeat, + autoReverse: this.autoReverse + } + + + if(this._pauseState) { + // We were paused, so update the fields + ionic.extend(animState, this._pauseState); + this._pauseState = null; + } + + ionic.Animation.animationStarted(this); + + return this._run(function(percent, now, render) { + if(render) { + self.step(percent); + } + }, function(droppedFrames, finishedAnimation) { + ionic.Animation.animationStopped(self); + void 0; + }, animState); + }, + + /** + * Start the animation. + * + * @param stepCallback {Function} Pointer to function which is executed on every step. + * Signature of the method should be `function(percent, now, virtual) { return continueWithAnimation; }` + * @param completedCallback {Function} + * Signature of the method should be `function(droppedFrames, finishedAnimation) {}` + * @param duration {Integer} Milliseconds to run the animation + * @param easingMethod {Function} Pointer to easing function + * Signature of the method should be `function(percent) { return modifiedValue; }` + * @return {Integer} Identifier of animation. Can be used to stop it any time. + */ + _run: function(stepCallback, completedCallback, state) { + + var self = this; + var start = time(); + var lastFrame = start; + var startTime = start + state.delay; + var percent = state.startPercent; + var startPercent = state.startPercent; + var endPercent = state.endPercent; + var autoReverse = state.autoReverse; + var delay = state.delay; + var duration = state.duration; + var easingMethod = state.easingMethod; + var repeat = state.repeat; + var reverse = state.reverse; + + var dropCounter = 0; + var iteration = 0; + + var perhapsAutoreverse = function() { + // Check if we hit the end and should auto reverse + if(percent === endPercent && autoReverse) { + // Flip the start and end values + var sp = endPercent; + reverse = !reverse; + endPercent = startPercent; + startPercent = sp; + + if(repeat === 0) { + autoReverse = false; + } + } else { + // Otherwise, just start over + percent = startPercent; + } + // Start fresh either way + start = time(); + ionic.requestAnimationFrame(step); + } + + + // This is the internal step method which is called every few milliseconds + var step = function(virtual) { + + // Normalize virtual value + var render = virtual !== true; + + // Get current time + var now = time(); + var diff = now - start; + + // Verification is executed before next animation step + if(self.isPaused) { + self._saveState(percent, iteration, reverse); + return; + } + + if (!self.isRunning) {// || (verifyCallback && !verifyCallback(id))) { + + completedCallback && completedCallback(desiredFrames - (dropCounter / ((now - start) / millisecondsPerSecond)), self._animationId, false); + return; + + } + + + // For the current rendering to apply let's update omitted steps in memory. + // This is important to bring internal state variables up-to-date with progress in time. + if (render) { + + var droppedFrames = Math.round((now - lastFrame) / (millisecondsPerSecond / desiredFrames)) - 1; + for (var j = 0; j < Math.min(droppedFrames, 4); j++) { + step(true); + dropCounter++; + } + + } + + // Compute percent value + if (diff > delay && duration) { + percent = (diff - delay) / duration; + if(reverse === true) { + percent = 1 - percent; + if (percent < 0) { + percent = 0; + } + } else { + if (percent > 1) { + percent = 1; + } + } + } + + // Execute step callback, then... + var value = easingMethod ? easingMethod(percent) : percent; + if ((stepCallback(value, now, render) === false || percent === endPercent) && render) { + if(repeat === -1) { + perhapsAutoreverse(); + } else if(iteration < repeat) { + // Track iterations + iteration++; + perhapsAutoreverse(); + } else if(repeat === 0 && autoReverse) { + perhapsAutoreverse(); + } else { + completedCallback && completedCallback(desiredFrames - (dropCounter / ((now - start) / millisecondsPerSecond)), self._animationId, percent === endPercent || duration == null); + } + } else if (render) { + lastFrame = now; + ionic.requestAnimationFrame(step); + } + }; + + + // Init first step + ionic.requestAnimationFrame(step); + + } + }; + + +})(window); + +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +(function(ionic) { + + var bezierCoord = function (x,y) { + if(!x) x=0; + if(!y) y=0; + return {x: x, y: y}; + }; + + function B1(t) { return t*t*t; } + function B2(t) { return 3*t*t*(1-t); } + function B3(t) { return 3*t*(1-t)*(1-t); } + function B4(t) { return (1-t)*(1-t)*(1-t); } + + ionic.Animation = ionic.Animation || {} + + + /** + * JavaScript port of Webkit implementation of CSS cubic-bezier(p1x.p1y,p2x,p2y) by http://mck.me + * http://svn.webkit.org/repository/webkit/trunk/Source/WebCore/platform/graphics/UnitBezier.h + */ + ionic.Animation.Bezier = (function(){ + 'use strict'; + + /** + * Duration value to use when one is not specified (400ms is a common value). + * @const + * @type {number} + */ + var DEFAULT_DURATION = 400;//ms + + /** + * The epsilon value we pass to UnitBezier::solve given that the animation is going to run over |dur| seconds. + * The longer the animation, the more precision we need in the timing function result to avoid ugly discontinuities. + * http://svn.webkit.org/repository/webkit/trunk/Source/WebCore/page/animation/AnimationBase.cpp + */ + var solveEpsilon = function(duration) { + return 1.0 / (200.0 * duration); + }; + + /** + * Defines a cubic-bezier curve given the middle two control points. + * NOTE: first and last control points are implicitly (0,0) and (1,1). + * @param p1x {number} X component of control point 1 + * @param p1y {number} Y component of control point 1 + * @param p2x {number} X component of control point 2 + * @param p2y {number} Y component of control point 2 + */ + var unitBezier = function(p1x, p1y, p2x, p2y) { + + // private members -------------------------------------------- + + // Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1). + + /** + * X component of Bezier coefficient C + * @const + * @type {number} + */ + var cx = 3.0 * p1x; + + /** + * X component of Bezier coefficient B + * @const + * @type {number} + */ + var bx = 3.0 * (p2x - p1x) - cx; + + /** + * X component of Bezier coefficient A + * @const + * @type {number} + */ + var ax = 1.0 - cx -bx; + + /** + * Y component of Bezier coefficient C + * @const + * @type {number} + */ + var cy = 3.0 * p1y; + + /** + * Y component of Bezier coefficient B + * @const + * @type {number} + */ + var by = 3.0 * (p2y - p1y) - cy; + + /** + * Y component of Bezier coefficient A + * @const + * @type {number} + */ + var ay = 1.0 - cy - by; + + /** + * @param t {number} parametric timing value + * @return {number} + */ + var sampleCurveX = function(t) { + // `ax t^3 + bx t^2 + cx t' expanded using Horner's rule. + return ((ax * t + bx) * t + cx) * t; + }; + + /** + * @param t {number} parametric timing value + * @return {number} + */ + var sampleCurveY = function(t) { + return ((ay * t + by) * t + cy) * t; + }; + + /** + * @param t {number} parametric timing value + * @return {number} + */ + var sampleCurveDerivativeX = function(t) { + return (3.0 * ax * t + 2.0 * bx) * t + cx; + }; + + /** + * Given an x value, find a parametric value it came from. + * @param x {number} value of x along the bezier curve, 0.0 <= x <= 1.0 + * @param epsilon {number} accuracy limit of t for the given x + * @return {number} the t value corresponding to x + */ + var solveCurveX = function(x, epsilon) { + var t0; + var t1; + var t2; + var x2; + var d2; + var i; + + // First try a few iterations of Newton's method -- normally very fast. + for (t2 = x, i = 0; i < 8; i++) { + x2 = sampleCurveX(t2) - x; + if (Math.abs (x2) < epsilon) { + return t2; + } + d2 = sampleCurveDerivativeX(t2); + if (Math.abs(d2) < 1e-6) { + break; + } + t2 = t2 - x2 / d2; + } + + // Fall back to the bisection method for reliability. + t0 = 0.0; + t1 = 1.0; + t2 = x; + + if (t2 < t0) { + return t0; + } + if (t2 > t1) { + return t1; + } + + while (t0 < t1) { + x2 = sampleCurveX(t2); + if (Math.abs(x2 - x) < epsilon) { + return t2; + } + if (x > x2) { + t0 = t2; + } else { + t1 = t2; + } + t2 = (t1 - t0) * 0.5 + t0; + } + + // Failure. + return t2; + }; + + /** + * @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0 + * @param epsilon {number} the accuracy of t for the given x + * @return {number} the y value along the bezier curve + */ + var solve = function(x, epsilon) { + return sampleCurveY(solveCurveX(x, epsilon)); + }; + + // public interface -------------------------------------------- + + /** + * Find the y of the cubic-bezier for a given x with accuracy determined by the animation duration. + * @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0 + * @param duration {number} the duration of the animation in milliseconds + * @return {number} the y value along the bezier curve + */ + return function(x, duration) { + return solve(x, solveEpsilon(+duration || DEFAULT_DURATION)); + }; + }; + + // http://www.w3.org/TR/css3-transitions/#transition-timing-function + return { + /** + * @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0 + * @param duration {number} the duration of the animation in milliseconds + * @return {number} the y value along the bezier curve + */ + linear: unitBezier(0.0, 0.0, 1.0, 1.0), + + /** + * @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0 + * @param duration {number} the duration of the animation in milliseconds + * @return {number} the y value along the bezier curve + */ + ease: unitBezier(0.25, 0.1, 0.25, 1.0), + + /** + * @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0 + * @param duration {number} the duration of the animation in milliseconds + * @return {number} the y value along the bezier curve + */ + easeIn: unitBezier(0.42, 0, 1.0, 1.0), + + /** + * @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0 + * @param duration {number} the duration of the animation in milliseconds + * @return {number} the y value along the bezier curve + */ + easeOut: unitBezier(0, 0, 0.58, 1.0), + + /** + * @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0 + * @param duration {number} the duration of the animation in milliseconds + * @return {number} the y value along the bezier curve + */ + easeInOut: unitBezier(0.42, 0, 0.58, 1.0), + + /** + * @param p1x {number} X component of control point 1 + * @param p1y {number} Y component of control point 1 + * @param p2x {number} X component of control point 2 + * @param p2y {number} Y component of control point 2 + * @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0 + * @param duration {number} the duration of the animation in milliseconds + * @return {number} the y value along the bezier curve + */ + cubicBezier: function(p1x, p1y, p2x, p2y, x, duration) { + return unitBezier(p1x, p1y, p2x, p2y)(x, duration); + } + }; + })(); + +/** + * Various fast approximations and alternates to cubic-bezier easing functions. + * http://www.w3.org/TR/css3-transitions/#transition-timing-function + */ +var Easing = (function(){ + 'use strict'; + + /** + * @const + */ + var EASE_IN_OUT_CONST = 0.5 * Math.pow(0.5, 1.925); + + return { + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + linear: function(x) { + return x; + }, + +// /** +// * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 +// * @return {number} the y value along the curve +// */ +// ease: function(x) { +// // TODO: find fast approximations +// return x; +// }, + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + easeInApprox: function(x) { + // very close approximation to cubic-bezier(0.42, 0, 1.0, 1.0) + return Math.pow(x, 1.685); + }, + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + easeInQuadratic: function(x) { + return (x * x); + }, + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + easeInCubic: function(x) { + return (x * x * x); + }, + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + easeOutApprox: function(x) { + // very close approximation to cubic-bezier(0, 0, 0.58, 1.0) + return 1 - Math.pow(1-x, 1.685); + }, + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + easeOutQuadratic: function(x) { + x -= 1; + return 1 - (x * x); + }, + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + easeOutCubic: function(x) { + x -= 1; + return 1 + (x * x * x); + }, + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + easeInOutApprox: function(x) { + // very close approximation to cubic-bezier(0.42, 0, 0.58, 1.0) + if (x < 0.5) { + return EASE_IN_OUT_CONST * Math.pow(x, 1.925); + + } else { + return 1 - EASE_IN_OUT_CONST * Math.pow(1-x, 1.925); + } + }, + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + easeInOutQuadratic: function(x) { + if (x < 0.5) { + return (2 * x * x); + + } else { + x -= 1; + return 1 - (2 * x * x); + } + }, + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + easeInOutCubic: function(x) { + if (x < 0.5) { + return (4 * x * x * x); + + } else { + x -= 1; + return 1 + (4 * x * x * x); + } + }, + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + easeInOutQuartic: function(x) { + if (x < 0.5) { + return (8 * x * x * x * x); + + } else { + x -= 1; + return 1 + (8 * x * x * x * x); + } + }, + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + easeInOutQuintic: function(x) { + if (x < 0.5) { + return (16 * x * x * x * x * x); + + } else { + x -= 1; + return 1 + (16 * x * x * x * x * x); + } + } + }; +})(); +})(ionic); + +/** + * @fileoverview gl-matrix - High performance matrix and vector operations + * @author Brandon Jones + * @author Colin MacKenzie IV + * @version 2.2.1 + */ + +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + + +(function(_global) { + "use strict"; + + var shim = {}; + if (typeof(exports) === 'undefined') { + if(typeof define == 'function' && typeof define.amd == 'object' && define.amd) { + shim.exports = {}; + define(function() { + return shim.exports; + }); + } else { + // gl-matrix lives in a browser, define its namespaces in global + shim.exports = typeof(window) !== 'undefined' ? window : _global; + } + } + else { + // gl-matrix lives in commonjs, define its namespaces in exports + shim.exports = exports; + } + + (function(exports) { + /* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + + +if(!GLMAT_EPSILON) { + var GLMAT_EPSILON = 0.000001; +} + +if(!GLMAT_ARRAY_TYPE) { + var GLMAT_ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array; +} + +if(!GLMAT_RANDOM) { + var GLMAT_RANDOM = Math.random; +} + +/** + * @class Common utilities + * @name glMatrix + */ +var glMatrix = {}; + +/** + * Sets the type of array used when creating new vectors and matricies + * + * @param {Type} type Array type, such as Float32Array or Array + */ +glMatrix.setMatrixArrayType = function(type) { + GLMAT_ARRAY_TYPE = type; +} + +if(typeof(exports) !== 'undefined') { + exports.glMatrix = glMatrix; +} + +var degree = Math.PI / 180; + +/** +* Convert Degree To Radian +* +* @param {Number} Angle in Degrees +*/ +glMatrix.toRadian = function(a){ + return a * degree; +} +; +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class 2 Dimensional Vector + * @name vec2 + */ + +var vec2 = {}; + +/** + * Creates a new, empty vec2 + * + * @returns {vec2} a new 2D vector + */ +vec2.create = function() { + var out = new GLMAT_ARRAY_TYPE(2); + out[0] = 0; + out[1] = 0; + return out; +}; + +/** + * Creates a new vec2 initialized with values from an existing vector + * + * @param {vec2} a vector to clone + * @returns {vec2} a new 2D vector + */ +vec2.clone = function(a) { + var out = new GLMAT_ARRAY_TYPE(2); + out[0] = a[0]; + out[1] = a[1]; + return out; +}; + +/** + * Creates a new vec2 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @returns {vec2} a new 2D vector + */ +vec2.fromValues = function(x, y) { + var out = new GLMAT_ARRAY_TYPE(2); + out[0] = x; + out[1] = y; + return out; +}; + +/** + * Copy the values from one vec2 to another + * + * @param {vec2} out the receiving vector + * @param {vec2} a the source vector + * @returns {vec2} out + */ +vec2.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + return out; +}; + +/** + * Set the components of a vec2 to the given values + * + * @param {vec2} out the receiving vector + * @param {Number} x X component + * @param {Number} y Y component + * @returns {vec2} out + */ +vec2.set = function(out, x, y) { + out[0] = x; + out[1] = y; + return out; +}; + +/** + * Adds two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.add = function(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + return out; +}; + +/** + * Subtracts vector b from vector a + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.subtract = function(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + return out; +}; + +/** + * Alias for {@link vec2.subtract} + * @function + */ +vec2.sub = vec2.subtract; + +/** + * Multiplies two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.multiply = function(out, a, b) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + return out; +}; + +/** + * Alias for {@link vec2.multiply} + * @function + */ +vec2.mul = vec2.multiply; + +/** + * Divides two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.divide = function(out, a, b) { + out[0] = a[0] / b[0]; + out[1] = a[1] / b[1]; + return out; +}; + +/** + * Alias for {@link vec2.divide} + * @function + */ +vec2.div = vec2.divide; + +/** + * Returns the minimum of two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.min = function(out, a, b) { + out[0] = Math.min(a[0], b[0]); + out[1] = Math.min(a[1], b[1]); + return out; +}; + +/** + * Returns the maximum of two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.max = function(out, a, b) { + out[0] = Math.max(a[0], b[0]); + out[1] = Math.max(a[1], b[1]); + return out; +}; + +/** + * Scales a vec2 by a scalar number + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {vec2} out + */ +vec2.scale = function(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + return out; +}; + +/** + * Adds two vec2's after scaling the second operand by a scalar value + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @param {Number} scale the amount to scale b by before adding + * @returns {vec2} out + */ +vec2.scaleAndAdd = function(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + return out; +}; + +/** + * Calculates the euclidian distance between two vec2's + * + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {Number} distance between a and b + */ +vec2.distance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1]; + return Math.sqrt(x*x + y*y); +}; + +/** + * Alias for {@link vec2.distance} + * @function + */ +vec2.dist = vec2.distance; + +/** + * Calculates the squared euclidian distance between two vec2's + * + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {Number} squared distance between a and b + */ +vec2.squaredDistance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1]; + return x*x + y*y; +}; + +/** + * Alias for {@link vec2.squaredDistance} + * @function + */ +vec2.sqrDist = vec2.squaredDistance; + +/** + * Calculates the length of a vec2 + * + * @param {vec2} a vector to calculate length of + * @returns {Number} length of a + */ +vec2.length = function (a) { + var x = a[0], + y = a[1]; + return Math.sqrt(x*x + y*y); +}; + +/** + * Alias for {@link vec2.length} + * @function + */ +vec2.len = vec2.length; + +/** + * Calculates the squared length of a vec2 + * + * @param {vec2} a vector to calculate squared length of + * @returns {Number} squared length of a + */ +vec2.squaredLength = function (a) { + var x = a[0], + y = a[1]; + return x*x + y*y; +}; + +/** + * Alias for {@link vec2.squaredLength} + * @function + */ +vec2.sqrLen = vec2.squaredLength; + +/** + * Negates the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to negate + * @returns {vec2} out + */ +vec2.negate = function(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + return out; +}; + +/** + * Normalize a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to normalize + * @returns {vec2} out + */ +vec2.normalize = function(out, a) { + var x = a[0], + y = a[1]; + var len = x*x + y*y; + if (len > 0) { + //TODO: evaluate use of glm_invsqrt here? + len = 1 / Math.sqrt(len); + out[0] = a[0] * len; + out[1] = a[1] * len; + } + return out; +}; + +/** + * Calculates the dot product of two vec2's + * + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {Number} dot product of a and b + */ +vec2.dot = function (a, b) { + return a[0] * b[0] + a[1] * b[1]; +}; + +/** + * Computes the cross product of two vec2's + * Note that the cross product must by definition produce a 3D vector + * + * @param {vec3} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec3} out + */ +vec2.cross = function(out, a, b) { + var z = a[0] * b[1] - a[1] * b[0]; + out[0] = out[1] = 0; + out[2] = z; + return out; +}; + +/** + * Performs a linear interpolation between two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {vec2} out + */ +vec2.lerp = function (out, a, b, t) { + var ax = a[0], + ay = a[1]; + out[0] = ax + t * (b[0] - ax); + out[1] = ay + t * (b[1] - ay); + return out; +}; + +/** + * Generates a random vector with the given scale + * + * @param {vec2} out the receiving vector + * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned + * @returns {vec2} out + */ +vec2.random = function (out, scale) { + scale = scale || 1.0; + var r = GLMAT_RANDOM() * 2.0 * Math.PI; + out[0] = Math.cos(r) * scale; + out[1] = Math.sin(r) * scale; + return out; +}; + +/** + * Transforms the vec2 with a mat2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat2} m matrix to transform with + * @returns {vec2} out + */ +vec2.transformMat2 = function(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[2] * y; + out[1] = m[1] * x + m[3] * y; + return out; +}; + +/** + * Transforms the vec2 with a mat2d + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat2d} m matrix to transform with + * @returns {vec2} out + */ +vec2.transformMat2d = function(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[2] * y + m[4]; + out[1] = m[1] * x + m[3] * y + m[5]; + return out; +}; + +/** + * Transforms the vec2 with a mat3 + * 3rd vector component is implicitly '1' + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat3} m matrix to transform with + * @returns {vec2} out + */ +vec2.transformMat3 = function(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[3] * y + m[6]; + out[1] = m[1] * x + m[4] * y + m[7]; + return out; +}; + +/** + * Transforms the vec2 with a mat4 + * 3rd vector component is implicitly '0' + * 4th vector component is implicitly '1' + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat4} m matrix to transform with + * @returns {vec2} out + */ +vec2.transformMat4 = function(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[4] * y + m[12]; + out[1] = m[1] * x + m[5] * y + m[13]; + return out; +}; + +/** + * Perform some operation over an array of vec2s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ +vec2.forEach = (function() { + var vec = vec2.create(); + + return function(a, stride, offset, count, fn, arg) { + var i, l; + if(!stride) { + stride = 2; + } + + if(!offset) { + offset = 0; + } + + if(count) { + l = Math.min((count * stride) + offset, a.length); + } else { + l = a.length; + } + + for(i = offset; i < l; i += stride) { + vec[0] = a[i]; vec[1] = a[i+1]; + fn(vec, vec, arg); + a[i] = vec[0]; a[i+1] = vec[1]; + } + + return a; + }; +})(); + +/** + * Returns a string representation of a vector + * + * @param {vec2} vec vector to represent as a string + * @returns {String} string representation of the vector + */ +vec2.str = function (a) { + return 'vec2(' + a[0] + ', ' + a[1] + ')'; +}; + +if(typeof(exports) !== 'undefined') { + exports.vec2 = vec2; +} +; +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class 3 Dimensional Vector + * @name vec3 + */ + +var vec3 = {}; + +/** + * Creates a new, empty vec3 + * + * @returns {vec3} a new 3D vector + */ +vec3.create = function() { + var out = new GLMAT_ARRAY_TYPE(3); + out[0] = 0; + out[1] = 0; + out[2] = 0; + return out; +}; + +/** + * Creates a new vec3 initialized with values from an existing vector + * + * @param {vec3} a vector to clone + * @returns {vec3} a new 3D vector + */ +vec3.clone = function(a) { + var out = new GLMAT_ARRAY_TYPE(3); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + return out; +}; + +/** + * Creates a new vec3 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @returns {vec3} a new 3D vector + */ +vec3.fromValues = function(x, y, z) { + var out = new GLMAT_ARRAY_TYPE(3); + out[0] = x; + out[1] = y; + out[2] = z; + return out; +}; + +/** + * Copy the values from one vec3 to another + * + * @param {vec3} out the receiving vector + * @param {vec3} a the source vector + * @returns {vec3} out + */ +vec3.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + return out; +}; + +/** + * Set the components of a vec3 to the given values + * + * @param {vec3} out the receiving vector + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @returns {vec3} out + */ +vec3.set = function(out, x, y, z) { + out[0] = x; + out[1] = y; + out[2] = z; + return out; +}; + +/** + * Adds two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.add = function(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + return out; +}; + +/** + * Subtracts vector b from vector a + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.subtract = function(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + return out; +}; + +/** + * Alias for {@link vec3.subtract} + * @function + */ +vec3.sub = vec3.subtract; + +/** + * Multiplies two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.multiply = function(out, a, b) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + out[2] = a[2] * b[2]; + return out; +}; + +/** + * Alias for {@link vec3.multiply} + * @function + */ +vec3.mul = vec3.multiply; + +/** + * Divides two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.divide = function(out, a, b) { + out[0] = a[0] / b[0]; + out[1] = a[1] / b[1]; + out[2] = a[2] / b[2]; + return out; +}; + +/** + * Alias for {@link vec3.divide} + * @function + */ +vec3.div = vec3.divide; + +/** + * Returns the minimum of two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.min = function(out, a, b) { + out[0] = Math.min(a[0], b[0]); + out[1] = Math.min(a[1], b[1]); + out[2] = Math.min(a[2], b[2]); + return out; +}; + +/** + * Returns the maximum of two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.max = function(out, a, b) { + out[0] = Math.max(a[0], b[0]); + out[1] = Math.max(a[1], b[1]); + out[2] = Math.max(a[2], b[2]); + return out; +}; + +/** + * Scales a vec3 by a scalar number + * + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {vec3} out + */ +vec3.scale = function(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + return out; +}; + +/** + * Adds two vec3's after scaling the second operand by a scalar value + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @param {Number} scale the amount to scale b by before adding + * @returns {vec3} out + */ +vec3.scaleAndAdd = function(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + out[2] = a[2] + (b[2] * scale); + return out; +}; + +/** + * Calculates the euclidian distance between two vec3's + * + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {Number} distance between a and b + */ +vec3.distance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1], + z = b[2] - a[2]; + return Math.sqrt(x*x + y*y + z*z); +}; + +/** + * Alias for {@link vec3.distance} + * @function + */ +vec3.dist = vec3.distance; + +/** + * Calculates the squared euclidian distance between two vec3's + * + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {Number} squared distance between a and b + */ +vec3.squaredDistance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1], + z = b[2] - a[2]; + return x*x + y*y + z*z; +}; + +/** + * Alias for {@link vec3.squaredDistance} + * @function + */ +vec3.sqrDist = vec3.squaredDistance; + +/** + * Calculates the length of a vec3 + * + * @param {vec3} a vector to calculate length of + * @returns {Number} length of a + */ +vec3.length = function (a) { + var x = a[0], + y = a[1], + z = a[2]; + return Math.sqrt(x*x + y*y + z*z); +}; + +/** + * Alias for {@link vec3.length} + * @function + */ +vec3.len = vec3.length; + +/** + * Calculates the squared length of a vec3 + * + * @param {vec3} a vector to calculate squared length of + * @returns {Number} squared length of a + */ +vec3.squaredLength = function (a) { + var x = a[0], + y = a[1], + z = a[2]; + return x*x + y*y + z*z; +}; + +/** + * Alias for {@link vec3.squaredLength} + * @function + */ +vec3.sqrLen = vec3.squaredLength; + +/** + * Negates the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to negate + * @returns {vec3} out + */ +vec3.negate = function(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + return out; +}; + +/** + * Normalize a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to normalize + * @returns {vec3} out + */ +vec3.normalize = function(out, a) { + var x = a[0], + y = a[1], + z = a[2]; + var len = x*x + y*y + z*z; + if (len > 0) { + //TODO: evaluate use of glm_invsqrt here? + len = 1 / Math.sqrt(len); + out[0] = a[0] * len; + out[1] = a[1] * len; + out[2] = a[2] * len; + } + return out; +}; + +/** + * Calculates the dot product of two vec3's + * + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {Number} dot product of a and b + */ +vec3.dot = function (a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; +}; + +/** + * Computes the cross product of two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.cross = function(out, a, b) { + var ax = a[0], ay = a[1], az = a[2], + bx = b[0], by = b[1], bz = b[2]; + + out[0] = ay * bz - az * by; + out[1] = az * bx - ax * bz; + out[2] = ax * by - ay * bx; + return out; +}; + +/** + * Performs a linear interpolation between two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {vec3} out + */ +vec3.lerp = function (out, a, b, t) { + var ax = a[0], + ay = a[1], + az = a[2]; + out[0] = ax + t * (b[0] - ax); + out[1] = ay + t * (b[1] - ay); + out[2] = az + t * (b[2] - az); + return out; +}; + +/** + * Generates a random vector with the given scale + * + * @param {vec3} out the receiving vector + * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned + * @returns {vec3} out + */ +vec3.random = function (out, scale) { + scale = scale || 1.0; + + var r = GLMAT_RANDOM() * 2.0 * Math.PI; + var z = (GLMAT_RANDOM() * 2.0) - 1.0; + var zScale = Math.sqrt(1.0-z*z) * scale; + + out[0] = Math.cos(r) * zScale; + out[1] = Math.sin(r) * zScale; + out[2] = z * scale; + return out; +}; + +/** + * Transforms the vec3 with a mat4. + * 4th vector component is implicitly '1' + * + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to transform + * @param {mat4} m matrix to transform with + * @returns {vec3} out + */ +vec3.transformMat4 = function(out, a, m) { + var x = a[0], y = a[1], z = a[2]; + out[0] = m[0] * x + m[4] * y + m[8] * z + m[12]; + out[1] = m[1] * x + m[5] * y + m[9] * z + m[13]; + out[2] = m[2] * x + m[6] * y + m[10] * z + m[14]; + return out; +}; + +/** + * Transforms the vec3 with a mat3. + * + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to transform + * @param {mat4} m the 3x3 matrix to transform with + * @returns {vec3} out + */ +vec3.transformMat3 = function(out, a, m) { + var x = a[0], y = a[1], z = a[2]; + out[0] = x * m[0] + y * m[3] + z * m[6]; + out[1] = x * m[1] + y * m[4] + z * m[7]; + out[2] = x * m[2] + y * m[5] + z * m[8]; + return out; +}; + +/** + * Transforms the vec3 with a quat + * + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to transform + * @param {quat} q quaternion to transform with + * @returns {vec3} out + */ +vec3.transformQuat = function(out, a, q) { + // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations + + var x = a[0], y = a[1], z = a[2], + qx = q[0], qy = q[1], qz = q[2], qw = q[3], + + // calculate quat * vec + ix = qw * x + qy * z - qz * y, + iy = qw * y + qz * x - qx * z, + iz = qw * z + qx * y - qy * x, + iw = -qx * x - qy * y - qz * z; + + // calculate result * inverse quat + out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; + out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; + out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; + return out; +}; + +/* +* Rotate a 3D vector around the x-axis +* @param {vec3} out The receiving vec3 +* @param {vec3} a The vec3 point to rotate +* @param {vec3} b The origin of the rotation +* @param {Number} c The angle of rotation +* @returns {vec3} out +*/ +vec3.rotateX = function(out, a, b, c){ + var p = [], r=[]; + //Translate point to the origin + p[0] = a[0] - b[0]; + p[1] = a[1] - b[1]; + p[2] = a[2] - b[2]; + + //perform rotation + r[0] = p[0]; + r[1] = p[1]*Math.cos(c) - p[2]*Math.sin(c); + r[2] = p[1]*Math.sin(c) + p[2]*Math.cos(c); + + //translate to correct position + out[0] = r[0] + b[0]; + out[1] = r[1] + b[1]; + out[2] = r[2] + b[2]; + + return out; +}; + +/* +* Rotate a 3D vector around the y-axis +* @param {vec3} out The receiving vec3 +* @param {vec3} a The vec3 point to rotate +* @param {vec3} b The origin of the rotation +* @param {Number} c The angle of rotation +* @returns {vec3} out +*/ +vec3.rotateY = function(out, a, b, c){ + var p = [], r=[]; + //Translate point to the origin + p[0] = a[0] - b[0]; + p[1] = a[1] - b[1]; + p[2] = a[2] - b[2]; + + //perform rotation + r[0] = p[2]*Math.sin(c) + p[0]*Math.cos(c); + r[1] = p[1]; + r[2] = p[2]*Math.cos(c) - p[0]*Math.sin(c); + + //translate to correct position + out[0] = r[0] + b[0]; + out[1] = r[1] + b[1]; + out[2] = r[2] + b[2]; + + return out; +}; + +/* +* Rotate a 3D vector around the z-axis +* @param {vec3} out The receiving vec3 +* @param {vec3} a The vec3 point to rotate +* @param {vec3} b The origin of the rotation +* @param {Number} c The angle of rotation +* @returns {vec3} out +*/ +vec3.rotateZ = function(out, a, b, c){ + var p = [], r=[]; + //Translate point to the origin + p[0] = a[0] - b[0]; + p[1] = a[1] - b[1]; + p[2] = a[2] - b[2]; + + //perform rotation + r[0] = p[0]*Math.cos(c) - p[1]*Math.sin(c); + r[1] = p[0]*Math.sin(c) + p[1]*Math.cos(c); + r[2] = p[2]; + + //translate to correct position + out[0] = r[0] + b[0]; + out[1] = r[1] + b[1]; + out[2] = r[2] + b[2]; + + return out; +}; + +/** + * Perform some operation over an array of vec3s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ +vec3.forEach = (function() { + var vec = vec3.create(); + + return function(a, stride, offset, count, fn, arg) { + var i, l; + if(!stride) { + stride = 3; + } + + if(!offset) { + offset = 0; + } + + if(count) { + l = Math.min((count * stride) + offset, a.length); + } else { + l = a.length; + } + + for(i = offset; i < l; i += stride) { + vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; + fn(vec, vec, arg); + a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; + } + + return a; + }; +})(); + +/** + * Returns a string representation of a vector + * + * @param {vec3} vec vector to represent as a string + * @returns {String} string representation of the vector + */ +vec3.str = function (a) { + return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')'; +}; + +if(typeof(exports) !== 'undefined') { + exports.vec3 = vec3; +} +; +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class 4 Dimensional Vector + * @name vec4 + */ + +var vec4 = {}; + +/** + * Creates a new, empty vec4 + * + * @returns {vec4} a new 4D vector + */ +vec4.create = function() { + var out = new GLMAT_ARRAY_TYPE(4); + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 0; + return out; +}; + +/** + * Creates a new vec4 initialized with values from an existing vector + * + * @param {vec4} a vector to clone + * @returns {vec4} a new 4D vector + */ +vec4.clone = function(a) { + var out = new GLMAT_ARRAY_TYPE(4); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +}; + +/** + * Creates a new vec4 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {vec4} a new 4D vector + */ +vec4.fromValues = function(x, y, z, w) { + var out = new GLMAT_ARRAY_TYPE(4); + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = w; + return out; +}; + +/** + * Copy the values from one vec4 to another + * + * @param {vec4} out the receiving vector + * @param {vec4} a the source vector + * @returns {vec4} out + */ +vec4.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +}; + +/** + * Set the components of a vec4 to the given values + * + * @param {vec4} out the receiving vector + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {vec4} out + */ +vec4.set = function(out, x, y, z, w) { + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = w; + return out; +}; + +/** + * Adds two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.add = function(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + return out; +}; + +/** + * Subtracts vector b from vector a + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.subtract = function(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + return out; +}; + +/** + * Alias for {@link vec4.subtract} + * @function + */ +vec4.sub = vec4.subtract; + +/** + * Multiplies two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.multiply = function(out, a, b) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + out[2] = a[2] * b[2]; + out[3] = a[3] * b[3]; + return out; +}; + +/** + * Alias for {@link vec4.multiply} + * @function + */ +vec4.mul = vec4.multiply; + +/** + * Divides two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.divide = function(out, a, b) { + out[0] = a[0] / b[0]; + out[1] = a[1] / b[1]; + out[2] = a[2] / b[2]; + out[3] = a[3] / b[3]; + return out; +}; + +/** + * Alias for {@link vec4.divide} + * @function + */ +vec4.div = vec4.divide; + +/** + * Returns the minimum of two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.min = function(out, a, b) { + out[0] = Math.min(a[0], b[0]); + out[1] = Math.min(a[1], b[1]); + out[2] = Math.min(a[2], b[2]); + out[3] = Math.min(a[3], b[3]); + return out; +}; + +/** + * Returns the maximum of two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.max = function(out, a, b) { + out[0] = Math.max(a[0], b[0]); + out[1] = Math.max(a[1], b[1]); + out[2] = Math.max(a[2], b[2]); + out[3] = Math.max(a[3], b[3]); + return out; +}; + +/** + * Scales a vec4 by a scalar number + * + * @param {vec4} out the receiving vector + * @param {vec4} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {vec4} out + */ +vec4.scale = function(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + return out; +}; + +/** + * Adds two vec4's after scaling the second operand by a scalar value + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @param {Number} scale the amount to scale b by before adding + * @returns {vec4} out + */ +vec4.scaleAndAdd = function(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + out[2] = a[2] + (b[2] * scale); + out[3] = a[3] + (b[3] * scale); + return out; +}; + +/** + * Calculates the euclidian distance between two vec4's + * + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {Number} distance between a and b + */ +vec4.distance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1], + z = b[2] - a[2], + w = b[3] - a[3]; + return Math.sqrt(x*x + y*y + z*z + w*w); +}; + +/** + * Alias for {@link vec4.distance} + * @function + */ +vec4.dist = vec4.distance; + +/** + * Calculates the squared euclidian distance between two vec4's + * + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {Number} squared distance between a and b + */ +vec4.squaredDistance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1], + z = b[2] - a[2], + w = b[3] - a[3]; + return x*x + y*y + z*z + w*w; +}; + +/** + * Alias for {@link vec4.squaredDistance} + * @function + */ +vec4.sqrDist = vec4.squaredDistance; + +/** + * Calculates the length of a vec4 + * + * @param {vec4} a vector to calculate length of + * @returns {Number} length of a + */ +vec4.length = function (a) { + var x = a[0], + y = a[1], + z = a[2], + w = a[3]; + return Math.sqrt(x*x + y*y + z*z + w*w); +}; + +/** + * Alias for {@link vec4.length} + * @function + */ +vec4.len = vec4.length; + +/** + * Calculates the squared length of a vec4 + * + * @param {vec4} a vector to calculate squared length of + * @returns {Number} squared length of a + */ +vec4.squaredLength = function (a) { + var x = a[0], + y = a[1], + z = a[2], + w = a[3]; + return x*x + y*y + z*z + w*w; +}; + +/** + * Alias for {@link vec4.squaredLength} + * @function + */ +vec4.sqrLen = vec4.squaredLength; + +/** + * Negates the components of a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to negate + * @returns {vec4} out + */ +vec4.negate = function(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = -a[3]; + return out; +}; + +/** + * Normalize a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to normalize + * @returns {vec4} out + */ +vec4.normalize = function(out, a) { + var x = a[0], + y = a[1], + z = a[2], + w = a[3]; + var len = x*x + y*y + z*z + w*w; + if (len > 0) { + len = 1 / Math.sqrt(len); + out[0] = a[0] * len; + out[1] = a[1] * len; + out[2] = a[2] * len; + out[3] = a[3] * len; + } + return out; +}; + +/** + * Calculates the dot product of two vec4's + * + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {Number} dot product of a and b + */ +vec4.dot = function (a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; +}; + +/** + * Performs a linear interpolation between two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {vec4} out + */ +vec4.lerp = function (out, a, b, t) { + var ax = a[0], + ay = a[1], + az = a[2], + aw = a[3]; + out[0] = ax + t * (b[0] - ax); + out[1] = ay + t * (b[1] - ay); + out[2] = az + t * (b[2] - az); + out[3] = aw + t * (b[3] - aw); + return out; +}; + +/** + * Generates a random vector with the given scale + * + * @param {vec4} out the receiving vector + * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned + * @returns {vec4} out + */ +vec4.random = function (out, scale) { + scale = scale || 1.0; + + //TODO: This is a pretty awful way of doing this. Find something better. + out[0] = GLMAT_RANDOM(); + out[1] = GLMAT_RANDOM(); + out[2] = GLMAT_RANDOM(); + out[3] = GLMAT_RANDOM(); + vec4.normalize(out, out); + vec4.scale(out, out, scale); + return out; +}; + +/** + * Transforms the vec4 with a mat4. + * + * @param {vec4} out the receiving vector + * @param {vec4} a the vector to transform + * @param {mat4} m matrix to transform with + * @returns {vec4} out + */ +vec4.transformMat4 = function(out, a, m) { + var x = a[0], y = a[1], z = a[2], w = a[3]; + out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w; + out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w; + out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w; + out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w; + return out; +}; + +/** + * Transforms the vec4 with a quat + * + * @param {vec4} out the receiving vector + * @param {vec4} a the vector to transform + * @param {quat} q quaternion to transform with + * @returns {vec4} out + */ +vec4.transformQuat = function(out, a, q) { + var x = a[0], y = a[1], z = a[2], + qx = q[0], qy = q[1], qz = q[2], qw = q[3], + + // calculate quat * vec + ix = qw * x + qy * z - qz * y, + iy = qw * y + qz * x - qx * z, + iz = qw * z + qx * y - qy * x, + iw = -qx * x - qy * y - qz * z; + + // calculate result * inverse quat + out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; + out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; + out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; + return out; +}; + +/** + * Perform some operation over an array of vec4s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ +vec4.forEach = (function() { + var vec = vec4.create(); + + return function(a, stride, offset, count, fn, arg) { + var i, l; + if(!stride) { + stride = 4; + } + + if(!offset) { + offset = 0; + } + + if(count) { + l = Math.min((count * stride) + offset, a.length); + } else { + l = a.length; + } + + for(i = offset; i < l; i += stride) { + vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3]; + fn(vec, vec, arg); + a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3]; + } + + return a; + }; +})(); + +/** + * Returns a string representation of a vector + * + * @param {vec4} vec vector to represent as a string + * @returns {String} string representation of the vector + */ +vec4.str = function (a) { + return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; +}; + +if(typeof(exports) !== 'undefined') { + exports.vec4 = vec4; +} +; +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class 2x2 Matrix + * @name mat2 + */ + +var mat2 = {}; + +/** + * Creates a new identity mat2 + * + * @returns {mat2} a new 2x2 matrix + */ +mat2.create = function() { + var out = new GLMAT_ARRAY_TYPE(4); + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; +}; + +/** + * Creates a new mat2 initialized with values from an existing matrix + * + * @param {mat2} a matrix to clone + * @returns {mat2} a new 2x2 matrix + */ +mat2.clone = function(a) { + var out = new GLMAT_ARRAY_TYPE(4); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +}; + +/** + * Copy the values from one mat2 to another + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ +mat2.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +}; + +/** + * Set a mat2 to the identity matrix + * + * @param {mat2} out the receiving matrix + * @returns {mat2} out + */ +mat2.identity = function(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; +}; + +/** + * Transpose the values of a mat2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ +mat2.transpose = function(out, a) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (out === a) { + var a1 = a[1]; + out[1] = a[2]; + out[2] = a1; + } else { + out[0] = a[0]; + out[1] = a[2]; + out[2] = a[1]; + out[3] = a[3]; + } + + return out; +}; + +/** + * Inverts a mat2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ +mat2.invert = function(out, a) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], + + // Calculate the determinant + det = a0 * a3 - a2 * a1; + + if (!det) { + return null; + } + det = 1.0 / det; + + out[0] = a3 * det; + out[1] = -a1 * det; + out[2] = -a2 * det; + out[3] = a0 * det; + + return out; +}; + +/** + * Calculates the adjugate of a mat2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ +mat2.adjoint = function(out, a) { + // Caching this value is nessecary if out == a + var a0 = a[0]; + out[0] = a[3]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = a0; + + return out; +}; + +/** + * Calculates the determinant of a mat2 + * + * @param {mat2} a the source matrix + * @returns {Number} determinant of a + */ +mat2.determinant = function (a) { + return a[0] * a[3] - a[2] * a[1]; +}; + +/** + * Multiplies two mat2's + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the first operand + * @param {mat2} b the second operand + * @returns {mat2} out + */ +mat2.multiply = function (out, a, b) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; + var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; + out[0] = a0 * b0 + a2 * b1; + out[1] = a1 * b0 + a3 * b1; + out[2] = a0 * b2 + a2 * b3; + out[3] = a1 * b2 + a3 * b3; + return out; +}; + +/** + * Alias for {@link mat2.multiply} + * @function + */ +mat2.mul = mat2.multiply; + +/** + * Rotates a mat2 by the given angle + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat2} out + */ +mat2.rotate = function (out, a, rad) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], + s = Math.sin(rad), + c = Math.cos(rad); + out[0] = a0 * c + a2 * s; + out[1] = a1 * c + a3 * s; + out[2] = a0 * -s + a2 * c; + out[3] = a1 * -s + a3 * c; + return out; +}; + +/** + * Scales the mat2 by the dimensions in the given vec2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the matrix to rotate + * @param {vec2} v the vec2 to scale the matrix by + * @returns {mat2} out + **/ +mat2.scale = function(out, a, v) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], + v0 = v[0], v1 = v[1]; + out[0] = a0 * v0; + out[1] = a1 * v0; + out[2] = a2 * v1; + out[3] = a3 * v1; + return out; +}; + +/** + * Returns a string representation of a mat2 + * + * @param {mat2} mat matrix to represent as a string + * @returns {String} string representation of the matrix + */ +mat2.str = function (a) { + return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; +}; + +/** + * Returns Frobenius norm of a mat2 + * + * @param {mat2} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ +mat2.frob = function (a) { + return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2))) +}; + +/** + * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix + * @param {mat2} L the lower triangular matrix + * @param {mat2} D the diagonal matrix + * @param {mat2} U the upper triangular matrix + * @param {mat2} a the input matrix to factorize + */ + +mat2.LDU = function (L, D, U, a) { + L[2] = a[2]/a[0]; + U[0] = a[0]; + U[1] = a[1]; + U[3] = a[3] - L[2] * U[1]; + return [L, D, U]; +}; + +if(typeof(exports) !== 'undefined') { + exports.mat2 = mat2; +} +; +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class 2x3 Matrix + * @name mat2d + * + * @description + * A mat2d contains six elements defined as: + *
+ * [a, c, tx,
+ *  b, d, ty]
+ * 
+ * This is a short form for the 3x3 matrix: + *
+ * [a, c, tx,
+ *  b, d, ty,
+ *  0, 0, 1]
+ * 
+ * The last row is ignored so the array is shorter and operations are faster. + */ + +var mat2d = {}; + +/** + * Creates a new identity mat2d + * + * @returns {mat2d} a new 2x3 matrix + */ +mat2d.create = function() { + var out = new GLMAT_ARRAY_TYPE(6); + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = 0; + out[5] = 0; + return out; +}; + +/** + * Creates a new mat2d initialized with values from an existing matrix + * + * @param {mat2d} a matrix to clone + * @returns {mat2d} a new 2x3 matrix + */ +mat2d.clone = function(a) { + var out = new GLMAT_ARRAY_TYPE(6); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + return out; +}; + +/** + * Copy the values from one mat2d to another + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the source matrix + * @returns {mat2d} out + */ +mat2d.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + return out; +}; + +/** + * Set a mat2d to the identity matrix + * + * @param {mat2d} out the receiving matrix + * @returns {mat2d} out + */ +mat2d.identity = function(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = 0; + out[5] = 0; + return out; +}; + +/** + * Inverts a mat2d + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the source matrix + * @returns {mat2d} out + */ +mat2d.invert = function(out, a) { + var aa = a[0], ab = a[1], ac = a[2], ad = a[3], + atx = a[4], aty = a[5]; + + var det = aa * ad - ab * ac; + if(!det){ + return null; + } + det = 1.0 / det; + + out[0] = ad * det; + out[1] = -ab * det; + out[2] = -ac * det; + out[3] = aa * det; + out[4] = (ac * aty - ad * atx) * det; + out[5] = (ab * atx - aa * aty) * det; + return out; +}; + +/** + * Calculates the determinant of a mat2d + * + * @param {mat2d} a the source matrix + * @returns {Number} determinant of a + */ +mat2d.determinant = function (a) { + return a[0] * a[3] - a[1] * a[2]; +}; + +/** + * Multiplies two mat2d's + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the first operand + * @param {mat2d} b the second operand + * @returns {mat2d} out + */ +mat2d.multiply = function (out, a, b) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], + b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5]; + out[0] = a0 * b0 + a2 * b1; + out[1] = a1 * b0 + a3 * b1; + out[2] = a0 * b2 + a2 * b3; + out[3] = a1 * b2 + a3 * b3; + out[4] = a0 * b4 + a2 * b5 + a4; + out[5] = a1 * b4 + a3 * b5 + a5; + return out; +}; + +/** + * Alias for {@link mat2d.multiply} + * @function + */ +mat2d.mul = mat2d.multiply; + + +/** + * Rotates a mat2d by the given angle + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat2d} out + */ +mat2d.rotate = function (out, a, rad) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], + s = Math.sin(rad), + c = Math.cos(rad); + out[0] = a0 * c + a2 * s; + out[1] = a1 * c + a3 * s; + out[2] = a0 * -s + a2 * c; + out[3] = a1 * -s + a3 * c; + out[4] = a4; + out[5] = a5; + return out; +}; + +/** + * Scales the mat2d by the dimensions in the given vec2 + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the matrix to translate + * @param {vec2} v the vec2 to scale the matrix by + * @returns {mat2d} out + **/ +mat2d.scale = function(out, a, v) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], + v0 = v[0], v1 = v[1]; + out[0] = a0 * v0; + out[1] = a1 * v0; + out[2] = a2 * v1; + out[3] = a3 * v1; + out[4] = a4; + out[5] = a5; + return out; +}; + +/** + * Translates the mat2d by the dimensions in the given vec2 + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the matrix to translate + * @param {vec2} v the vec2 to translate the matrix by + * @returns {mat2d} out + **/ +mat2d.translate = function(out, a, v) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], + v0 = v[0], v1 = v[1]; + out[0] = a0; + out[1] = a1; + out[2] = a2; + out[3] = a3; + out[4] = a0 * v0 + a2 * v1 + a4; + out[5] = a1 * v0 + a3 * v1 + a5; + return out; +}; + +/** + * Returns a string representation of a mat2d + * + * @param {mat2d} a matrix to represent as a string + * @returns {String} string representation of the matrix + */ +mat2d.str = function (a) { + return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + + a[3] + ', ' + a[4] + ', ' + a[5] + ')'; +}; + +/** + * Returns Frobenius norm of a mat2d + * + * @param {mat2d} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ +mat2d.frob = function (a) { + return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + 1)) +}; + +if(typeof(exports) !== 'undefined') { + exports.mat2d = mat2d; +} +; +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class 3x3 Matrix + * @name mat3 + */ + +var mat3 = {}; + +/** + * Creates a new identity mat3 + * + * @returns {mat3} a new 3x3 matrix + */ +mat3.create = function() { + var out = new GLMAT_ARRAY_TYPE(9); + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 1; + out[5] = 0; + out[6] = 0; + out[7] = 0; + out[8] = 1; + return out; +}; + +/** + * Copies the upper-left 3x3 values into the given mat3. + * + * @param {mat3} out the receiving 3x3 matrix + * @param {mat4} a the source 4x4 matrix + * @returns {mat3} out + */ +mat3.fromMat4 = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[4]; + out[4] = a[5]; + out[5] = a[6]; + out[6] = a[8]; + out[7] = a[9]; + out[8] = a[10]; + return out; +}; + +/** + * Creates a new mat3 initialized with values from an existing matrix + * + * @param {mat3} a matrix to clone + * @returns {mat3} a new 3x3 matrix + */ +mat3.clone = function(a) { + var out = new GLMAT_ARRAY_TYPE(9); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + return out; +}; + +/** + * Copy the values from one mat3 to another + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out + */ +mat3.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + return out; +}; + +/** + * Set a mat3 to the identity matrix + * + * @param {mat3} out the receiving matrix + * @returns {mat3} out + */ +mat3.identity = function(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 1; + out[5] = 0; + out[6] = 0; + out[7] = 0; + out[8] = 1; + return out; +}; + +/** + * Transpose the values of a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out + */ +mat3.transpose = function(out, a) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (out === a) { + var a01 = a[1], a02 = a[2], a12 = a[5]; + out[1] = a[3]; + out[2] = a[6]; + out[3] = a01; + out[5] = a[7]; + out[6] = a02; + out[7] = a12; + } else { + out[0] = a[0]; + out[1] = a[3]; + out[2] = a[6]; + out[3] = a[1]; + out[4] = a[4]; + out[5] = a[7]; + out[6] = a[2]; + out[7] = a[5]; + out[8] = a[8]; + } + + return out; +}; + +/** + * Inverts a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out + */ +mat3.invert = function(out, a) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8], + + b01 = a22 * a11 - a12 * a21, + b11 = -a22 * a10 + a12 * a20, + b21 = a21 * a10 - a11 * a20, + + // Calculate the determinant + det = a00 * b01 + a01 * b11 + a02 * b21; + + if (!det) { + return null; + } + det = 1.0 / det; + + out[0] = b01 * det; + out[1] = (-a22 * a01 + a02 * a21) * det; + out[2] = (a12 * a01 - a02 * a11) * det; + out[3] = b11 * det; + out[4] = (a22 * a00 - a02 * a20) * det; + out[5] = (-a12 * a00 + a02 * a10) * det; + out[6] = b21 * det; + out[7] = (-a21 * a00 + a01 * a20) * det; + out[8] = (a11 * a00 - a01 * a10) * det; + return out; +}; + +/** + * Calculates the adjugate of a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out + */ +mat3.adjoint = function(out, a) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8]; + + out[0] = (a11 * a22 - a12 * a21); + out[1] = (a02 * a21 - a01 * a22); + out[2] = (a01 * a12 - a02 * a11); + out[3] = (a12 * a20 - a10 * a22); + out[4] = (a00 * a22 - a02 * a20); + out[5] = (a02 * a10 - a00 * a12); + out[6] = (a10 * a21 - a11 * a20); + out[7] = (a01 * a20 - a00 * a21); + out[8] = (a00 * a11 - a01 * a10); + return out; +}; + +/** + * Calculates the determinant of a mat3 + * + * @param {mat3} a the source matrix + * @returns {Number} determinant of a + */ +mat3.determinant = function (a) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8]; + + return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20); +}; + +/** + * Multiplies two mat3's + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the first operand + * @param {mat3} b the second operand + * @returns {mat3} out + */ +mat3.multiply = function (out, a, b) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8], + + b00 = b[0], b01 = b[1], b02 = b[2], + b10 = b[3], b11 = b[4], b12 = b[5], + b20 = b[6], b21 = b[7], b22 = b[8]; + + out[0] = b00 * a00 + b01 * a10 + b02 * a20; + out[1] = b00 * a01 + b01 * a11 + b02 * a21; + out[2] = b00 * a02 + b01 * a12 + b02 * a22; + + out[3] = b10 * a00 + b11 * a10 + b12 * a20; + out[4] = b10 * a01 + b11 * a11 + b12 * a21; + out[5] = b10 * a02 + b11 * a12 + b12 * a22; + + out[6] = b20 * a00 + b21 * a10 + b22 * a20; + out[7] = b20 * a01 + b21 * a11 + b22 * a21; + out[8] = b20 * a02 + b21 * a12 + b22 * a22; + return out; +}; + +/** + * Alias for {@link mat3.multiply} + * @function + */ +mat3.mul = mat3.multiply; + +/** + * Translate a mat3 by the given vector + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the matrix to translate + * @param {vec2} v vector to translate by + * @returns {mat3} out + */ +mat3.translate = function(out, a, v) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8], + x = v[0], y = v[1]; + + out[0] = a00; + out[1] = a01; + out[2] = a02; + + out[3] = a10; + out[4] = a11; + out[5] = a12; + + out[6] = x * a00 + y * a10 + a20; + out[7] = x * a01 + y * a11 + a21; + out[8] = x * a02 + y * a12 + a22; + return out; +}; + +/** + * Rotates a mat3 by the given angle + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat3} out + */ +mat3.rotate = function (out, a, rad) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8], + + s = Math.sin(rad), + c = Math.cos(rad); + + out[0] = c * a00 + s * a10; + out[1] = c * a01 + s * a11; + out[2] = c * a02 + s * a12; + + out[3] = c * a10 - s * a00; + out[4] = c * a11 - s * a01; + out[5] = c * a12 - s * a02; + + out[6] = a20; + out[7] = a21; + out[8] = a22; + return out; +}; + +/** + * Scales the mat3 by the dimensions in the given vec2 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the matrix to rotate + * @param {vec2} v the vec2 to scale the matrix by + * @returns {mat3} out + **/ +mat3.scale = function(out, a, v) { + var x = v[0], y = v[1]; + + out[0] = x * a[0]; + out[1] = x * a[1]; + out[2] = x * a[2]; + + out[3] = y * a[3]; + out[4] = y * a[4]; + out[5] = y * a[5]; + + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + return out; +}; + +/** + * Copies the values from a mat2d into a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat2d} a the matrix to copy + * @returns {mat3} out + **/ +mat3.fromMat2d = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = 0; + + out[3] = a[2]; + out[4] = a[3]; + out[5] = 0; + + out[6] = a[4]; + out[7] = a[5]; + out[8] = 1; + return out; +}; + +/** +* Calculates a 3x3 matrix from the given quaternion +* +* @param {mat3} out mat3 receiving operation result +* @param {quat} q Quaternion to create matrix from +* +* @returns {mat3} out +*/ +mat3.fromQuat = function (out, q) { + var x = q[0], y = q[1], z = q[2], w = q[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, + + xx = x * x2, + yx = y * x2, + yy = y * y2, + zx = z * x2, + zy = z * y2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; + + out[0] = 1 - yy - zz; + out[3] = yx - wz; + out[6] = zx + wy; + + out[1] = yx + wz; + out[4] = 1 - xx - zz; + out[7] = zy - wx; + + out[2] = zx - wy; + out[5] = zy + wx; + out[8] = 1 - xx - yy; + + return out; +}; + +/** +* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix +* +* @param {mat3} out mat3 receiving operation result +* @param {mat4} a Mat4 to derive the normal matrix from +* +* @returns {mat3} out +*/ +mat3.normalFromMat4 = function (out, a) { + var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], + + b00 = a00 * a11 - a01 * a10, + b01 = a00 * a12 - a02 * a10, + b02 = a00 * a13 - a03 * a10, + b03 = a01 * a12 - a02 * a11, + b04 = a01 * a13 - a03 * a11, + b05 = a02 * a13 - a03 * a12, + b06 = a20 * a31 - a21 * a30, + b07 = a20 * a32 - a22 * a30, + b08 = a20 * a33 - a23 * a30, + b09 = a21 * a32 - a22 * a31, + b10 = a21 * a33 - a23 * a31, + b11 = a22 * a33 - a23 * a32, + + // Calculate the determinant + det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; + + if (!det) { + return null; + } + det = 1.0 / det; + + out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; + out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det; + out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det; + + out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det; + out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det; + out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det; + + out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det; + out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det; + out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det; + + return out; +}; + +/** + * Returns a string representation of a mat3 + * + * @param {mat3} mat matrix to represent as a string + * @returns {String} string representation of the matrix + */ +mat3.str = function (a) { + return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + + a[6] + ', ' + a[7] + ', ' + a[8] + ')'; +}; + +/** + * Returns Frobenius norm of a mat3 + * + * @param {mat3} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ +mat3.frob = function (a) { + return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2))) +}; + + +if(typeof(exports) !== 'undefined') { + exports.mat3 = mat3; +} +; +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class 4x4 Matrix + * @name mat4 + */ + +var mat4 = {}; + +/** + * Creates a new identity mat4 + * + * @returns {mat4} a new 4x4 matrix + */ +mat4.create = function() { + var out = new GLMAT_ARRAY_TYPE(16); + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; +}; + +/** + * Creates a new mat4 initialized with values from an existing matrix + * + * @param {mat4} a matrix to clone + * @returns {mat4} a new 4x4 matrix + */ +mat4.clone = function(a) { + var out = new GLMAT_ARRAY_TYPE(16); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; +}; + +/** + * Copy the values from one mat4 to another + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +mat4.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; +}; + +/** + * Set a mat4 to the identity matrix + * + * @param {mat4} out the receiving matrix + * @returns {mat4} out + */ +mat4.identity = function(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; +}; + +/** + * Transpose the values of a mat4 + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +mat4.transpose = function(out, a) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (out === a) { + var a01 = a[1], a02 = a[2], a03 = a[3], + a12 = a[6], a13 = a[7], + a23 = a[11]; + + out[1] = a[4]; + out[2] = a[8]; + out[3] = a[12]; + out[4] = a01; + out[6] = a[9]; + out[7] = a[13]; + out[8] = a02; + out[9] = a12; + out[11] = a[14]; + out[12] = a03; + out[13] = a13; + out[14] = a23; + } else { + out[0] = a[0]; + out[1] = a[4]; + out[2] = a[8]; + out[3] = a[12]; + out[4] = a[1]; + out[5] = a[5]; + out[6] = a[9]; + out[7] = a[13]; + out[8] = a[2]; + out[9] = a[6]; + out[10] = a[10]; + out[11] = a[14]; + out[12] = a[3]; + out[13] = a[7]; + out[14] = a[11]; + out[15] = a[15]; + } + + return out; +}; + +/** + * Inverts a mat4 + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +mat4.invert = function(out, a) { + var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], + + b00 = a00 * a11 - a01 * a10, + b01 = a00 * a12 - a02 * a10, + b02 = a00 * a13 - a03 * a10, + b03 = a01 * a12 - a02 * a11, + b04 = a01 * a13 - a03 * a11, + b05 = a02 * a13 - a03 * a12, + b06 = a20 * a31 - a21 * a30, + b07 = a20 * a32 - a22 * a30, + b08 = a20 * a33 - a23 * a30, + b09 = a21 * a32 - a22 * a31, + b10 = a21 * a33 - a23 * a31, + b11 = a22 * a33 - a23 * a32, + + // Calculate the determinant + det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; + + if (!det) { + return null; + } + det = 1.0 / det; + + out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; + out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; + out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; + out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; + out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; + out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; + out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; + out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; + out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; + out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; + out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; + out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; + out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; + out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; + out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; + out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; + + return out; +}; + +/** + * Calculates the adjugate of a mat4 + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +mat4.adjoint = function(out, a) { + var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; + + out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22)); + out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22)); + out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12)); + out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12)); + out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22)); + out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22)); + out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12)); + out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12)); + out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21)); + out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21)); + out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11)); + out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11)); + out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21)); + out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21)); + out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11)); + out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11)); + return out; +}; + +/** + * Calculates the determinant of a mat4 + * + * @param {mat4} a the source matrix + * @returns {Number} determinant of a + */ +mat4.determinant = function (a) { + var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], + + b00 = a00 * a11 - a01 * a10, + b01 = a00 * a12 - a02 * a10, + b02 = a00 * a13 - a03 * a10, + b03 = a01 * a12 - a02 * a11, + b04 = a01 * a13 - a03 * a11, + b05 = a02 * a13 - a03 * a12, + b06 = a20 * a31 - a21 * a30, + b07 = a20 * a32 - a22 * a30, + b08 = a20 * a33 - a23 * a30, + b09 = a21 * a32 - a22 * a31, + b10 = a21 * a33 - a23 * a31, + b11 = a22 * a33 - a23 * a32; + + // Calculate the determinant + return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; +}; + +/** + * Multiplies two mat4's + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the first operand + * @param {mat4} b the second operand + * @returns {mat4} out + */ +mat4.multiply = function (out, a, b) { + var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; + + // Cache only the current line of the second matrix + var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; + out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; + out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; + out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; + out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + return out; +}; + +/** + * Alias for {@link mat4.multiply} + * @function + */ +mat4.mul = mat4.multiply; + +/** + * Translate a mat4 by the given vector + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to translate + * @param {vec3} v vector to translate by + * @returns {mat4} out + */ +mat4.translate = function (out, a, v) { + var x = v[0], y = v[1], z = v[2], + a00, a01, a02, a03, + a10, a11, a12, a13, + a20, a21, a22, a23; + + if (a === out) { + out[12] = a[0] * x + a[4] * y + a[8] * z + a[12]; + out[13] = a[1] * x + a[5] * y + a[9] * z + a[13]; + out[14] = a[2] * x + a[6] * y + a[10] * z + a[14]; + out[15] = a[3] * x + a[7] * y + a[11] * z + a[15]; + } else { + a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; + a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; + a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; + + out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03; + out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13; + out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23; + + out[12] = a00 * x + a10 * y + a20 * z + a[12]; + out[13] = a01 * x + a11 * y + a21 * z + a[13]; + out[14] = a02 * x + a12 * y + a22 * z + a[14]; + out[15] = a03 * x + a13 * y + a23 * z + a[15]; + } + + return out; +}; + +/** + * Scales the mat4 by the dimensions in the given vec3 + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to scale + * @param {vec3} v the vec3 to scale the matrix by + * @returns {mat4} out + **/ +mat4.scale = function(out, a, v) { + var x = v[0], y = v[1], z = v[2]; + + out[0] = a[0] * x; + out[1] = a[1] * x; + out[2] = a[2] * x; + out[3] = a[3] * x; + out[4] = a[4] * y; + out[5] = a[5] * y; + out[6] = a[6] * y; + out[7] = a[7] * y; + out[8] = a[8] * z; + out[9] = a[9] * z; + out[10] = a[10] * z; + out[11] = a[11] * z; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; +}; + +/** + * Rotates a mat4 by the given angle + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @param {vec3} axis the axis to rotate around + * @returns {mat4} out + */ +mat4.rotate = function (out, a, rad, axis) { + var x = axis[0], y = axis[1], z = axis[2], + len = Math.sqrt(x * x + y * y + z * z), + s, c, t, + a00, a01, a02, a03, + a10, a11, a12, a13, + a20, a21, a22, a23, + b00, b01, b02, + b10, b11, b12, + b20, b21, b22; + + if (Math.abs(len) < GLMAT_EPSILON) { return null; } + + len = 1 / len; + x *= len; + y *= len; + z *= len; + + s = Math.sin(rad); + c = Math.cos(rad); + t = 1 - c; + + a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; + a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; + a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; + + // Construct the elements of the rotation matrix + b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s; + b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s; + b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c; + + // Perform rotation-specific matrix multiplication + out[0] = a00 * b00 + a10 * b01 + a20 * b02; + out[1] = a01 * b00 + a11 * b01 + a21 * b02; + out[2] = a02 * b00 + a12 * b01 + a22 * b02; + out[3] = a03 * b00 + a13 * b01 + a23 * b02; + out[4] = a00 * b10 + a10 * b11 + a20 * b12; + out[5] = a01 * b10 + a11 * b11 + a21 * b12; + out[6] = a02 * b10 + a12 * b11 + a22 * b12; + out[7] = a03 * b10 + a13 * b11 + a23 * b12; + out[8] = a00 * b20 + a10 * b21 + a20 * b22; + out[9] = a01 * b20 + a11 * b21 + a21 * b22; + out[10] = a02 * b20 + a12 * b21 + a22 * b22; + out[11] = a03 * b20 + a13 * b21 + a23 * b22; + + if (a !== out) { // If the source and destination differ, copy the unchanged last row + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } + return out; +}; + +/** + * Rotates a matrix by the given angle around the X axis + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +mat4.rotateX = function (out, a, rad) { + var s = Math.sin(rad), + c = Math.cos(rad), + a10 = a[4], + a11 = a[5], + a12 = a[6], + a13 = a[7], + a20 = a[8], + a21 = a[9], + a22 = a[10], + a23 = a[11]; + + if (a !== out) { // If the source and destination differ, copy the unchanged rows + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } + + // Perform axis-specific matrix multiplication + out[4] = a10 * c + a20 * s; + out[5] = a11 * c + a21 * s; + out[6] = a12 * c + a22 * s; + out[7] = a13 * c + a23 * s; + out[8] = a20 * c - a10 * s; + out[9] = a21 * c - a11 * s; + out[10] = a22 * c - a12 * s; + out[11] = a23 * c - a13 * s; + return out; +}; + +/** + * Rotates a matrix by the given angle around the Y axis + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +mat4.rotateY = function (out, a, rad) { + var s = Math.sin(rad), + c = Math.cos(rad), + a00 = a[0], + a01 = a[1], + a02 = a[2], + a03 = a[3], + a20 = a[8], + a21 = a[9], + a22 = a[10], + a23 = a[11]; + + if (a !== out) { // If the source and destination differ, copy the unchanged rows + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } + + // Perform axis-specific matrix multiplication + out[0] = a00 * c - a20 * s; + out[1] = a01 * c - a21 * s; + out[2] = a02 * c - a22 * s; + out[3] = a03 * c - a23 * s; + out[8] = a00 * s + a20 * c; + out[9] = a01 * s + a21 * c; + out[10] = a02 * s + a22 * c; + out[11] = a03 * s + a23 * c; + return out; +}; + +/** + * Rotates a matrix by the given angle around the Z axis + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +mat4.rotateZ = function (out, a, rad) { + var s = Math.sin(rad), + c = Math.cos(rad), + a00 = a[0], + a01 = a[1], + a02 = a[2], + a03 = a[3], + a10 = a[4], + a11 = a[5], + a12 = a[6], + a13 = a[7]; + + if (a !== out) { // If the source and destination differ, copy the unchanged last row + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } + + // Perform axis-specific matrix multiplication + out[0] = a00 * c + a10 * s; + out[1] = a01 * c + a11 * s; + out[2] = a02 * c + a12 * s; + out[3] = a03 * c + a13 * s; + out[4] = a10 * c - a00 * s; + out[5] = a11 * c - a01 * s; + out[6] = a12 * c - a02 * s; + out[7] = a13 * c - a03 * s; + return out; +}; + +/** + * Creates a matrix from a quaternion rotation and vector translation + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.translate(dest, vec); + * var quatMat = mat4.create(); + * quat4.toMat4(quat, quatMat); + * mat4.multiply(dest, quatMat); + * + * @param {mat4} out mat4 receiving operation result + * @param {quat4} q Rotation quaternion + * @param {vec3} v Translation vector + * @returns {mat4} out + */ +mat4.fromRotationTranslation = function (out, q, v) { + // Quaternion math + var x = q[0], y = q[1], z = q[2], w = q[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, + + xx = x * x2, + xy = x * y2, + xz = x * z2, + yy = y * y2, + yz = y * z2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; + + out[0] = 1 - (yy + zz); + out[1] = xy + wz; + out[2] = xz - wy; + out[3] = 0; + out[4] = xy - wz; + out[5] = 1 - (xx + zz); + out[6] = yz + wx; + out[7] = 0; + out[8] = xz + wy; + out[9] = yz - wx; + out[10] = 1 - (xx + yy); + out[11] = 0; + out[12] = v[0]; + out[13] = v[1]; + out[14] = v[2]; + out[15] = 1; + + return out; +}; + +mat4.fromQuat = function (out, q) { + var x = q[0], y = q[1], z = q[2], w = q[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, + + xx = x * x2, + yx = y * x2, + yy = y * y2, + zx = z * x2, + zy = z * y2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; + + out[0] = 1 - yy - zz; + out[1] = yx + wz; + out[2] = zx - wy; + out[3] = 0; + + out[4] = yx - wz; + out[5] = 1 - xx - zz; + out[6] = zy + wx; + out[7] = 0; + + out[8] = zx + wy; + out[9] = zy - wx; + out[10] = 1 - xx - yy; + out[11] = 0; + + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + + return out; +}; + +/** + * Generates a frustum matrix with the given bounds + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {Number} left Left bound of the frustum + * @param {Number} right Right bound of the frustum + * @param {Number} bottom Bottom bound of the frustum + * @param {Number} top Top bound of the frustum + * @param {Number} near Near bound of the frustum + * @param {Number} far Far bound of the frustum + * @returns {mat4} out + */ +mat4.frustum = function (out, left, right, bottom, top, near, far) { + var rl = 1 / (right - left), + tb = 1 / (top - bottom), + nf = 1 / (near - far); + out[0] = (near * 2) * rl; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = (near * 2) * tb; + out[6] = 0; + out[7] = 0; + out[8] = (right + left) * rl; + out[9] = (top + bottom) * tb; + out[10] = (far + near) * nf; + out[11] = -1; + out[12] = 0; + out[13] = 0; + out[14] = (far * near * 2) * nf; + out[15] = 0; + return out; +}; + +/** + * Generates a perspective projection matrix with the given bounds + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {number} fovy Vertical field of view in radians + * @param {number} aspect Aspect ratio. typically viewport width/height + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @returns {mat4} out + */ +mat4.perspective = function (out, fovy, aspect, near, far) { + var f = 1.0 / Math.tan(fovy / 2), + nf = 1 / (near - far); + out[0] = f / aspect; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = f; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = (far + near) * nf; + out[11] = -1; + out[12] = 0; + out[13] = 0; + out[14] = (2 * far * near) * nf; + out[15] = 0; + return out; +}; + +/** + * Generates a orthogonal projection matrix with the given bounds + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {number} left Left bound of the frustum + * @param {number} right Right bound of the frustum + * @param {number} bottom Bottom bound of the frustum + * @param {number} top Top bound of the frustum + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @returns {mat4} out + */ +mat4.ortho = function (out, left, right, bottom, top, near, far) { + var lr = 1 / (left - right), + bt = 1 / (bottom - top), + nf = 1 / (near - far); + out[0] = -2 * lr; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = -2 * bt; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 2 * nf; + out[11] = 0; + out[12] = (left + right) * lr; + out[13] = (top + bottom) * bt; + out[14] = (far + near) * nf; + out[15] = 1; + return out; +}; + +/** + * Generates a look-at matrix with the given eye position, focal point, and up axis + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {vec3} eye Position of the viewer + * @param {vec3} center Point the viewer is looking at + * @param {vec3} up vec3 pointing up + * @returns {mat4} out + */ +mat4.lookAt = function (out, eye, center, up) { + var x0, x1, x2, y0, y1, y2, z0, z1, z2, len, + eyex = eye[0], + eyey = eye[1], + eyez = eye[2], + upx = up[0], + upy = up[1], + upz = up[2], + centerx = center[0], + centery = center[1], + centerz = center[2]; + + if (Math.abs(eyex - centerx) < GLMAT_EPSILON && + Math.abs(eyey - centery) < GLMAT_EPSILON && + Math.abs(eyez - centerz) < GLMAT_EPSILON) { + return mat4.identity(out); + } + + z0 = eyex - centerx; + z1 = eyey - centery; + z2 = eyez - centerz; + + len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2); + z0 *= len; + z1 *= len; + z2 *= len; + + x0 = upy * z2 - upz * z1; + x1 = upz * z0 - upx * z2; + x2 = upx * z1 - upy * z0; + len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2); + if (!len) { + x0 = 0; + x1 = 0; + x2 = 0; + } else { + len = 1 / len; + x0 *= len; + x1 *= len; + x2 *= len; + } + + y0 = z1 * x2 - z2 * x1; + y1 = z2 * x0 - z0 * x2; + y2 = z0 * x1 - z1 * x0; + + len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2); + if (!len) { + y0 = 0; + y1 = 0; + y2 = 0; + } else { + len = 1 / len; + y0 *= len; + y1 *= len; + y2 *= len; + } + + out[0] = x0; + out[1] = y0; + out[2] = z0; + out[3] = 0; + out[4] = x1; + out[5] = y1; + out[6] = z1; + out[7] = 0; + out[8] = x2; + out[9] = y2; + out[10] = z2; + out[11] = 0; + out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); + out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); + out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); + out[15] = 1; + + return out; +}; + +/** + * Returns a string representation of a mat4 + * + * @param {mat4} mat matrix to represent as a string + * @returns {String} string representation of the matrix + */ +mat4.str = function (a) { + return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + + a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' + + a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')'; +}; + +/** + * Returns Frobenius norm of a mat4 + * + * @param {mat4} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ +mat4.frob = function (a) { + return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2) + Math.pow(a[9], 2) + Math.pow(a[10], 2) + Math.pow(a[11], 2) + Math.pow(a[12], 2) + Math.pow(a[13], 2) + Math.pow(a[14], 2) + Math.pow(a[15], 2) )) +}; + + +if(typeof(exports) !== 'undefined') { + exports.mat4 = mat4; +} +; +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class Quaternion + * @name quat + */ + +var quat = {}; + +/** + * Creates a new identity quat + * + * @returns {quat} a new quaternion + */ +quat.create = function() { + var out = new GLMAT_ARRAY_TYPE(4); + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; +}; + +/** + * Sets a quaternion to represent the shortest rotation from one + * vector to another. + * + * Both vectors are assumed to be unit length. + * + * @param {quat} out the receiving quaternion. + * @param {vec3} a the initial vector + * @param {vec3} b the destination vector + * @returns {quat} out + */ +quat.rotationTo = (function() { + var tmpvec3 = vec3.create(); + var xUnitVec3 = vec3.fromValues(1,0,0); + var yUnitVec3 = vec3.fromValues(0,1,0); + + return function(out, a, b) { + var dot = vec3.dot(a, b); + if (dot < -0.999999) { + vec3.cross(tmpvec3, xUnitVec3, a); + if (vec3.length(tmpvec3) < 0.000001) + vec3.cross(tmpvec3, yUnitVec3, a); + vec3.normalize(tmpvec3, tmpvec3); + quat.setAxisAngle(out, tmpvec3, Math.PI); + return out; + } else if (dot > 0.999999) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; + } else { + vec3.cross(tmpvec3, a, b); + out[0] = tmpvec3[0]; + out[1] = tmpvec3[1]; + out[2] = tmpvec3[2]; + out[3] = 1 + dot; + return quat.normalize(out, out); + } + }; +})(); + +/** + * Sets the specified quaternion with values corresponding to the given + * axes. Each axis is a vec3 and is expected to be unit length and + * perpendicular to all other specified axes. + * + * @param {vec3} view the vector representing the viewing direction + * @param {vec3} right the vector representing the local "right" direction + * @param {vec3} up the vector representing the local "up" direction + * @returns {quat} out + */ +quat.setAxes = (function() { + var matr = mat3.create(); + + return function(out, view, right, up) { + matr[0] = right[0]; + matr[3] = right[1]; + matr[6] = right[2]; + + matr[1] = up[0]; + matr[4] = up[1]; + matr[7] = up[2]; + + matr[2] = -view[0]; + matr[5] = -view[1]; + matr[8] = -view[2]; + + return quat.normalize(out, quat.fromMat3(out, matr)); + }; +})(); + +/** + * Creates a new quat initialized with values from an existing quaternion + * + * @param {quat} a quaternion to clone + * @returns {quat} a new quaternion + * @function + */ +quat.clone = vec4.clone; + +/** + * Creates a new quat initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {quat} a new quaternion + * @function + */ +quat.fromValues = vec4.fromValues; - if(openPercent === 0) { - this.val(false); - } else if(openPercent === 100) { - this.val(true); - } else { - var openPixel = Math.round( (openPercent / 100) * this.track.offsetWidth - (this.handle.offsetWidth) ); - openPixel = (openPixel < 1 ? 0 : openPixel); - this.handle.style[ionic.CSS.TRANSFORM] = 'translate3d(' + openPixel + 'px,0,0)'; - } - } - }, +/** + * Copy the values from one quat to another + * + * @param {quat} out the receiving quaternion + * @param {quat} a the source quaternion + * @returns {quat} out + * @function + */ +quat.copy = vec4.copy; - val: function(value) { - if(value === true || value === false) { - if(this.handle.style[ionic.CSS.TRANSFORM] !== "") { - this.handle.style[ionic.CSS.TRANSFORM] = ""; - } - this.checkbox.checked = value; - this.openPercent = (value ? 100 : 0); - this.onChange && this.onChange(); - } - return this.checkbox.checked; - } +/** + * Set the components of a quat to the given values + * + * @param {quat} out the receiving quaternion + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {quat} out + * @function + */ +quat.set = vec4.set; - }); +/** + * Set a quat to the identity quaternion + * + * @param {quat} out the receiving quaternion + * @returns {quat} out + */ +quat.identity = function(out) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; +}; -})(ionic); +/** + * Sets a quat from the given angle and rotation axis, + * then returns it. + * + * @param {quat} out the receiving quaternion + * @param {vec3} axis the axis around which to rotate + * @param {Number} rad the angle in radians + * @returns {quat} out + **/ +quat.setAxisAngle = function(out, axis, rad) { + rad = rad * 0.5; + var s = Math.sin(rad); + out[0] = s * axis[0]; + out[1] = s * axis[1]; + out[2] = s * axis[2]; + out[3] = Math.cos(rad); + return out; +}; -(function(ionic) { -'use strict'; - ionic.controllers.ViewController = function(options) { - this.initialize.apply(this, arguments); - }; +/** + * Adds two quat's + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @returns {quat} out + * @function + */ +quat.add = vec4.add; - ionic.controllers.ViewController.inherit = ionic.inherit; +/** + * Multiplies two quat's + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @returns {quat} out + */ +quat.multiply = function(out, a, b) { + var ax = a[0], ay = a[1], az = a[2], aw = a[3], + bx = b[0], by = b[1], bz = b[2], bw = b[3]; - ionic.extend(ionic.controllers.ViewController.prototype, { - initialize: function() {}, - // Destroy this view controller, including all child views - destroy: function() { - } - }); + out[0] = ax * bw + aw * bx + ay * bz - az * by; + out[1] = ay * bw + aw * by + az * bx - ax * bz; + out[2] = az * bw + aw * bz + ax * by - ay * bx; + out[3] = aw * bw - ax * bx - ay * by - az * bz; + return out; +}; -})(window.ionic); +/** + * Alias for {@link quat.multiply} + * @function + */ +quat.mul = quat.multiply; -(function(ionic) { -'use strict'; +/** + * Scales a quat by a scalar number + * + * @param {quat} out the receiving vector + * @param {quat} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {quat} out + * @function + */ +quat.scale = vec4.scale; - /** - * The SideMenuController is a controller with a left and/or right menu that - * can be slid out and toggled. Seen on many an app. - * - * The right or left menu can be disabled or not used at all, if desired. - */ - ionic.controllers.SideMenuController = ionic.controllers.ViewController.inherit({ - initialize: function(options) { - var self = this; +/** + * Rotates a quaternion by the given angle about the X axis + * + * @param {quat} out quat receiving operation result + * @param {quat} a quat to rotate + * @param {number} rad angle (in radians) to rotate + * @returns {quat} out + */ +quat.rotateX = function (out, a, rad) { + rad *= 0.5; - this.left = options.left; - this.right = options.right; - this.content = options.content; - this.dragThresholdX = options.dragThresholdX || 10; + var ax = a[0], ay = a[1], az = a[2], aw = a[3], + bx = Math.sin(rad), bw = Math.cos(rad); - this._rightShowing = false; - this._leftShowing = false; - this._isDragging = false; + out[0] = ax * bw + aw * bx; + out[1] = ay * bw + az * bx; + out[2] = az * bw - ay * bx; + out[3] = aw * bw - ax * bx; + return out; +}; - if(this.content) { - this.content.onDrag = function(e) { - self._handleDrag(e); - }; +/** + * Rotates a quaternion by the given angle about the Y axis + * + * @param {quat} out quat receiving operation result + * @param {quat} a quat to rotate + * @param {number} rad angle (in radians) to rotate + * @returns {quat} out + */ +quat.rotateY = function (out, a, rad) { + rad *= 0.5; - this.content.onEndDrag =function(e) { - self._endDrag(e); - }; - } - }, - /** - * Set the content view controller if not passed in the constructor options. - * - * @param {object} content - */ - setContent: function(content) { - var self = this; + var ax = a[0], ay = a[1], az = a[2], aw = a[3], + by = Math.sin(rad), bw = Math.cos(rad); - this.content = content; + out[0] = ax * bw - az * by; + out[1] = ay * bw + aw * by; + out[2] = az * bw + ax * by; + out[3] = aw * bw - ay * by; + return out; +}; - this.content.onDrag = function(e) { - self._handleDrag(e); - }; +/** + * Rotates a quaternion by the given angle about the Z axis + * + * @param {quat} out quat receiving operation result + * @param {quat} a quat to rotate + * @param {number} rad angle (in radians) to rotate + * @returns {quat} out + */ +quat.rotateZ = function (out, a, rad) { + rad *= 0.5; - this.content.endDrag = function(e) { - self._endDrag(e); - }; - }, + var ax = a[0], ay = a[1], az = a[2], aw = a[3], + bz = Math.sin(rad), bw = Math.cos(rad); - isOpenLeft: function() { - return this.getOpenAmount() > 0; - }, + out[0] = ax * bw + ay * bz; + out[1] = ay * bw - ax * bz; + out[2] = az * bw + aw * bz; + out[3] = aw * bw - az * bz; + return out; +}; - isOpenRight: function() { - return this.getOpenAmount() < 0; - }, +/** + * Calculates the W component of a quat from the X, Y, and Z components. + * Assumes that quaternion is 1 unit in length. + * Any existing W component will be ignored. + * + * @param {quat} out the receiving quaternion + * @param {quat} a quat to calculate W component of + * @returns {quat} out + */ +quat.calculateW = function (out, a) { + var x = a[0], y = a[1], z = a[2]; - /** - * Toggle the left menu to open 100% - */ - toggleLeft: function(shouldOpen) { - var openAmount = this.getOpenAmount(); - if (arguments.length === 0) { - shouldOpen = openAmount <= 0; - } - this.content.enableAnimation(); - if(!shouldOpen) { - this.openPercentage(0); - } else { - this.openPercentage(100); - } - }, + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); + return out; +}; - /** - * Toggle the right menu to open 100% - */ - toggleRight: function(shouldOpen) { - var openAmount = this.getOpenAmount(); - if (arguments.length === 0) { - shouldOpen = openAmount >= 0; - } - this.content.enableAnimation(); - if(!shouldOpen) { - this.openPercentage(0); - } else { - this.openPercentage(-100); - } - }, +/** + * Calculates the dot product of two quat's + * + * @param {quat} a the first operand + * @param {quat} b the second operand + * @returns {Number} dot product of a and b + * @function + */ +quat.dot = vec4.dot; - /** - * Close all menus. - */ - close: function() { - this.openPercentage(0); - }, +/** + * Performs a linear interpolation between two quat's + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {quat} out + * @function + */ +quat.lerp = vec4.lerp; + +/** + * Performs a spherical linear interpolation between two quat + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {quat} out + */ +quat.slerp = function (out, a, b, t) { + // benchmarks: + // http://jsperf.com/quaternion-slerp-implementations + + var ax = a[0], ay = a[1], az = a[2], aw = a[3], + bx = b[0], by = b[1], bz = b[2], bw = b[3]; + + var omega, cosom, sinom, scale0, scale1; + + // calc cosine + cosom = ax * bx + ay * by + az * bz + aw * bw; + // adjust signs (if necessary) + if ( cosom < 0.0 ) { + cosom = -cosom; + bx = - bx; + by = - by; + bz = - bz; + bw = - bw; + } + // calculate coefficients + if ( (1.0 - cosom) > 0.000001 ) { + // standard case (slerp) + omega = Math.acos(cosom); + sinom = Math.sin(omega); + scale0 = Math.sin((1.0 - t) * omega) / sinom; + scale1 = Math.sin(t * omega) / sinom; + } else { + // "from" and "to" quaternions are very close + // ... so we can do a linear interpolation + scale0 = 1.0 - t; + scale1 = t; + } + // calculate final values + out[0] = scale0 * ax + scale1 * bx; + out[1] = scale0 * ay + scale1 * by; + out[2] = scale0 * az + scale1 * bz; + out[3] = scale0 * aw + scale1 * bw; + + return out; +}; - /** - * @return {float} The amount the side menu is open, either positive or negative for left (positive), or right (negative) - */ - getOpenAmount: function() { - return this.content && this.content.getTranslateX() || 0; - }, +/** + * Calculates the inverse of a quat + * + * @param {quat} out the receiving quaternion + * @param {quat} a quat to calculate inverse of + * @returns {quat} out + */ +quat.invert = function(out, a) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], + dot = a0*a0 + a1*a1 + a2*a2 + a3*a3, + invDot = dot ? 1.0/dot : 0; + + // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0 - /** - * @return {float} The ratio of open amount over menu width. For example, a - * menu of width 100 open 50 pixels would be open 50% or a ratio of 0.5. Value is negative - * for right menu. - */ - getOpenRatio: function() { - var amount = this.getOpenAmount(); - if(amount >= 0) { - return amount / this.left.width; - } - return amount / this.right.width; - }, + out[0] = -a0*invDot; + out[1] = -a1*invDot; + out[2] = -a2*invDot; + out[3] = a3*invDot; + return out; +}; - isOpen: function() { - return this.getOpenAmount() !== 0; - }, +/** + * Calculates the conjugate of a quat + * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result. + * + * @param {quat} out the receiving quaternion + * @param {quat} a quat to calculate conjugate of + * @returns {quat} out + */ +quat.conjugate = function (out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = a[3]; + return out; +}; - /** - * @return {float} The percentage of open amount over menu width. For example, a - * menu of width 100 open 50 pixels would be open 50%. Value is negative - * for right menu. - */ - getOpenPercentage: function() { - return this.getOpenRatio() * 100; - }, +/** + * Calculates the length of a quat + * + * @param {quat} a vector to calculate length of + * @returns {Number} length of a + * @function + */ +quat.length = vec4.length; - /** - * Open the menu with a given percentage amount. - * @param {float} percentage The percentage (positive or negative for left/right) to open the menu. - */ - openPercentage: function(percentage) { - var p = percentage / 100; +/** + * Alias for {@link quat.length} + * @function + */ +quat.len = quat.length; - if(this.left && percentage >= 0) { - this.openAmount(this.left.width * p); - } else if(this.right && percentage < 0) { - var maxRight = this.right.width; - this.openAmount(this.right.width * p); - } - }, +/** + * Calculates the squared length of a quat + * + * @param {quat} a vector to calculate squared length of + * @returns {Number} squared length of a + * @function + */ +quat.squaredLength = vec4.squaredLength; - /** - * Open the menu the given pixel amount. - * @param {float} amount the pixel amount to open the menu. Positive value for left menu, - * negative value for right menu (only one menu will be visible at a time). - */ - openAmount: function(amount) { - var maxLeft = this.left && this.left.width || 0; - var maxRight = this.right && this.right.width || 0; +/** + * Alias for {@link quat.squaredLength} + * @function + */ +quat.sqrLen = quat.squaredLength; - // Check if we can move to that side, depending if the left/right panel is enabled - if(!(this.left && this.left.isEnabled) && amount > 0) { - this.content.setTranslateX(0); - return; - } +/** + * Normalize a quat + * + * @param {quat} out the receiving quaternion + * @param {quat} a quaternion to normalize + * @returns {quat} out + * @function + */ +quat.normalize = vec4.normalize; - if(!(this.right && this.right.isEnabled) && amount < 0) { - this.content.setTranslateX(0); - return; - } +/** + * Creates a quaternion from the given 3x3 rotation matrix. + * + * NOTE: The resultant quaternion is not normalized, so you should be sure + * to renormalize the quaternion yourself where necessary. + * + * @param {quat} out the receiving quaternion + * @param {mat3} m rotation matrix + * @returns {quat} out + * @function + */ +quat.fromMat3 = function(out, m) { + // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes + // article "Quaternion Calculus and Fast Animation". + var fTrace = m[0] + m[4] + m[8]; + var fRoot; + + if ( fTrace > 0.0 ) { + // |w| > 1/2, may as well choose w > 1/2 + fRoot = Math.sqrt(fTrace + 1.0); // 2w + out[3] = 0.5 * fRoot; + fRoot = 0.5/fRoot; // 1/(4w) + out[0] = (m[7]-m[5])*fRoot; + out[1] = (m[2]-m[6])*fRoot; + out[2] = (m[3]-m[1])*fRoot; + } else { + // |w| <= 1/2 + var i = 0; + if ( m[4] > m[0] ) + i = 1; + if ( m[8] > m[i*3+i] ) + i = 2; + var j = (i+1)%3; + var k = (i+2)%3; + + fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0); + out[i] = 0.5 * fRoot; + fRoot = 0.5 / fRoot; + out[3] = (m[k*3+j] - m[j*3+k]) * fRoot; + out[j] = (m[j*3+i] + m[i*3+j]) * fRoot; + out[k] = (m[k*3+i] + m[i*3+k]) * fRoot; + } + + return out; +}; - if(this._leftShowing && amount > maxLeft) { - this.content.setTranslateX(maxLeft); - return; - } +/** + * Returns a string representation of a quatenion + * + * @param {quat} vec vector to represent as a string + * @returns {String} string representation of the vector + */ +quat.str = function (a) { + return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; +}; - if(this._rightShowing && amount < -maxRight) { - this.content.setTranslateX(-maxRight); - return; - } +if(typeof(exports) !== 'undefined') { + exports.quat = quat; +} +; - this.content.setTranslateX(amount); - if(amount >= 0) { - this._leftShowing = true; - this._rightShowing = false; - if(amount > 0) { - // Push the z-index of the right menu down - this.right && this.right.pushDown && this.right.pushDown(); - // Bring the z-index of the left menu up - this.left && this.left.bringUp && this.left.bringUp(); - } - } else { - this._rightShowing = true; - this._leftShowing = false; - // Bring the z-index of the right menu up - this.right && this.right.bringUp && this.right.bringUp(); - // Push the z-index of the left menu down - this.left && this.left.pushDown && this.left.pushDown(); - } - }, - /** - * Given an event object, find the final resting position of this side - * menu. For example, if the user "throws" the content to the right and - * releases the touch, the left menu should snap open (animated, of course). - * - * @param {Event} e the gesture event to use for snapping - */ - snapToRest: function(e) { - // We want to animate at the end of this - this.content.enableAnimation(); - this._isDragging = false; - // Check how much the panel is open after the drag, and - // what the drag velocity is - var ratio = this.getOpenRatio(); - if(ratio === 0) { - // Just to be safe - this.openPercentage(0); - return; - } - var velocityThreshold = 0.3; - var velocityX = e.gesture.velocityX; - var direction = e.gesture.direction; - // Less than half, going left - //if(ratio > 0 && ratio < 0.5 && direction == 'left' && velocityX < velocityThreshold) { - //this.openPercentage(0); - //} - // Going right, less than half, too slow (snap back) - if(ratio > 0 && ratio < 0.5 && direction == 'right' && velocityX < velocityThreshold) { - this.openPercentage(0); - } - // Going left, more than half, too slow (snap back) - else if(ratio > 0.5 && direction == 'left' && velocityX < velocityThreshold) { - this.openPercentage(100); - } - // Going left, less than half, too slow (snap back) - else if(ratio < 0 && ratio > -0.5 && direction == 'left' && velocityX < velocityThreshold) { - this.openPercentage(0); - } - // Going right, more than half, too slow (snap back) - else if(ratio < 0.5 && direction == 'right' && velocityX < velocityThreshold) { - this.openPercentage(-100); - } + })(shim.exports); +})(this); - // Going right, more than half, or quickly (snap open) - else if(direction == 'right' && ratio >= 0 && (ratio >= 0.5 || velocityX > velocityThreshold)) { - this.openPercentage(100); - } +(function(window) { - // Going left, more than half, or quickly (span open) - else if(direction == 'left' && ratio <= 0 && (ratio <= -0.5 || velocityX > velocityThreshold)) { - this.openPercentage(-100); - } + // Namespace + ionic.Animation = ionic.Animation || {}; - // Snap back for safety - else { - this.openPercentage(0); + + ionic.Animation.TimingFn = { + 'linear': function(duration) { + return function(t) { + return ionic.Animation.Bezier.linear(t, duration); } }, - - // End a drag with the given event - _endDrag: function(e) { - if(this._isDragging) { - this.snapToRest(e); + 'ease': function(duration) { + return function(t) { + return ionic.Animation.Bezier.ease(t, duration); } - this._startX = null; - this._lastX = null; - this._offsetX = null; }, - - // Handle a drag event - _handleDrag: function(e) { - // If we don't have start coords, grab and store them - if(!this._startX) { - this._startX = e.gesture.touches[0].pageX; - this._lastX = this._startX; - } else { - // Grab the current tap coords - this._lastX = e.gesture.touches[0].pageX; + 'ease-in': function(duration) { + return function(t) { + return ionic.Animation.Bezier.easeIn(t, duration); } - - // Calculate difference from the tap points - if(!this._isDragging && Math.abs(this._lastX - this._startX) > this.dragThresholdX) { - // if the difference is greater than threshold, start dragging using the current - // point as the starting point - this._startX = this._lastX; - - this._isDragging = true; - // Initialize dragging - this.content.disableAnimation(); - this._offsetX = this.getOpenAmount(); + }, + 'ease-out': function(duration) { + return function(t) { + return ionic.Animation.Bezier.easeOut(t, duration); } - - if(this._isDragging) { - this.openAmount(this._offsetX + (this._lastX - this._startX)); + }, + 'ease-in-out': function(duration) { + return function(t) { + return ionic.Animation.Bezier.easeInOut(t, duration); } } - }); - -})(ionic); + }; +})(window); })(); /*! @@ -32175,7 +37387,7 @@ angular.module('ui.router.compat') * Copyright 2014 Drifty Co. * http://drifty.com/ * - * Ionic, v1.0.0-beta.3 + * Ionic, v1.0.0-beta.4 * A powerful HTML5 mobile app framework. * http://ionicframework.com/ * @@ -32449,6 +37661,68 @@ angular.element.prototype.removeClass = function(cssClasses) { return this; }; + +/** + * @ngdoc service + * @name $ionicAnimation + * @module ionic + * @description + * + * A powerful animation and transition system for Ionic apps. + * + * @usage + * + * ```js + * angular.module('mySuperApp', ['ionic']) + * .controller(function($scope, $ionicAnimation) { + * var anim = $ionicAnimate({ + * // A unique, reusable name + * name: 'popIn', + * + * // The duration of an auto playthrough + * duration: 0.5, + * + * // How long to wait before running the animation + * delay: 0, + * + * // Whether to reverse after doing one run through + * autoReverse: false, + * + * // How many times to repeat? -1 or null for infinite + * repeat: -1, + * + * // Timing curve to use (same as CSS timing functions), or a function of time "t" to handle it yourself + * curve: 'ease-in-out' + * + * onStart: function() { + * // Callback on start + * }, + * onEnd: function() { + * // Callback on end + * }, + * step: function(amt) { + * + * } + * }) + * }); + * ``` + * + */ +IonicModule +.provider('$ionicAnimation', function() { + var useSlowAnimations = false; + this.setSlowAnimations = function(isSlow) { + useSlowAnimations = isSlow; + }; + + this.$get = [function() { + return function(opts) { + opts.useSlowAnimations = useSlowAnimations; + return ionic.Animation.create(opts); + } + }] +}); + /** * @ngdoc service * @name $ionicBackdrop @@ -32707,6 +37981,7 @@ function($cacheFactory, $parse) { this.transcludeParent[0].appendChild(item.element[0]); } reconnectScope(item.scope); + !item.scope.$$phase && item.scope.$digest(); }, getLength: function() { return this.data && this.data.length || 0; @@ -32981,7 +38256,7 @@ function($rootScope, $timeout) { this.renderItem(i, rect.primaryPos - startPos, rect.secondaryPos); i++; } - var bufferEndIndex = i -1; + var bufferEndIndex = i - 1; for (i in this.renderedItems) { if (i < bufferStartIndex || i > bufferEndIndex) { @@ -33000,9 +38275,6 @@ function($rootScope, $timeout) { primaryPos, secondaryPos, secondaryPos ); this.renderedItems[dataIndex] = item; - if (item.scope && !item.scope.$$phase) { - item.scope.$digest(); - } } else { delete this.renderedItems[dataIndex]; } @@ -33208,10 +38480,12 @@ IonicModule '$q', '$log', '$compile', -function($document, $ionicTemplateLoader, $ionicBackdrop, $timeout, $q, $log, $compile) { + '$ionicPlatform', +function($document, $ionicTemplateLoader, $ionicBackdrop, $timeout, $q, $log, $compile, $ionicPlatform) { var loaderInstance; - //default value + //default values + var deregisterBackAction = angular.noop; var loadingShowDelay = $q.when(); return { @@ -33248,7 +38522,6 @@ function($document, $ionicTemplateLoader, $ionicBackdrop, $timeout, $q, $log, $c appendTo: $document[0].body }) .then(function(loader) { - var self = loader; loader.show = function(options) { @@ -33305,10 +38578,11 @@ function($document, $ionicTemplateLoader, $ionicBackdrop, $timeout, $q, $log, $c $timeout.cancel(this.durationTimeout); this.isShown = false; }; + return loader; }); } - return $q.when(loaderInstance); + return loaderInstance; } function showLoader(options) { @@ -33316,10 +38590,16 @@ function($document, $ionicTemplateLoader, $ionicBackdrop, $timeout, $q, $log, $c var delay = options.delay || options.showDelay || 0; //If loading.show() was called previously, cancel it and show with our new options - $timeout.cancel(loadingShowDelay); + loadingShowDelay && $timeout.cancel(loadingShowDelay); loadingShowDelay = $timeout(angular.noop, delay); loadingShowDelay.then(getLoader).then(function(loader) { + deregisterBackAction(); + //Disable hardware back button while loading + deregisterBackAction = $ionicPlatform.registerBackButtonAction( + angular.noop, + PLATFORM_BACK_BUTTON_PRIORITY_LOADING + ); return loader.show(options); }); @@ -33337,6 +38617,7 @@ function($document, $ionicTemplateLoader, $ionicBackdrop, $timeout, $q, $log, $c } function hideLoader() { + deregisterBackAction(); $timeout.cancel(loadingShowDelay); getLoader().then(function(loader) { loader.hide(); @@ -33440,7 +38721,10 @@ function($rootScope, $document, $compile, $timeout, $ionicPlatform, $ionicTempla var modalEl = angular.element(self.modalEl); self.el.classList.remove('hide'); - $document[0].body.classList.add('modal-open'); + $timeout(function(){ + $document[0].body.classList.add('modal-open'); + }, 400) + if(!self.el.parentElement) { modalEl.addClass(self.animation); @@ -33464,7 +38748,14 @@ function($rootScope, $document, $compile, $timeout, $ionicPlatform, $ionicTempla self.el.classList.add('active'); }, 20); - return $timeout(angular.noop, 400); + return $timeout(function() { + //After animating in, allow hide on backdrop click + self.$el.on('click', function(e) { + if (e.target === self.el) { + self.hide(); + } + }); + }, 400); }, /** @@ -33485,6 +38776,7 @@ function($rootScope, $document, $compile, $timeout, $ionicPlatform, $ionicTempla .removeClass('ng-enter ng-enter-active active'); }, 20); + self.$el.off('click'); self._isShown = false; self.scope.$parent && self.scope.$parent.$broadcast('modal.hidden', self); self._deregisterBackButton && self._deregisterBackButton(); @@ -33509,7 +38801,7 @@ function($rootScope, $document, $compile, $timeout, $ionicPlatform, $ionicTempla return self.hide().then(function() { self.scope.$destroy(); - angular.element(self.el).remove(); + self.$el.remove(); }); }, @@ -33539,6 +38831,7 @@ function($rootScope, $document, $compile, $timeout, $ionicPlatform, $ionicTempla // Compile the template var element = $compile('' + templateString + '')(scope); + options.$el = element; options.el = element[0]; options.modalEl = options.el.querySelector('.modal'); var modal = new ModalView(options); @@ -33698,8 +38991,10 @@ IonicModule ])); var PLATFORM_BACK_BUTTON_PRIORITY_VIEW = 100; +var PLATFORM_BACK_BUTTON_PRIORITY_SIDE_MENU = 150; var PLATFORM_BACK_BUTTON_PRIORITY_ACTION_SHEET = 300; -var PLATFORM_BACK_BUTTON_PRIORITY_POPUP = 500; +var PLATFORM_BACK_BUTTON_PRIORITY_POPUP = 400; +var PLATFORM_BACK_BUTTON_PRIORITY_LOADING = 500; /** * @ngdoc service * @name $ionicPlatform @@ -35775,15 +41070,17 @@ function($scope, scrollViewOptions, $timeout, $window, $$scrollValueCache, $loca var viewId = historyData && historyData.viewId; if (viewId) { - self.rememberScrollPosition(viewId); - self.scrollToRememberedPosition(); + $timeout(function() { + self.rememberScrollPosition(viewId); + self.scrollToRememberedPosition(); - backListenDone = $rootScope.$on('$viewHistory.viewBack', function(e, fromViewId, toViewId) { - //When going back from this view, forget its saved scroll position - if (viewId === fromViewId) { - self.forgetScrollPosition(); - } - }); + backListenDone = $rootScope.$on('$viewHistory.viewBack', function(e, fromViewId, toViewId) { + //When going back from this view, forget its saved scroll position + if (viewId === fromViewId) { + self.forgetScrollPosition(); + } + }); + }, 1, false); } }); @@ -35889,9 +41186,13 @@ IonicModule '$scope', '$attrs', '$ionicSideMenuDelegate', -function($scope, $attrs, $ionicSideMenuDelegate) { + '$ionicPlatform', +function($scope, $attrs, $ionicSideMenuDelegate, $ionicPlatform) { + var self = this; angular.extend(this, ionic.controllers.SideMenuController.prototype); + this.$scope = $scope; + ionic.controllers.SideMenuController.call(this, { left: { width: 275 }, right: { width: 275 } @@ -35914,10 +41215,28 @@ function($scope, $attrs, $ionicSideMenuDelegate) { $scope.sideMenuContentTranslateX = 0; + + var deregisterBackButtonAction = angular.noop; + var closeSideMenu = angular.bind(this, this.close); + $scope.$watch(function() { + return self.getOpenAmount() !== 0; + }, function(isOpen) { + deregisterBackButtonAction(); + if (isOpen) { + deregisterBackButtonAction = $ionicPlatform.registerBackButtonAction( + closeSideMenu, + PLATFORM_BACK_BUTTON_PRIORITY_SIDE_MENU + ); + } + }); + var deregisterInstance = $ionicSideMenuDelegate._registerInstance( this, $attrs.delegateHandle ); - $scope.$on('$destroy', deregisterInstance); + $scope.$on('$destroy', function() { + deregisterInstance(); + deregisterBackButtonAction(); + }); }]); IonicModule @@ -36169,20 +41488,20 @@ IonicModule * Here are a few things to keep in mind while using collection-repeat: * * 1. The data supplied to collection-repeat must be an array. - * 2. You must explicitly tell the directive what size your items will be in the DOM - * (pixel amount or percentage), using directive attributes (see below). - * 3. The elements rendered will be absolutely positioned: be sure to let your CSS work with this (see below). - * 4. Keep the HTML of your repeated elements as simple as possible. As the user scrolls down, elements - * will be lazily compiled. Resultingly, the more complicated your elements, the more likely it is that - * the on-demand compilation will cause jankiness in the user's scrolling. - * 5. The more elements you render on the screen at a time, the slower the scrolling will be. - * It is recommended to keep grids of collection-repeat list elements at 3-wide or less. + * 2. You must explicitly tell the directive what size your items will be in the DOM, using directive attributes. Pixel amounts or percentages are allowed (see below). + * 3. The elements rendered will be absolutely positioned: be sure to let your CSS work with + * this (see below). + * 4. Keep the HTML of your repeated elements as simple as possible. As the user scrolls down, + * elements will be lazily compiled. Resultingly, the more complicated your elements, the more + * likely it is that the on-demand compilation will cause some jerkiness in the user's scrolling. + * 5. The more elements you render on the screen per row, the more likelihood for scrolling to + * slow down. It is recommended to keep grids of collection-repeat list elements at 3-wide or less. + * For example, if you have a gallery of images just set their width to 33%. * 6. Each collection-repeat list will take up all of its parent scrollView's space. * If you wish to have multiple lists on one page, put each list within its own * {@link ionic.directive:ionScroll ionScroll} container. * * - * * @usage * * #### Basic Usage (single rows of items) @@ -36278,6 +41597,11 @@ IonicModule * @param {expression} collection-item-height The height of the repeated element. Can be a number (in pixels), or a percentage. * */ +var COLLECTION_REPEAT_SCROLLVIEW_XY_ERROR = "Cannot create a collection-repeat within a scrollView that is scrollable on both x and y axis. Choose either x direction or y direction."; +var COLLECTION_REPEAT_ATTR_HEIGHT_ERROR = "collection-repeat expected attribute collection-item-height to be a an expression that returns a number (in pixels) or percentage."; +var COLLECTION_REPEAT_ATTR_WIDTH_ERROR = "collection-repeat expected attribute collection-item-width to be a an expression that returns a number (in pixels) or percentage."; +var COLLECTION_REPEAT_ATTR_REPEAT_ERROR = "collection-repeat expected expression in form of '_item_ in _collection_[ track by _id_]' but got '%'"; + IonicModule .directive('collectionRepeat', [ '$collectionRepeatManager', @@ -36293,14 +41617,14 @@ function($collectionRepeatManager, $collectionDataSource, $parse) { link: function($scope, $element, $attr, scrollCtrl, $transclude) { var scrollView = scrollCtrl.scrollView; if (scrollView.options.scrollingX && scrollView.options.scrollingY) { - throw new Error("Cannot create a collection-repeat within a scrollView that is scrollable on both x and y axis. Choose either x direction or y direction."); + throw new Error(COLLECTION_REPEAT_SCROLLVIEW_XY_ERROR); } var isVertical = !!scrollView.options.scrollingY; if (isVertical && !$attr.collectionItemHeight) { - throw new Error("collection-repeat expected attribute collection-item-height to be a an expression that returns a number."); + throw new Error(COLLECTION_REPEAT_ATTR_HEIGHT_ERROR); } else if (!isVertical && !$attr.collectionItemWidth) { - throw new Error("collection-repeat expected attribute collection-item-width to be a an expression that returns a number."); + throw new Error(COLLECTION_REPEAT_ATTR_WIDTH_ERROR); } $attr.collectionItemHeight = $attr.collectionItemHeight || '"100%"'; $attr.collectionItemWidth = $attr.collectionItemWidth || '"100%"'; @@ -36329,16 +41653,20 @@ function($collectionRepeatManager, $collectionDataSource, $parse) { var match = $attr.collectionRepeat.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/); if (!match) { - throw new Error("collection-repeat expected expression in form of '_item_ in _collection_[ track by _id_]' but got '" + $attr.collectionRepeat + "'."); + throw new Error(COLLECTION_REPEAT_ATTR_REPEAT_ERROR + .replace('%', $attr.collectionRepeat)); } + var keyExpr = match[1]; + var listExpr = match[2]; + var trackByExpr = match[3]; var dataSource = new $collectionDataSource({ scope: $scope, transcludeFn: $transclude, transcludeParent: $element.parent(), - keyExpr: match[1], - listExpr: match[2], - trackByExpr: match[3], + keyExpr: keyExpr, + listExpr: listExpr, + trackByExpr: trackByExpr, heightGetter: heightGetter, widthGetter: widthGetter }); @@ -36348,7 +41676,7 @@ function($collectionRepeatManager, $collectionDataSource, $parse) { scrollView: scrollCtrl.scrollView, }); - $scope.$watchCollection(dataSource.listExpr, function(value) { + $scope.$watchCollection(listExpr, function(value) { if (value && !angular.isArray(value)) { throw new Error("collection-repeat expects an array to repeat over, but instead got '" + typeof value + "'."); } @@ -36360,15 +41688,16 @@ function($collectionRepeatManager, $collectionDataSource, $parse) { dataSource.setData(value); collectionRepeatManager.resize(); } - var resize = angular.bind(collectionRepeatManager, collectionRepeatManager.resize); - ionic.on('resize', function() { - rerender($scope.$eval(dataSource.listExpr)); - }, window); + function onWindowResize() { + rerender($scope.$eval(listExpr)); + } + + ionic.on('resize', onWindowResize, window); $scope.$on('$destroy', function() { collectionRepeatManager.destroy(); dataSource.destroy(); - ionic.off('resize', resize, window); + ionic.off('resize', onWindowResize, window); }); } }; @@ -36838,8 +42167,6 @@ function($animate, $compile) { this.$scope = $scope; this.$element = $element; }], - priorty: Number.MAX_VALUE, - require: ['ionItem', '^ionList'], scope: true, compile: function($element, $attrs) { var isAnchor = angular.isDefined($attrs.href) || angular.isDefined($attrs.ngHref); @@ -37316,7 +42643,7 @@ IonicModule replace: true, template: '' + '
' }; }]); @@ -37385,7 +42712,14 @@ IonicModule IonicModule .directive('ionNavBackButton', [ '$animate', -function($animate) { + '$rootScope', +function($animate, $rootScope) { + var backIsShown = false; + //If the current viewstate does not allow a back button, + //always hide it. + $rootScope.$on('$viewHistory.historyChange', function(e, data) { + backIsShown = !!data.showBack; + }); return { restrict: 'E', require: '^ionNavBar', @@ -37401,19 +42735,11 @@ function($animate) { }); } - //If the current viewstate does not allow a back button, - //always hide it. - var deregisterListener = $scope.$parent.$on( - '$viewHistory.historyChange', - function(e, data) { - $scope.hasBackButton = !!data.showBack; - } - ); - $scope.$on('$destroy', deregisterListener); - //Make sure both that a backButton is allowed in the first place, //and that it is shown by the current view. - $scope.$watch('!!(backButtonShown && hasBackButton)', ionic.animationFrameThrottle(function(show) { + $scope.$watch(function() { + return !!(backIsShown && $scope.backButtonShown); + }, ionic.animationFrameThrottle(function(show) { if (show) $animate.removeClass($element, 'ng-hide'); else $animate.addClass($element, 'ng-hide'); })); @@ -37459,6 +42785,33 @@ function($animate) { * with {@link ionic.service:$ionicNavBarDelegate}. * @param align-title {string=} Where to align the title of the navbar. * Available: 'left', 'right', 'center'. Defaults to 'center'. + * + *
+ * + * ### Alternative Usage + * + * Alternatively, you may put ion-nav-bar inside of each individual view's ion-view element. + * This will allow you to have the whole navbar, not just its contents, transition every view change. + * + * This is similar to using a header bar inside your ion-view, except it will has all the power of a navbar. + * + * If you do this, simply put nav buttons inside the navbar itself; do not use ``. + * + * + * ```html + * + * + * Back + * + *
+ * + *
+ *
+ * + * + * ``` */ IonicModule .directive('ionNavBar', [ @@ -37601,13 +42954,16 @@ IonicModule * @restrict AC * * @description - * Disables any transition animations between views, along with removing the back - * button which would normally show on the next view. This directive is useful for - * links within a sideMenu. + * nav-clear is an attribute directive which should be used with an element that changes + * the view on click, for example an `` or a `
';c.factory("$ionicPopup",["$ionicTemplateLoader","$ionicBackdrop","$q","$timeout","$rootScope","$document","$compile","$ionicPlatform",function(e,t,n,i,r,o,a,s){function c(t){t=angular.extend({scope:null,title:"",buttons:[]},t||{});var r=e.compile({template:g,scope:t.scope&&t.scope.$new(),appendTo:o[0].body}),s=t.templateUrl?e.load(t.templateUrl):n.when(t.template||t.content||"");return n.all([r,s]).then(function(e){var r=e[0],o=e[1],s=n.defer();r.responseDeferred=s;var c=angular.element(r.element[0].querySelector(".popup-body"));return o?(c.html(o),a(c.contents())(r.scope)):c.remove(),angular.extend(r.scope,{title:t.title,buttons:t.buttons,subTitle:t.subTitle,$buttonTapped:function(e,t){var n=(e.onTap||angular.noop)(t);t=t.originalEvent||t,t.defaultPrevented||s.resolve(n)}}),r.show=function(){r.isShown||(r.isShown=!0,ionic.requestAnimationFrame(function(){r.isShown&&(r.element.removeClass("popup-hidden"),r.element.addClass("popup-showing active"),ionic.DomUtil.centerElementByMarginTwice(r.element[0]),d(r.element))}))},r.hide=function(e){return e=e||angular.noop,r.isShown?(r.isShown=!1,r.element.removeClass("active"),r.element.addClass("popup-hidden"),void i(e,250)):e()},r.remove=function(){r.removed||(r.hide(function(){r.element.remove(),r.scope.$destroy()}),r.removed=!0)},r})}function l(){$[0]&&$[0].responseDeferred.resolve()}function u(e){function n(e){r.then(function(t){t.removed||t.responseDeferred.resolve(e)})}var r=w._createPopup(e),o=$[0];o&&o.hide();var a=i(angular.noop,o?m.stackPushDelay:0).then(function(){return r}).then(function(e){return o||(document.body.classList.add("popup-open"),t.retain(),w._backButtonActionDone=s.registerBackButtonAction(l,v)),$.unshift(e),e.show(),e.responseDeferred.notify({close:a.close}),e.responseDeferred.promise.then(function(n){var i=$.indexOf(e);-1!==i&&$.splice(i,1),e.remove();var r=$[0];return r?r.show():(document.body.classList.remove("popup-open"),t.release(),(w._backButtonActionDone||angular.noop)()),n})});return a.close=n,a}function d(e){var t=e[0].querySelectorAll("input");t.length||(t=e[0].querySelectorAll("button"));var n=t[t.length-1];n&&n.focus()}function h(e){return u(angular.extend({buttons:[{text:e.okText||"OK",type:e.okType||"button-positive",onTap:function(){return!0}}]},e||{}))}function f(e){return u(angular.extend({buttons:[{text:e.cancelText||"Cancel",type:e.cancelType||"button-default",onTap:function(){return!1}},{text:e.okText||"OK",type:e.okType||"button-positive",onTap:function(){return!0}}]},e||{}))}function p(e){var t=r.$new(!0);return t.data={},u(angular.extend({template:'',scope:t,buttons:[{text:e.cancelText||"Cancel",type:e.cancelType||"button-default",onTap:function(){}},{text:e.okText||"OK",type:e.okType||"button-positive",onTap:function(){return t.data.response||""}}]},e||{}))}var m={stackPushDelay:50},$=[],w={show:u,alert:h,confirm:f,prompt:p,_createPopup:c,_popupStack:$};return w}]),c.service("$ionicScrollDelegate",i(["resize","scrollTop","scrollBottom","scrollTo","scrollBy","getScrollPosition","anchorScroll","getScrollView","rememberScrollPosition","forgetScrollPosition","scrollToRememberedPosition"])),c.service("$ionicSideMenuDelegate",i(["toggleLeft","toggleRight","getOpenRatio","isOpen","isOpenLeft","isOpenRight","canDragContent"])),c.service("$ionicSlideBoxDelegate",i(["update","slide","enableSlide","previous","next","stop","currentIndex","slidesCount"])),c.service("$ionicTabsDelegate",i(["select","selectedIndex"])),c.factory("$ionicTemplateLoader",["$compile","$controller","$http","$q","$rootScope","$templateCache",function(e,t,n,i,r,o){function a(e){return n.get(e,{cache:o}).then(function(e){return e.data&&e.data.trim()})}function s(n){n=angular.extend({template:"",templateUrl:"",scope:null,controller:null,locals:{},appendTo:null},n||{});var o=n.templateUrl?this.load(n.templateUrl):i.when(n.template);return o.then(function(i){var o,a=n.scope||r.$new(),s=angular.element("
").html(i).contents();return n.controller&&(o=t(n.controller,angular.extend(n.locals,{$scope:a})),s.children().data("$ngControllerController",o)),n.appendTo&&angular.element(n.appendTo).append(s),e(s)(a),{element:s,scope:a}})}return{load:a,compile:s}}]),c.run(["$rootScope","$state","$location","$document","$animate","$ionicPlatform","$ionicViewService",function(e,t,n,i,r,o,a){function s(t){return e.$viewHistory.backView?e.$viewHistory.backView.go():ionic.Platform.exitApp(),t.preventDefault(),!1}e.$viewHistory={histories:{root:{historyId:"root",parentHistoryId:null,stack:[],cursor:-1}},views:{},backView:null,forwardView:null,currentView:null,disabledRegistrableTagNames:[]},a.disableRegisterByTagName&&(a.disableRegisterByTagName("ion-tabs"),a.disableRegisterByTagName("ion-side-menus")),e.$on("viewState.changeHistory",function(i,r){if(r){var o=r.historyId?e.$viewHistory.histories[r.historyId]:null;if(o&&o.cursor>-1&&o.cursor-1&&s.stack.length>0&&s.cursor=u.index;v--)p.stack[v].destroy(),p.stack.splice(v)}}else h.navAction="initialView";r.views[h.viewId]=this.createView({viewId:h.viewId,index:s.stack.length,historyId:s.historyId,backViewId:c&&c.viewId?c.viewId:null,forwardViewId:null,stateId:o,stateName:this.getCurrentStateName(),stateParams:this.getCurrentStateParams(),url:n.url()}),"moveBack"==h.navAction&&e.$emit("$viewHistory.viewBack",c.viewId,h.viewId),s.stack.push(r.views[h.viewId])}return d&&(d.disableAnimate&&(h.navDirection=null),d.disableBack&&(r.views[h.viewId].backViewId=null),this.nextViewOptions(null)),this.setNavViews(h.viewId),s.cursor=r.currentView.index,h},setNavViews:function(t){var n=e.$viewHistory;n.currentView=this._getViewById(t),n.backView=this._getBackView(n.currentView),n.forwardView=this._getForwardView(n.currentView),e.$broadcast("$viewHistory.historyChange",{showBack:n.backView&&n.backView.historyId===n.currentView.historyId})},registerHistory:function(e){e.$historyId=ionic.Utils.nextUid()},createView:function(e){var t=new s;return t.initialize(e)},getCurrentView:function(){return e.$viewHistory.currentView},getBackView:function(){return e.$viewHistory.backView},getForwardView:function(){return e.$viewHistory.forwardView},getNavDirection:function(){return e.$viewHistory.navDirection},getCurrentStateName:function(){return t&&t.current?t.current.name:null},isCurrentStateNavView:function(e){return t&&t.current&&t.current.views&&t.current.views[e]?!0:!1},getCurrentStateParams:function(){var e;if(t&&t.params)for(var n in t.params)t.params.hasOwnProperty(n)&&(e=e||{},e[n]=t.params[n]);return e},getCurrentStateId:function(){var e;if(t&&t.current&&t.current.name){if(e=t.current.name,t.params)for(var n in t.params)t.params.hasOwnProperty(n)&&t.params[n]&&(e+="_"+n+"="+t.params[n]);return e}return ionic.Utils.nextUid()},goToHistoryRoot:function(t){if(t){var n=e.$viewHistory.histories[t];if(n&&n.stack.length){if(e.$viewHistory.currentView&&e.$viewHistory.currentView.viewId===n.stack[0].viewId)return;e.$viewHistory.forcedNav={viewId:n.stack[0].viewId,navAction:"moveBack",navDirection:"back"},n.stack[0].go()}}},_getViewById:function(t){return t?e.$viewHistory.views[t]:null},_getBackView:function(e){return e?this._getViewById(e.backViewId):null},_getForwardView:function(e){return e?this._getViewById(e.forwardViewId):null},_getHistoryById:function(t){return t?e.$viewHistory.histories[t]:null},_getHistory:function(t){var n=this._getParentHistoryObj(t);return e.$viewHistory.histories[n.historyId]||(e.$viewHistory.histories[n.historyId]={historyId:n.historyId,parentHistoryId:this._getParentHistoryObj(n.scope.$parent).historyId,stack:[],cursor:-1}),e.$viewHistory.histories[n.historyId]},_getParentHistoryObj:function(t){for(var n=t;n;){if(n.hasOwnProperty("$historyId"))return{historyId:n.$historyId,scope:n};n=n.$parent}return{historyId:"root",scope:e}},nextViewOptions:function(e){return arguments.length?void(this._nextOpts=e):this._nextOpts},getRenderer:function(e,t,n){function i(e){for(var t="";!t&&e;)t=e.getAttribute("animation"),e=e.parentElement;return t}function r(){l&&e[0].classList.add(l),"back"===a.navDirection?e[0].classList.add("reverse"):e[0].classList.remove("reverse")}var a,s,c=this,l=i(e[0]);return function(t){return{enter:function(n){return s&&t?(r(),n.addClass("ng-enter"),document.body.classList.add("disable-pointer-events"),void o.enter(n,e,null,function(){document.body.classList.remove("disable-pointer-events"),l&&e[0].classList.remove(l)})):void e.append(n)},leave:function(){var n=e.contents();return s&&t?(r(),void o.leave(n,function(){n.remove()})):void n.remove()},register:function(e){return a=c.register(n,e),s=null!==l&&null!==a.navDirection,a}}}},disableRegisterByTagName:function(t){e.$viewHistory.disabledRegistrableTagNames.push(t.toUpperCase())},isTagNameRegistrable:function(t){var n,i,r=e.$viewHistory.disabledRegistrableTagNames;for(n=0;n')(e),angular.element(a[0]).replaceWith(n)),i=o('

')(e),ionic.requestAnimationFrame(function(){n&&r.leave(angular.element(n)); -var o=n&&angular.element(n)||null;r.enter(i,t,o,function(){c._headerBarView.align()}),angular.forEach(a,function(e){e&&e.parentNode&&angular.element(e).remove()}),e.$digest(),ionic.requestAnimationFrame(function(){i[0].classList.remove("invisible")})})}}]),c.factory("$$scrollValueCache",function(){return{}}).controller("$ionicScroll",["$scope","scrollViewOptions","$timeout","$window","$$scrollValueCache","$location","$rootScope","$document","$ionicScrollDelegate",function(e,t,n,i,r,o,a,s,c){var l=this;this._scrollViewOptions=t;var u=this.element=t.el,d=this.$element=angular.element(u),h=this.scrollView=new ionic.views.Scroll(t);(d.parent().length?d.parent():d).data("$$ionicScrollController",this);var f=c._registerInstance(this,t.delegateHandle);angular.isDefined(t.bouncing)||ionic.Platform.ready(function(){h.options.bouncing=!ionic.Platform.isAndroid()});var p=angular.bind(h,h.resize);ionic.on("resize",p,i);var v=angular.noop;e.$on("$destroy",function(){f(),ionic.off("resize",p,i),i.removeEventListener("resize",p),v(),l._rememberScrollId&&(r[l._rememberScrollId]=h.getValues())}),d.on("scroll",function(t){var n=(t.originalEvent||t).detail||{};e.$onScroll&&e.$onScroll({event:t,scrollTop:n.scrollTop||0,scrollLeft:n.scrollLeft||0})}),e.$on("$viewContentLoaded",function(e,t){if(!e.defaultPrevented){e.preventDefault();var n=t&&t.viewId;n&&(l.rememberScrollPosition(n),l.scrollToRememberedPosition(),v=a.$on("$viewHistory.viewBack",function(e,t){n===t&&l.forgetScrollPosition()}))}}),n(function(){h.run()}),this._rememberScrollId=null,this.getScrollView=function(){return this.scrollView},this.getScrollPosition=function(){return this.scrollView.getValues()},this.resize=function(){return n(p)},this.scrollTop=function(e){this.resize().then(function(){h.scrollTo(0,0,!!e)})},this.scrollBottom=function(e){this.resize().then(function(){var t=h.getScrollMax();h.scrollTo(t.left,t.top,!!e)})},this.scrollTo=function(e,t,n){this.resize().then(function(){h.scrollTo(e,t,!!n)})},this.scrollBy=function(e,t,n){this.resize().then(function(){h.scrollBy(e,t,!!n)})},this.anchorScroll=function(e){this.resize().then(function(){var t=o.hash(),n=t&&s[0].getElementById(t);if(t&&n){var i=ionic.DomUtil.getPositionInParent(n,l.$element);h.scrollTo(i.left,i.top,!!e)}else h.scrollTo(0,0,!!e)})},this.rememberScrollPosition=function(e){if(!e)throw new Error("Must supply an id to remember the scroll by!");this._rememberScrollId=e},this.forgetScrollPosition=function(){delete r[this._rememberScrollId],this._rememberScrollId=null},this.scrollToRememberedPosition=function(e){var t=r[this._rememberScrollId];t&&this.resize().then(function(){h.scrollTo(+t.left,+t.top,e)})},this._setRefresher=function(e,t){var n=this.refresher=t,i=l.refresher.clientHeight||0;h.activatePullToRefresh(i,function(){n.classList.add("active"),e.$onPulling()},function(){n.classList.remove("refreshing"),n.classList.remove("active")},function(){n.classList.add("refreshing"),e.$onRefresh()})}}]),c.controller("$ionicSideMenus",["$scope","$attrs","$ionicSideMenuDelegate",function(e,t,n){angular.extend(this,ionic.controllers.SideMenuController.prototype),ionic.controllers.SideMenuController.call(this,{left:{width:275},right:{width:275}}),this.canDragContent=function(t){return arguments.length&&(e.dragContent=!!t),e.dragContent},this.isDraggableTarget=function(t){return e.dragContent&&!t.gesture.srcEvent.defaultPrevented&&!t.target.tagName.match(/input|textarea|select|object|embed/i)&&!t.target.isContentEditable&&!(t.target.dataset?t.target.dataset.preventScroll:"true"==t.target.getAttribute("data-prevent-default"))},e.sideMenuContentTranslateX=0;var i=n._registerInstance(this,t.delegateHandle);e.$on("$destroy",i)}]),c.controller("$ionicTab",["$scope","$ionicViewService","$attrs","$location","$state",function(e,t,n,i,r){this.$scope=e,this.hrefMatchesState=function(){return n.href&&0===i.path().indexOf(n.href.replace(/^#/,"").replace(/\/$/,""))},this.srefMatchesState=function(){return n.uiSref&&r.includes(n.uiSref.split("(")[0])},this.navNameMatchesState=function(){return this.navViewName&&t.isCurrentStateNavView(this.navViewName)},this.tabMatchesState=function(){return this.hrefMatchesState()||this.srefMatchesState()||this.navNameMatchesState()}}]),c.controller("$ionicTabs",["$scope","$ionicViewService","$element",function(e,t){var n=null,i=this;i.tabs=[],i.selectedIndex=function(){return i.tabs.indexOf(n)},i.selectedTab=function(){return n},i.add=function(e){t.registerHistory(e),i.tabs.push(e),1===i.tabs.length&&i.select(e)},i.remove=function(e){var t=i.tabs.indexOf(e);if(-1!==t){if(e.$tabSelected)if(i.deselect(e),1===i.tabs.length);else{var n=t===i.tabs.length-1?t-1:t+1;i.select(i.tabs[n])}i.tabs.splice(t,1)}},i.deselect=function(e){e.$tabSelected&&(n=null,e.$tabSelected=!1,(e.onDeselect||angular.noop)())},i.select=function(r,o){var a;if(angular.isNumber(r)?(a=r,r=i.tabs[a]):a=i.tabs.indexOf(r),!r||-1==a)throw new Error('Cannot select tab "'+a+'"!');if(n&&n.$historyId==r.$historyId)o&&t.goToHistoryRoot(r.$historyId);else if(angular.forEach(i.tabs,function(e){i.deselect(e)}),n=r,r.$tabSelected=!0,(r.onSelect||angular.noop)(),o){var s={type:"tab",tabIndex:a,historyId:r.$historyId,navViewName:r.navViewName,hasNavView:!!r.navViewName,title:r.title,url:r.href,uiSref:r.uiSref};e.$emit("viewState.changeHistory",s)}}}]),c.directive("ionActionSheet",["$document",function(e){return{restrict:"E",scope:!0,replace:!0,link:function(t,n){var i=function(e){27==e.which&&(t.cancel(),t.$apply())},r=function(e){e.target==n[0]&&(t.cancel(),t.$apply())};t.$on("$destroy",function(){n.remove(),e.unbind("keyup",i)}),e.bind("keyup",i),n.bind("click",r)},template:'
'}}]),c.directive("ionCheckbox",function(){return{restrict:"E",replace:!0,require:"?ngModel",scope:{ngModel:"=?",ngValue:"=?",ngChecked:"=?",ngDisabled:"=?",ngChange:"&"},transclude:!0,template:'',compile:function(e,t){var n=e.find("input");t.name&&n.attr("name",t.name),t.ngChecked&&n.attr("ng-checked",t.ngChecked),t.ngDisabled&&n.attr("ng-disabled",t.ngDisabled),t.ngTrueValue&&n.attr("ng-true-value",t.ngTrueValue),t.ngFalseValue&&n.attr("ng-false-value",t.ngFalseValue)}}}),c.directive("collectionRepeat",["$collectionRepeatManager","$collectionDataSource","$parse",function(e,t,n){return{priority:1e3,transclude:"element",terminal:!0,$$tlb:!0,require:"^$ionicScroll",link:function(i,r,o,a,s){function c(e){l.resize(),g.setData(e),m.resize()}var l=a.scrollView;if(l.options.scrollingX&&l.options.scrollingY)throw new Error("Cannot create a collection-repeat within a scrollView that is scrollable on both x and y axis. Choose either x direction or y direction.");var u=!!l.options.scrollingY;if(u&&!o.collectionItemHeight)throw new Error("collection-repeat expected attribute collection-item-height to be a an expression that returns a number.");if(!u&&!o.collectionItemWidth)throw new Error("collection-repeat expected attribute collection-item-width to be a an expression that returns a number.");o.collectionItemHeight=o.collectionItemHeight||'"100%"',o.collectionItemWidth=o.collectionItemWidth||'"100%"';var d=o.collectionItemHeight?n(o.collectionItemHeight):function(){return l.__clientHeight},h=o.collectionItemWidth?n(o.collectionItemWidth):function(){return l.__clientWidth},f=function(e,t){var n=d(e,t);return angular.isString(n)&&n.indexOf("%")>-1?Math.floor(parseInt(n,10)/100*l.__clientHeight):n},p=function(e,t){var n=h(e,t);return angular.isString(n)&&n.indexOf("%")>-1?Math.floor(parseInt(n,10)/100*l.__clientWidth):n},v=o.collectionRepeat.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);if(!v)throw new Error("collection-repeat expected expression in form of '_item_ in _collection_[ track by _id_]' but got '"+o.collectionRepeat+"'.");var g=new t({scope:i,transcludeFn:s,transcludeParent:r.parent(),keyExpr:v[1],listExpr:v[2],trackByExpr:v[3],heightGetter:f,widthGetter:p}),m=new e({dataSource:g,element:a.$element,scrollView:a.scrollView});i.$watchCollection(g.listExpr,function(e){if(e&&!angular.isArray(e))throw new Error("collection-repeat expects an array to repeat over, but instead got '"+typeof e+"'.");c(e)});var $=angular.bind(m,m.resize);ionic.on("resize",function(){c(i.$eval(g.listExpr))},window),i.$on("$destroy",function(){m.destroy(),g.destroy(),ionic.off("resize",$,window)})}}}]),c.directive("ionContent",["$timeout","$controller","$ionicBind",function(e,t,n){return{restrict:"E",require:"^?ionNavView",scope:!0,priority:800,compile:function(e,i){function r(e,r,a){var s=e.$parent;e.$watch(function(){return(s.$hasHeader?" has-header":"")+(s.$hasSubheader?" has-subheader":"")+(s.$hasFooter?" has-footer":"")+(s.$hasSubfooter?" has-subfooter":"")+(s.$hasTabs?" has-tabs":"")+(s.$hasTabsTop?" has-tabs-top":"")},function(e,t){r.removeClass(t),r.addClass(e)}),e.$hasHeader=e.$hasSubheader=e.$hasFooter=e.$hasSubfooter=e.$hasTabs=e.$hasTabsTop=!1,n(e,a,{$onScroll:"&onScroll",$onScrollComplete:"&onScrollComplete",hasBouncing:"@",scroll:"@",padding:"@",hasScrollX:"@",hasScrollY:"@",scrollbarX:"@",scrollbarY:"@",startX:"@",startY:"@",scrollEventInterval:"@"}),angular.isDefined(a.padding)&&e.$watch(a.padding,function(e){(o||r).toggleClass("padding",!!e)}),"false"===e.scroll||("true"===i.overflowScroll?r.addClass("overflow-scroll"):t("$ionicScroll",{$scope:e,scrollViewOptions:{el:r[0],delegateHandle:i.delegateHandle,bouncing:e.$eval(e.hasBouncing),startX:e.$eval(e.startX)||0,startY:e.$eval(e.startY)||0,scrollbarX:e.$eval(e.scrollbarX)!==!1,scrollbarY:e.$eval(e.scrollbarY)!==!1,scrollingX:e.$eval(e.hasScrollX)===!0,scrollingY:e.$eval(e.hasScrollY)!==!1,scrollEventInterval:parseInt(e.scrollEventInterval,10)||10,scrollingComplete:function(){e.$onScrollComplete({scrollTop:this.__scrollTop,scrollLeft:this.__scrollLeft})}}}))}var o;return e.addClass("scroll-content"),"false"!=i.scroll&&(o=angular.element('
'),o.append(e.contents()),e.append(o)),{pre:r}}}}]),c.directive("ionNavBar",r()).directive("ionHeaderBar",r()).directive("ionHeaderBar",o(!0)).directive("ionFooterBar",o(!1)),c.directive("ionInfiniteScroll",["$timeout",function(e){function t(e,t,n){return n?t*(1-parseInt(e,10)/100):t-parseInt(e,10)}return{restrict:"E",require:["^$ionicScroll","ionInfiniteScroll"],template:'
',scope:!0,controller:["$scope","$attrs",function(e,n){this.isLoading=!1,this.scrollView=null,this.getMaxScroll=function(){var e=(n.distance||"1%").trim(),i=-1!==e.indexOf("%"),r=this.scrollView.getScrollMax();return{left:this.scrollView.options.scrollingX?t(e,r.left,i):-1,top:this.scrollView.options.scrollingY?t(e,r.top,i):-1}}}],link:function(t,n,i,r){function o(){if(!s.isLoading){var e=c.getValues(),t=s.getMaxScroll();(-1!==t.left&&e.left>=t.left||-1!==t.top&&e.top>=t.top)&&l()}}var a=r[0],s=r[1],c=s.scrollView=a.scrollView;t.icon=function(){return angular.isDefined(i.icon)?i.icon:"ion-loading-d"};var l=function(){n[0].classList.add("active"),s.isLoading=!0,t.$parent&&t.$parent.$apply(i.onInfinite||"")},u=function(){n[0].classList.remove("active"),e(function(){c.resize()},0,!1),s.isLoading=!1};t.$on("scroll.infiniteScrollComplete",function(){u()}),t.$on("$destroy",function(){a.$element.off("scroll",d)});var d=ionic.animationFrameThrottle(o);setTimeout(d),a.$element.on("scroll",d)}}}]);var m='',$='
';c.directive("ionItem",["$animate","$compile",function(){return{restrict:"E",controller:["$scope","$element",function(e,t){this.$scope=e,this.$element=t}],priorty:Number.MAX_VALUE,require:["ionItem","^ionList"],scope:!0,compile:function(e,t){var n=angular.isDefined(t.href)||angular.isDefined(t.ngHref),i=n||/ion-(delete|option|reorder)-button/i.test(e.html());if(i){var r=angular.element(n?m:$);r.append(e.contents()),e.append(r),e.addClass("item item-complex")}else e.addClass("item");return function(e,t,n){e.$href=function(){return n.href||n.ngHref}}}}}]);var w='
';c.directive("ionDeleteButton",["$animate",function(e){return{restrict:"E",require:["^ionItem","^ionList"],priority:Number.MAX_VALUE,compile:function(t,n){return n.$set("class",(n["class"]||"")+" button icon button-icon",!0),function(t,n,i,r){var o=r[0],a=r[1],s=angular.element(w);s.append(n),o.$element.append(s).addClass("item-left-editable"),a.showDelete()&&e.removeClass(s,"ng-hide")}}}}]);var b='';c.directive("ionOptionButton",["$compile",function(){return{restrict:"E",require:"^ionItem",priority:Number.MAX_VALUE,compile:function(e,t){return t.$set("class",(t["class"]||"")+" button",!0),function(e,t,n,i){i.optionsContainer||(i.optionsContainer=angular.element(b),i.$element.append(i.optionsContainer)),i.optionsContainer.append(t),t.on("click",a)}}}}]);var y='
';c.directive("ionReorderButton",["$animate",function(e){return{restrict:"E",require:["^ionItem","^ionList"],priority:Number.MAX_VALUE,compile:function(t,n){return n.$set("class",(n["class"]||"")+" button icon button-icon",!0),t[0].setAttribute("data-prevent-scroll",!0),function(t,n,i,r){var o=r[0],a=r[1];t.$onReorder=function(e,n){t.$eval(i.onReorder,{$fromIndex:e,$toIndex:n})};var s=angular.element(y);s.append(n),o.$element.append(s).addClass("item-right-editable"),a.showReorder()&&e.removeClass(s,"ng-hide")}}}}]),c.directive("ionList",["$animate","$timeout",function(e,t){return{restrict:"E",require:["ionList","^?$ionicScroll"],controller:"$ionicList",compile:function(n,i){var r=angular.element('
').append(n.contents());return n.append(r),function(n,r,o,a){function s(){function t(t,n){angular.forEach(r[0].querySelectorAll(t),function(t){n?e.removeClass(angular.element(t),"ng-hide"):e.addClass(angular.element(t),"ng-hide")})}function o(e,t){var n=angular.element(r[0].querySelectorAll(e));t?n.attr("data-tap-disabled","true"):n.removeAttr("data-tap-disabled")}c.listView=new ionic.views.ListView({el:r[0],listEl:r.children()[0],scrollEl:l&&l.element,scrollView:l&&l.scrollView,onReorder:function(e,t,n){var i=angular.element(e).scope();i&&i.$onReorder&&i.$onReorder(t,n)},canSwipe:function(){return c.canSwipeItems()}});angular.isDefined(i.canSwipe)&&n.$watch("!!("+i.canSwipe+")",function(e){c.canSwipeItems(e)}),angular.isDefined(i.showDelete)&&n.$watch("!!("+i.showDelete+")",function(e){c.showDelete(e)}),angular.isDefined(i.showReorder)&&n.$watch("!!("+i.showReorder+")",function(e){c.showReorder(e)}),n.$watch(function(){return c.showDelete()},function(e,n){(e||n)&&(e&&c.closeOptionButtons(),c.canSwipeItems(!e),r.children().toggleClass("list-left-editing",e),t(".item-delete.item-left-edit",e),o(".item-content",e))}),n.$watch(function(){return c.showReorder()},function(e,n){(e||n)&&(e&&c.closeOptionButtons(),c.canSwipeItems(!e),r.children().toggleClass("list-right-editing",e),t(".item-reorder.item-right-edit",e),o(".item-content",e))})}var c=a[0],l=a[1];t(s)}}}}]),c.directive("menuClose",["$ionicViewService",function(){return{restrict:"AC",require:"^ionSideMenus",link:function(e,t,n,i){t.bind("click",function(){i.close()})}}}]),c.directive("menuToggle",["$ionicViewService",function(){return{restrict:"AC",require:"^ionSideMenus",link:function(e,t,n,i){var r=n.menuToggle||"left";t.bind("click",function(){"left"===r?i.toggleLeft():"right"===r&&i.toggleRight()})}}}]),c.directive("ionModal",[function(){return{restrict:"E",transclude:!0,replace:!0,template:''}}]),c.directive("ionNavBackButton",["$animate",function(e){return{restrict:"E",require:"^ionNavBar",compile:function(t){return t.addClass("button back-button ng-hide"),function(t,n,i,r){i.ngClick||(t.$navBack=r.back,n.on("click",function(e){t.$apply(function(){t.$navBack(e)})}));var o=t.$parent.$on("$viewHistory.historyChange",function(e,n){t.hasBackButton=!!n.showBack});t.$on("$destroy",o),t.$watch("!!(backButtonShown && hasBackButton)",ionic.animationFrameThrottle(function(t){t?e.removeClass(n,"ng-hide"):e.addClass(n,"ng-hide")}))}}}}]),c.directive("ionNavBar",["$ionicViewService","$rootScope","$animate","$compile",function(){return{restrict:"E",controller:"$ionicNavBar",scope:!0,compile:function(e){function t(e,t,n,i){i._headerBarView=new ionic.views.HeaderBar({el:t[0],alignTitle:n.alignTitle||"center"}),e.backButtonShown=!1,e.shouldAnimate=!0,e.isReverse=!1,e.isInvisible=!0,e.$on("$destroy",function(){e.$parent.$hasHeader=!1}),e.$watch(function(){return(e.isReverse?" reverse":"")+(e.isInvisible?" invisible":"")+(e.shouldAnimate?"":" no-animation")},function(e,n){t.removeClass(n),t.addClass(e)})}return e.addClass("bar bar-header nav-bar").append('

'),{pre:t}}}}]),c.directive("ionNavButtons",["$compile","$animate",function(e,t){return{require:"^ionNavBar",restrict:"E",compile:function(n){var i=n.contents().remove();return function(n,r,o,a){var s="right"===o.side?a.rightButtonsElement:a.leftButtonsElement,c=angular.element("").append(i);r.append(c),e(c)(n),ionic.requestAnimationFrame(function(){t.enter(c,s)}),n.$on("$destroy",function(){t.leave(c)}),r.css("display","none")}}}}]),c.directive("navClear",["$ionicViewService","$state","$location","$window","$rootScope",function(e,t,n,i,r){return r.$on("$stateChangeError",function(){e.nextViewOptions(null)}),{priority:100,restrict:"AC",compile:function(){function t(t,n){function r(){o=t.$on("$stateChangeStart",function(){e.nextViewOptions({disableAnimate:!0,disableBack:!0}),o()}),i.setTimeout(o,300)}var o;n.on("click",r)}return{pre:t}}}}]),c.directive("ionNavView",["$ionicViewService","$state","$compile","$controller","$animate",function(e,t,n,i,r){var o=!1,a={restrict:"E",terminal:!0,priority:2e3,transclude:!0,controller:function(){},compile:function(s,c,l){return function(s,c,u){function d(o){r.enabled()===!1&&(o=!1);var a=t.$current&&t.$current.locals[p];if(a!==f){var l=e.getRenderer(c,u,s);if(h&&(h.$destroy(),h=null),!a)return f=null,$.state=null,c.append(g);var d=angular.element("
").html(a.$template).contents(),m=l().register(d);l(o).leave(),f=a,$.state=a.$$state,l(o).enter(d);var w=n(d);if(h=s.$new(),h.$navDirection=m.navDirection,a.$$controller){a.$scope=h;var b=i(a.$$controller,a);c.children().data("$ngControllerController",b)}w(h);var y=e._getViewById(m.viewId)||{};h.$broadcast("$viewContentLoaded",y),v&&h.$eval(v),d=null}}var h,f,p=u[a.name]||u.name||"",v=u.onload||"",g=l(s);c.append(g);var m=c.parent().inheritedData("$uiView");p.indexOf("@")<0&&(p=p+"@"+(m?m.state.name:""));var $={name:p,state:null};c.data("$uiView",$);var w=function(){if(!o){o=!0;try{d(!0)}catch(e){throw o=!1,e}o=!1}};s.$on("$stateChangeSuccess",w),d(!1)}}};return a}]),c.config(["$provide",function(e){e.decorator("ngClickDirective",["$delegate",function(e){return e.shift(),e}])}]).factory("$ionicNgClick",["$parse",function(e){return function(t,n,i){var r=e(i);n.on("click",function(e){t.$apply(function(){r(t,{$event:e})})}),n.onclick=function(){}}}]).directive("ngClick",["$ionicNgClick",function(e){return function(t,n,i){e(t,n,i.ngClick)}}]).directive("ionStopEvent",function(){return{restrict:"A",link:function(e,t,n){t.bind(n.ionStopEvent,a)}}}),c.directive("ionPane",function(){return{restrict:"E",link:function(e,t){t.addClass("pane")}}}),c.directive("ionRadio",function(){return{restrict:"E",replace:!0,require:"?ngModel",scope:{ngModel:"=?",ngValue:"=?",ngChange:"&",icon:"@",name:"@"},transclude:!0,template:'',compile:function(e,t){t.name&&e.children().eq(0).attr("name",t.name),t.icon&&e.children().eq(2).removeClass("ion-checkmark").addClass(t.icon)}}}),c.directive("ionRefresher",["$ionicBind",function(e){return{restrict:"E",replace:!0,require:"^$ionicScroll",template:'
',compile:function(t,n){return angular.isUndefined(n.pullingIcon)&&n.$set("pullingIcon","ion-arrow-down-c"),angular.isUndefined(n.refreshingIcon)&&n.$set("refreshingIcon","ion-loading-d"),function(t,n,i,r){e(t,i,{pullingIcon:"@",pullingText:"@",refreshingIcon:"@",refreshingText:"@",$onRefresh:"&onRefresh",$onPulling:"&onPulling"}),r._setRefresher(t,n[0]),t.$on("scroll.refreshComplete",function(){n[0].classList.remove("active"),r.scrollView.finishPullToRefresh()})}}}}]),c.directive("ionScroll",["$timeout","$controller","$ionicBind",function(e,t,n){return{restrict:"E",scope:!0,controller:function(){},compile:function(e){function i(e,i,o){var a,s;n(e,o,{direction:"@",paging:"@",$onScroll:"&onScroll",scroll:"@",scrollbarX:"@",scrollbarY:"@",zooming:"@",minZoom:"@",maxZoom:"@"}),angular.isDefined(o.padding)&&e.$watch(o.padding,function(e){r.toggleClass("padding",!!e)}),e.$eval(e.paging)===!0&&r.addClass("scroll-paging"),e.direction||(e.direction="y");var c=e.$eval(e.paging)===!0,l={el:i[0],delegateHandle:o.delegateHandle,paging:c,scrollbarX:e.$eval(e.scrollbarX)!==!1,scrollbarY:e.$eval(e.scrollbarY)!==!1,scrollingX:e.direction.indexOf("x")>=0,scrollingY:e.direction.indexOf("y")>=0,zooming:e.$eval(e.zooming)===!0,maxZoom:e.$eval(e.maxZoom)||3,minZoom:e.$eval(e.minZoom)||.5};c&&(l.speedMultiplier=.8,l.bouncing=!1),s=t("$ionicScroll",{$scope:e,scrollViewOptions:l}),a=e.$parent.scrollView=s.scrollView}e.addClass("scroll-view");var r=angular.element('
');return r.append(e.contents()),e.append(r),{pre:i}}}}]),c.directive("ionSideMenu",function(){return{restrict:"E",require:"^ionSideMenus",scope:!0,compile:function(e,t){return angular.isUndefined(t.isEnabled)&&t.$set("isEnabled","true"),angular.isUndefined(t.width)&&t.$set("width","275"),e.addClass("menu menu-"+t.side),function(e,t,n,i){e.side=n.side||"left";var r=i[e.side]=new ionic.views.SideMenu({width:275,el:t[0],isEnabled:!0});e.$watch(n.width,function(e){var t=+e;t&&t==e&&r.setWidth(+e)}),e.$watch(n.isEnabled,function(e){r.setIsEnabled(!!e)})}}}}),c.directive("ionSideMenuContent",["$timeout","$ionicGesture",function(e,t){return{restrict:"EA",require:"^ionSideMenus",scope:!0,compile:function(n,i){function r(n,r,o,a){function s(e){0!==a.getOpenAmount()&&(a.close(),e.gesture.srcEvent.preventDefault())}r.addClass("menu-content pane"),angular.isDefined(i.dragContent)?n.$watch(i.dragContent,function(e){a.canDragContent(e)}):a.canDragContent(!0);var c=!1,l=!1;ionic.on("tap",s,r[0]);var u=function(e){!c&&a.isDraggableTarget(e)&&(l=!0,a._handleDrag(e),e.gesture.srcEvent.preventDefault())},d=function(e){l&&e.gesture.srcEvent.preventDefault()},h=t.on("dragright",u,r),f=t.on("dragleft",u,r),p=t.on("dragup",d,r),v=t.on("dragdown",d,r),g=function(e){l=!1,c||a._endDrag(e),c=!1},m=t.on("release",g,r);a.setContent({onDrag:function(){},endDrag:function(){},getTranslateX:function(){return n.sideMenuContentTranslateX||0},setTranslateX:ionic.animationFrameThrottle(function(t){r[0].style[ionic.CSS.TRANSFORM]="translate3d("+t+"px, 0, 0)",e(function(){n.sideMenuContentTranslateX=t})}),enableAnimation:function(){n.animationEnabled=!0,r[0].classList.add("menu-animated")},disableAnimation:function(){n.animationEnabled=!1,r[0].classList.remove("menu-animated")}}),n.$on("$destroy",function(){t.off(f,"dragleft",u),t.off(h,"dragright",u),t.off(p,"dragup",u),t.off(v,"dragdown",u),t.off(m,"release",g),ionic.off("tap",s,r[0])})}return{pre:r}}}}]),c.directive("ionSideMenus",[function(){return{restrict:"ECA",replace:!0,transclude:!0,controller:"$ionicSideMenus",template:'
'}}]),c.directive("ionSlideBox",["$timeout","$compile","$ionicSlideBoxDelegate",function(e,t,n){return{restrict:"E",replace:!0,transclude:!0,scope:{doesContinue:"@",slideInterval:"@",showPager:"@",pagerClick:"&",disableScroll:"@",onSlideChanged:"&",activeSlide:"=?"},controller:["$scope","$element","$attrs",function(t,i,r){var o=t.$eval(t.doesContinue)===!0,a=o?t.$eval(t.slideInterval)||4e3:0,s=new ionic.views.Slider({el:i[0],auto:a,disableScroll:t.$eval(t.disableScroll)===!0||!1,continuous:o,startSlide:t.activeSlide,slidesChanged:function(){t.currentSlide=s.currentIndex(),e(function(){})},callback:function(n){t.currentSlide=n,t.onSlideChanged({index:t.currentSlide}),t.$parent.$broadcast("slideBox.slideChanged",n),t.activeSlide=n,e(function(){})}});t.$watch("activeSlide",function(e){angular.isDefined(e)&&s.slide(e)}),t.$on("slideBox.nextSlide",function(){s.next()}),t.$on("slideBox.prevSlide",function(){s.prev()}),t.$on("slideBox.setSlide",function(e,t){s.slide(t)}),this.__slider=s;var c=n._registerInstance(s,r.delegateHandle);t.$on("$destroy",c),this.slidesCount=function(){return s.slidesCount()},this.onPagerClick=function(e){t.pagerClick({index:e})},e(function(){s.load()})}],template:'
',link:function(e,n){if(e.$eval(e.showPager)!==!1){var i=e.$new(),r=angular.element("");n.append(r),t(r)(i)}}}}]).directive("ionSlide",function(){return{restrict:"E",require:"^ionSlideBox",compile:function(e){return e.addClass("slider-slide"),function(){}}}}).directive("ionPager",function(){return{restrict:"E",replace:!0,require:"^ionSlideBox",template:'
',link:function(e,t,n,i){var r=function(e){for(var n=t[0].children,i=n.length,r=0;i>r;r++)r==e?n[r].classList.add("active"):n[r].classList.remove("active")};e.pagerClick=function(e){i.onPagerClick(e)},e.numSlides=function(){return new Array(i.slidesCount())},e.$watch("currentSlide",function(e){r(e)})}}}),c.directive("ionTab",["$rootScope","$animate","$ionicBind","$compile",function(e,t,n,i){function r(e,t){return angular.isDefined(t)?" "+e+'="'+t+'"':""}return{restrict:"E",require:["^ionTabs","ionTab"],replace:!0,controller:"$ionicTab",scope:!0,compile:function(e,o){var a="",s=angular.element('
').append(e.contents().remove());return function(e,r,o,c){function l(){f.tabMatchesState()&&h.select(e)}var u,d,h=c[0],f=c[1],p=s[0].querySelector("ion-nav-view")||s[0].querySelector("data-ion-nav-view"),v=p&&p.getAttribute("name");n(e,o,{animate:"=",onSelect:"&",onDeselect:"&",title:"@",uiSref:"@",href:"@"}),h.add(e),e.$on("$destroy",function(){h.remove(e),g.isolateScope().$destroy(),g.remove()}),r[0].removeAttribute("title"),v&&(f.navViewName=v),e.$on("$stateChangeSuccess",l),l();var g=angular.element(a);g.data("$ionTabsController",h),g.data("$ionTabController",f),h.$tabsElement.append(i(g)(e)),e.$watch("$tabSelected",function(n){u&&u.$destroy(),u=null,d&&t.leave(d),d=null,n&&(u=e.$new(),d=s.clone(),t.enter(d,h.$element),i(d)(u))})}}}}]),c.directive("ionTabNav",[function(){return{restrict:"E",replace:!0,require:["^ionTabs","^ionTab"],template:'{{badge}}',scope:{title:"@",icon:"@",iconOn:"@",iconOff:"@",badge:"=",badgeStyle:"@"},compile:function(){return function(e,t,n,i){var r=i[0],o=i[1];t[0].removeAttribute("title"),e.selectTab=function(e){e.preventDefault(),r.select(o.$scope,!0)},n.ngClick||t.on("click",function(t){e.$apply(function(){e.selectTab(t)})}),e.getIconOn=function(){return e.iconOn||e.icon},e.getIconOff=function(){return e.iconOff||e.icon},e.isTabActive=function(){return r.selectedTab()===o.$scope}}}}}]),c.directive("ionTabs",["$ionicViewService","$ionicTabsDelegate",function(e,t){return{restrict:"E",scope:!0,controller:"$ionicTabs",compile:function(e){function n(e,n,i,r){var o=t._registerInstance(r,i.delegateHandle);e.$on("$destroy",o),r.$scope=e,r.$element=n,r.$tabsElement=angular.element(n[0].querySelector(".tabs"));var a=n[0];e.$watch(function(){return a.className},function(t){var n=-1!==t.indexOf("tabs-top"),i=-1!==t.indexOf("tabs-item-hide");e.$hasTabs=!n&&!i,e.$hasTabsTop=n&&!i}),e.$on("$destroy",function(){delete e.$hasTabs,delete e.$hasTabsTop})}e.addClass("view");var i=angular.element('
');return i.append(e.contents()),e.append(i),{pre:n}}}}]),c.directive("ionToggle",["$ionicGesture","$timeout",function(){return{restrict:"E",replace:!0,require:"?ngModel",scope:{ngModel:"=?",ngValue:"=?",ngChecked:"=?",ngChange:"&",ngDisabled:"=?"},transclude:!0,template:'
',compile:function(e,t){var n=e.find("input");return t.name&&n.attr("name",t.name),t.ngChecked&&n.attr("ng-checked","ngChecked"),t.ngTrueValue&&n.attr("ng-true-value",t.ngTrueValue),t.ngFalseValue&&n.attr("ng-false-value",t.ngFalseValue),function(e,t){var n,i,r,o;n=t[0].getElementsByTagName("label")[0],i=n.children[0],r=n.children[1],o=r.children[0];var a=angular.element(i).controller("ngModel");e.toggle=new ionic.views.Toggle({el:n,track:r,checkbox:i,handle:o,onChange:function(){a.$setViewValue(i.checked?!0:!1),e.$apply()}}),e.$on("$destroy",function(){e.toggle.destroy()})}}}}]),c.directive("ionView",["$ionicViewService","$rootScope","$animate",function(){return{restrict:"EA",priority:1e3,require:"^?ionNavBar",compile:function(e){return e.addClass("pane"),e[0].removeAttribute("title"),function(e,t,n,i){if(i){if(angular.isDefined(n.title)){var r=n.title;i.changeTitle(r,e.$navDirection),n.$observe("title",function(e){e!==r&&i.setTitle(e)})}var o=angular.isDefined(n.hideBackButton)?n.hideBackButton:"false";e.$watch(o,function(e){i.showBackButton(!e)});var a=angular.isDefined(n.hideNavBar)?n.hideNavBar:"false";e.$watch(a,function(e){i.showBar(!e)})}}}}}])}(); \ No newline at end of file +!function(){function e(e){var t,n=typeof e;return"object"==n&&null!==e?"function"==typeof(t=e.$$hashKey)?t=e.$$hashKey():void 0===t&&(t=e.$$hashKey=ionic.Utils.nextUid()):t=e,n+":"+t}function t(e){if(e.$root!==e){var t=e.$parent;e.$$disconnected=!0,t.$$childHead===e&&(t.$$childHead=e.$$nextSibling),t.$$childTail===e&&(t.$$childTail=e.$$prevSibling),e.$$prevSibling&&(e.$$prevSibling.$$nextSibling=e.$$nextSibling),e.$$nextSibling&&(e.$$nextSibling.$$prevSibling=e.$$prevSibling),e.$$nextSibling=e.$$prevSibling=null}}function n(e){if(e.$root!==e&&e.$$disconnected){var t=e.$parent;e.$$disconnected=!1,e.$$prevSibling=t.$$childTail,t.$$childHead?(t.$$childTail.$$nextSibling=e,t.$$childTail=e):t.$$childHead=t.$$childTail=e}}function i(e){return["$log",function(t){function n(e){this.handle=e}var i=this,r=this._instances=[];this._registerInstance=function(e,t){return e.$$delegateHandle=t,r.push(e),function(){var t=r.indexOf(e);-1!==t&&r.splice(t,1)}},this.$getByHandle=function(e){return e?new n(e):i},e.forEach(function(e){n.prototype[e]=function(){var n,i,o=this.handle,a=arguments,s=0;return r.forEach(function(t){t.$$delegateHandle===o&&(s++,i=t[e].apply(t,a),1===s&&(n=i))}),s?n:t.warn('Delegate for handle "'+this.handle+'" could not find a corresponding element with delegate-handle="'+this.handle+'"! '+e+"() was not called!\nPossible cause: If you are calling "+e+'() immediately, and your element with delegate-handle="'+this.handle+'" is a child of your controller, then your element may not be compiled yet. Put a $timeout around your call to '+e+"() and try again.")},i[e]=function(){var t,n,i=arguments;return r.forEach(function(r,o){n=r[e].apply(r,i),0===o&&(t=n)}),t}})}]}function r(){return["$ionicScrollDelegate",function(e){return{restrict:"E",link:function(t,n){function i(t){for(var i=3,r=t.target;i--&&r;){if(r.classList.contains("button")||r.tagName.match(/input|textarea|select/i)||r.isContentEditable)return;r=r.parentNode}var o=t.gesture&&t.gesture.touches[0]||t.detail.touches[0],a=n[0].getBoundingClientRect();ionic.DomUtil.rectContains(o.pageX,o.pageY,a.left,a.top-20,a.left+a.width,a.top+a.height)&&e.scrollTop(!0)}ionic.on("tap",i,n[0]),t.$on("$destroy",function(){ionic.off("tap",i,n[0])})}}}]}function o(e){return[function(){return{restrict:"E",compile:function(t){function n(t,n,i){var r=(new ionic.views.HeaderBar({el:n[0],alignTitle:i.alignTitle||"center"}),n[0]);e?(t.$watch(function(){return r.className},function(e){var n=-1!==e.indexOf("bar-subheader");t.$hasHeader=!n,t.$hasSubheader=n}),t.$on("$destroy",function(){delete t.$hasHeader,delete t.$hasSubheader})):(t.$watch(function(){return r.className},function(e){var n=-1!==e.indexOf("bar-subfooter");t.$hasFooter=!n,t.$hasSubfooter=n}),t.$on("$destroy",function(){delete t.$hasFooter,delete t.$hasSubfooter}),t.$watch("$hasTabs",function(e){n.toggleClass("has-tabs",!!e)}))}return t.addClass(e?"bar bar-header":"bar bar-footer"),{pre:n}}}}]}function a(e){e.stopPropagation()}var s={method:function(e,t,n){var i=!1;return function(){return i||(i=!0,t(e)),n.apply(this,arguments)}},field:function(e,t,n,i,r){var o=!1,a=function(){return o||(o=!0,t(e)),r},s=function(n){return o||(o=!0,t(e)),r=n,n};Object.defineProperty(n,i,{get:a,set:s,enumerable:!0})}},c=angular.module("ionic",["ngAnimate","ngSanitize","ui.router"]);c.factory("$ionicActionSheet",["$rootScope","$document","$compile","$animate","$timeout","$ionicTemplateLoader","$ionicPlatform",function(e,t,n,i,r,o,a){return{show:function(o){var s=e.$new(!0);angular.extend(s,{cancel:angular.noop,buttonClicked:angular.noop,destructiveButtonClicked:angular.noop},o);var c=n('')(s),l=angular.element(c[0].querySelector(".action-sheet-wrapper")),u=function(e){l.removeClass("action-sheet-up"),e&&r(function(){o.cancel()},200),i.removeClass(c,"active",function(){s.$destroy()}),t[0].body.classList.remove("action-sheet-open"),s.$deregisterBackButton&&s.$deregisterBackButton()};s.$deregisterBackButton=a.registerBackButtonAction(function(){u()},v),s.cancel=function(){u(!0)},s.buttonClicked=function(e){(o.buttonClicked&&o.buttonClicked(e))===!0&&u(!1)},s.destructiveButtonClicked=function(){(o.destructiveButtonClicked&&o.destructiveButtonClicked())===!0&&u(!1)},t[0].body.appendChild(c[0]),t[0].body.classList.add("action-sheet-open");var d=new ionic.views.ActionSheet({el:c[0]});return s.sheet=d,i.addClass(c,"active"),r(function(){l.addClass("action-sheet-up")},20),d}}}]),angular.element.prototype.addClass=function(e){var t,n,i,r,o,a;if(e&&"ng-scope"!=e&&"ng-isolate-scope"!=e)for(t=0;t'),r=0;return e[0].body.appendChild(i[0]),{retain:t,release:n,_element:i}}]),c.factory("$ionicBind",["$parse","$interpolate",function(e,t){var n=/^\s*([@=&])(\??)\s*(\w*)\s*$/;return function(i,r,o){angular.forEach(o||{},function(o,a){var s,c,l=o.match(n)||[],u=l[3]||a,d=l[1];switch(d){case"@":if(!r[u])return;r.$observe(u,function(e){i[a]=e}),r[u]&&(i[a]=t(r[u])(i));break;case"=":if(!r[u])return;c=i.$watch(r[u],function(e){i[a]=e}),i.$on("$destroy",c);break;case"&":if(r[u]&&r[u].match(RegExp(a+"(.*?)")))throw new Error('& expression binding "'+a+'" looks like it will recursively call "'+r[u]+'" and cause a stack overflow! Please choose a different scopeName.');s=e(r[u]),i[a]=function(e){return s(i,e)}}})}}]),c.factory("$collectionDataSource",["$cacheFactory","$parse",function(i,r){function o(t){var n=this;if(this.scope=t.scope,this.transcludeFn=t.transcludeFn,this.transcludeParent=t.transcludeParent,this.keyExpr=t.keyExpr,this.listExpr=t.listExpr,this.trackByExpr=t.trackByExpr,this.heightGetter=t.heightGetter,this.widthGetter=t.widthGetter,this.dimensions=[],this.data=[],this.trackByExpr){var o=r(this.trackByExpr),s={$id:e};this.itemHashGetter=function(e,t){return s[n.keyExpr]=t,s.$index=e,o(n.scope,s)}}else this.itemHashGetter=function(t,n){return e(n)};var c={};this.itemCache=i(a++,{size:500});var l=this.itemCache.put;this.itemCache.put=function(e,t){return c[e]=!0,l(e,t)};var u=this.itemCache.remove;this.itemCache.remove=function(e){return delete c[e],u(e)},this.itemCache.keys=function(){return Object.keys(c)}}var a=0;return o.prototype={destroy:function(){this.dimensions.length=0,this.itemCache.keys().forEach(function(e){var t=this.itemCache.get(e);t.element.remove(),t.scope.$destroy()},this),this.itemCache.removeAll()},calculateDataDimensions:function(){var e={};this.dimensions=this.data.map(function(t,n){return e[this.keyExpr]=t,e.$index=n,{width:this.widthGetter(this.scope,e),height:this.heightGetter(this.scope,e)}},this)},compileItem:function(e,t){var n=this.itemHashGetter(e,t),i=this.itemCache.get(n);if(i)return i;var r={};return r.scope=this.scope.$new(),r.scope[this.keyExpr]=t,this.transcludeFn(r.scope,function(e){r.element=e,r.element[0].style.position="absolute"}),this.itemCache.put(n,r)},getItem:function(e){var t=this.data[e],n=this.compileItem(e,t);return n.scope.$index!==e&&(n.scope.$index=e,n.scope.$first=0===e,n.scope.$last=e===this.getLength()-1,n.scope.$middle=!(n.scope.$first||n.scope.$last),n.scope.$odd=!(n.scope.$even=0===(1&e))),n},detachItem:function(e){var n,i,r;for(n=0;ni&&(n=0,t+=e.primarySize)),o.primaryPos=t,o.secondaryPos=n,e=o,o},this)},resize:function(){this.dimensions=this.calculateDimensions();var e=this.dimensions[this.dimensions.length-1];this.viewportSize=e?e.primaryPos+e.primarySize:0,this.setCurrentIndex(0),this.render(!0)},setCurrentIndex:function(e){this.currentIndex=e,this.hasPrevIndex=e>0,this.hasPrevIndex&&(this.previousPos=this.dimensions[e-1].primaryPos),this.hasNextIndex=e+1=this.nextPos||this.hasPrevIndex&&e100)&&this.render(),e-this.lastRenderScrollValue},getIndexForScrollValue:function(e,t){var n;if(t<=this.dimensions[e].primaryPos)for(;(n=this.dimensions[e-1])&&n.primaryPos>t;)e--;else for(;(n=this.dimensions[e+1])&&n.primaryPos=this.dataSource.getLength()||e){for(t in this.renderedItems)this.removeItem(t);if(this.currentIndex>=this.dataSource.getLength())return null}for(var n,i=this.scrollValue(),r=(i-this.lastRenderScrollValue,this.scrollSize()),o=r+i,a=this.getIndexForScrollValue(this.currentIndex,i),s=Math.max(a-1,0);s>0&&(n=this.dimensions[s])&&n.primaryPos===this.dimensions[a-1].primaryPos;)s--;var c=this.dimensions[s].primaryPos;for(t=s;(n=this.dimensions[t])&&n.primaryPos-n.primarySizet||t>l)&&this.removeItem(t);this.setCurrentIndex(a),this.lastRenderScrollValue=c},renderItem:function(e,t,n){var i=this.dataSource.getItem(e);i?(this.dataSource.attachItem(i),i.element[0].style[ionic.CSS.TRANSFORM]=this.transformString(t,n,n),this.renderedItems[e]=i):delete this.renderedItems[e]},removeItem:function(e){var t=this.renderedItems[e];t&&(this.dataSource.detachItem(t),delete this.renderedItems[e])}},e}]),c.factory("$ionicGesture",[function(){return{on:function(e,t,n){return window.ionic.onGesture(e,t,n[0])},off:function(e,t,n){return window.ionic.offGesture(e,t,n)}}}]);var l='
',u="$ionicLoading instance.hide() has been deprecated. Use $ionicLoading.hide().",d="$ionicLoading instance.show() has been deprecated. Use $ionicLoading.show().",h="$ionicLoading instance.setContent() has been deprecated. Use $ionicLoading.show({ template: 'my content' }).";c.factory("$ionicLoading",["$document","$ionicTemplateLoader","$ionicBackdrop","$timeout","$q","$log","$compile","$ionicPlatform",function(e,t,n,i,r,o,a,c){function f(){return g||(g=t.compile({template:l,appendTo:e[0].body}).then(function(e){var o=e;return e.show=function(e){var s=e.templateUrl?t.load(e.templateUrl):r.when(e.template||e.content||"");this.isShown||(this.hasBackdrop=!e.noBackdrop&&e.showBackdrop!==!1,this.hasBackdrop&&n.retain()),e.duration&&(i.cancel(this.durationTimeout),this.durationTimeout=i(angular.bind(this,this.hide),+e.duration)),s.then(function(e){e&&(o.element.html(e),a(o.element.contents())(o.scope)),o.isShown&&(o.element.addClass("visible"),ionic.DomUtil.centerElementByMarginTwice(o.element[0]),ionic.requestAnimationFrame(function(){o.isShown&&o.element.addClass("active")}))}),this.isShown=!0},e.hide=function(){this.isShown&&(this.hasBackdrop&&n.release(),o.element.removeClass("active"),setTimeout(function(){!o.isShown&&o.element.removeClass("visible")},200)),i.cancel(this.durationTimeout),this.isShown=!1},e})),g}function p(e){e||(e={});var t=e.delay||e.showDelay||0;return w&&i.cancel(w),w=i(angular.noop,t),w.then(f).then(function(t){return $(),$=c.registerBackButtonAction(angular.noop,m),t.show(e)}),{hide:s.method(u,o.error,v),show:s.method(d,o.error,function(){p(e)}),setContent:s.method(h,o.error,function(e){f().then(function(t){t.show({template:e})})})}}function v(){$(),i.cancel(w),f().then(function(e){e.hide()})}var g,$=angular.noop,w=r.when();return{show:p,hide:v,_getLoader:f}}]),c.factory("$ionicModal",["$rootScope","$document","$compile","$timeout","$ionicPlatform","$ionicTemplateLoader","$q",function(e,t,n,i,r,o,a){var s=ionic.views.Modal.inherit({initialize:function(e){ionic.views.Modal.prototype.initialize.call(this,e),this.animation=e.animation||"slide-in-up"},show:function(){var e=this,n=angular.element(e.modalEl);return e.el.classList.remove("hide"),i(function(){t[0].body.classList.add("modal-open")},400),e.el.parentElement||(n.addClass(e.animation),t[0].body.appendChild(e.el)),n.addClass("ng-enter active").removeClass("ng-leave ng-leave-active"),e._isShown=!0,e._deregisterBackButton=r.registerBackButtonAction(function(){e.hide()},200),e._isOpenPromise=a.defer(),ionic.views.Modal.prototype.show.call(e),i(function(){n.addClass("ng-enter-active"),e.scope.$parent&&e.scope.$parent.$broadcast("modal.shown",e),e.el.classList.add("active")},20),i(function(){e.$el.on("click",function(t){t.target===e.el&&e.hide()})},400)},hide:function(){var e=this,n=angular.element(e.modalEl);return e.el.classList.remove("active"),n.addClass("ng-leave"),i(function(){n.addClass("ng-leave-active").removeClass("ng-enter ng-enter-active active")},20),e.$el.off("click"),e._isShown=!1,e.scope.$parent&&e.scope.$parent.$broadcast("modal.hidden",e),e._deregisterBackButton&&e._deregisterBackButton(),ionic.views.Modal.prototype.hide.call(e),i(function(){t[0].body.classList.remove("modal-open"),e.el.classList.add("hide")},500)},remove:function(){var e=this;return e.scope.$parent&&e.scope.$parent.$broadcast("modal.removed",e),e.hide().then(function(){e.scope.$destroy(),e.$el.remove()})},isShown:function(){return!!this._isShown}}),c=function(t,i){var r=i.scope&&i.scope.$new()||e.$new(!0);angular.extend(r,{$hasHeader:!1,$hasSubheader:!1,$hasFooter:!1,$hasSubfooter:!1,$hasTabs:!1,$hasTabsTop:!1});var o=n(""+t+"")(r);i.$el=o,i.el=o[0],i.modalEl=i.el.querySelector(".modal");var a=new s(i);return a.scope=r,i.scope||(r.modal=a),a};return{fromTemplate:function(e,t){var n=c(e,t||{});return n},fromTemplateUrl:function(e,t,n){var i;return angular.isFunction(t)&&(i=t,t=n),o.load(e).then(function(e){var n=c(e,t||{});return i&&i(n),n})}}}]),c.service("$ionicNavBarDelegate",i(["back","align","showBackButton","showBar","setTitle","changeTitle","getTitle","getPreviousTitle"]));var f=100,p=150,v=300,g=400,m=500;c.provider("$ionicPlatform",function(){return{$get:["$q","$rootScope",function(e){var t={onHardwareBackButton:function(e){ionic.Platform.ready(function(){document.addEventListener("backbutton",e,!1)})},offHardwareBackButton:function(e){ionic.Platform.ready(function(){document.removeEventListener("backbutton",e)})},$backButtonActions:{},registerBackButtonAction:function(e,n,i){t._hasBackButtonHandler||(t.$backButtonActions={},t.onHardwareBackButton(t.hardwareBackButtonClick),t._hasBackButtonHandler=!0);var r={id:i?i:ionic.Utils.nextUid(),priority:n?n:0,fn:e};return t.$backButtonActions[r.id]=r,function(){delete t.$backButtonActions[r.id]}},hardwareBackButtonClick:function(e){var n,i;for(i in t.$backButtonActions)(!n||t.$backButtonActions[i].priority>=n.priority)&&(n=t.$backButtonActions[i]);return n?(n.fn(e),n):void 0},is:function(e){return ionic.Platform.is(e)},ready:function(t){var n=e.defer();return ionic.Platform.ready(function(){n.resolve(),t&&t()}),n.promise}};return t}]}});var $='';c.factory("$ionicPopup",["$ionicTemplateLoader","$ionicBackdrop","$q","$timeout","$rootScope","$document","$compile","$ionicPlatform",function(e,t,n,i,r,o,a,s){function c(t){t=angular.extend({scope:null,title:"",buttons:[]},t||{});var r=e.compile({template:$,scope:t.scope&&t.scope.$new(),appendTo:o[0].body}),s=t.templateUrl?e.load(t.templateUrl):n.when(t.template||t.content||"");return n.all([r,s]).then(function(e){var r=e[0],o=e[1],s=n.defer();r.responseDeferred=s;var c=angular.element(r.element[0].querySelector(".popup-body"));return o?(c.html(o),a(c.contents())(r.scope)):c.remove(),angular.extend(r.scope,{title:t.title,buttons:t.buttons,subTitle:t.subTitle,$buttonTapped:function(e,t){var n=(e.onTap||angular.noop)(t);t=t.originalEvent||t,t.defaultPrevented||s.resolve(n)}}),r.show=function(){r.isShown||(r.isShown=!0,ionic.requestAnimationFrame(function(){r.isShown&&(r.element.removeClass("popup-hidden"),r.element.addClass("popup-showing active"),ionic.DomUtil.centerElementByMarginTwice(r.element[0]),d(r.element))}))},r.hide=function(e){return e=e||angular.noop,r.isShown?(r.isShown=!1,r.element.removeClass("active"),r.element.addClass("popup-hidden"),void i(e,250)):e()},r.remove=function(){r.removed||(r.hide(function(){r.element.remove(),r.scope.$destroy()}),r.removed=!0)},r})}function l(){m[0]&&m[0].responseDeferred.resolve()}function u(e){function n(e){r.then(function(t){t.removed||t.responseDeferred.resolve(e)})}var r=w._createPopup(e),o=m[0];o&&o.hide();var a=i(angular.noop,o?v.stackPushDelay:0).then(function(){return r}).then(function(e){return o||(document.body.classList.add("popup-open"),t.retain(),w._backButtonActionDone=s.registerBackButtonAction(l,g)),m.unshift(e),e.show(),e.responseDeferred.notify({close:a.close}),e.responseDeferred.promise.then(function(n){var i=m.indexOf(e);-1!==i&&m.splice(i,1),e.remove();var r=m[0];return r?r.show():(document.body.classList.remove("popup-open"),t.release(),(w._backButtonActionDone||angular.noop)()),n})});return a.close=n,a}function d(e){var t=e[0].querySelectorAll("input");t.length||(t=e[0].querySelectorAll("button"));var n=t[t.length-1];n&&n.focus()}function h(e){return u(angular.extend({buttons:[{text:e.okText||"OK",type:e.okType||"button-positive",onTap:function(){return!0}}]},e||{}))}function f(e){return u(angular.extend({buttons:[{text:e.cancelText||"Cancel",type:e.cancelType||"button-default",onTap:function(){return!1}},{text:e.okText||"OK",type:e.okType||"button-positive",onTap:function(){return!0}}]},e||{}))}function p(e){var t=r.$new(!0);return t.data={},u(angular.extend({template:'',scope:t,buttons:[{text:e.cancelText||"Cancel",type:e.cancelType||"button-default",onTap:function(){}},{text:e.okText||"OK",type:e.okType||"button-positive",onTap:function(){return t.data.response||""}}]},e||{}))}var v={stackPushDelay:50},m=[],w={show:u,alert:h,confirm:f,prompt:p,_createPopup:c,_popupStack:m};return w}]),c.service("$ionicScrollDelegate",i(["resize","scrollTop","scrollBottom","scrollTo","scrollBy","getScrollPosition","anchorScroll","getScrollView","rememberScrollPosition","forgetScrollPosition","scrollToRememberedPosition"])),c.service("$ionicSideMenuDelegate",i(["toggleLeft","toggleRight","getOpenRatio","isOpen","isOpenLeft","isOpenRight","canDragContent"])),c.service("$ionicSlideBoxDelegate",i(["update","slide","enableSlide","previous","next","stop","currentIndex","slidesCount"])),c.service("$ionicTabsDelegate",i(["select","selectedIndex"])),c.factory("$ionicTemplateLoader",["$compile","$controller","$http","$q","$rootScope","$templateCache",function(e,t,n,i,r,o){function a(e){return n.get(e,{cache:o}).then(function(e){return e.data&&e.data.trim()})}function s(n){n=angular.extend({template:"",templateUrl:"",scope:null,controller:null,locals:{},appendTo:null},n||{});var o=n.templateUrl?this.load(n.templateUrl):i.when(n.template);return o.then(function(i){var o,a=n.scope||r.$new(),s=angular.element("
").html(i).contents();return n.controller&&(o=t(n.controller,angular.extend(n.locals,{$scope:a})),s.children().data("$ngControllerController",o)),n.appendTo&&angular.element(n.appendTo).append(s),e(s)(a),{element:s,scope:a}})}return{load:a,compile:s}}]),c.run(["$rootScope","$state","$location","$document","$animate","$ionicPlatform","$ionicViewService",function(e,t,n,i,r,o,a){function s(t){return e.$viewHistory.backView?e.$viewHistory.backView.go():ionic.Platform.exitApp(),t.preventDefault(),!1}e.$viewHistory={histories:{root:{historyId:"root",parentHistoryId:null,stack:[],cursor:-1}},views:{},backView:null,forwardView:null,currentView:null,disabledRegistrableTagNames:[]},a.disableRegisterByTagName&&(a.disableRegisterByTagName("ion-tabs"),a.disableRegisterByTagName("ion-side-menus")),e.$on("viewState.changeHistory",function(i,r){if(r){var o=r.historyId?e.$viewHistory.histories[r.historyId]:null;if(o&&o.cursor>-1&&o.cursor-1&&s.stack.length>0&&s.cursor=u.index;v--)p.stack[v].destroy(),p.stack.splice(v)}}else h.navAction="initialView";r.views[h.viewId]=this.createView({viewId:h.viewId,index:s.stack.length,historyId:s.historyId,backViewId:c&&c.viewId?c.viewId:null,forwardViewId:null,stateId:o,stateName:this.getCurrentStateName(),stateParams:this.getCurrentStateParams(),url:n.url()}),"moveBack"==h.navAction&&e.$emit("$viewHistory.viewBack",c.viewId,h.viewId),s.stack.push(r.views[h.viewId])}return d&&(d.disableAnimate&&(h.navDirection=null),d.disableBack&&(r.views[h.viewId].backViewId=null),this.nextViewOptions(null)),this.setNavViews(h.viewId),s.cursor=r.currentView.index,h},setNavViews:function(t){var n=e.$viewHistory;n.currentView=this._getViewById(t),n.backView=this._getBackView(n.currentView),n.forwardView=this._getForwardView(n.currentView),e.$broadcast("$viewHistory.historyChange",{showBack:n.backView&&n.backView.historyId===n.currentView.historyId})},registerHistory:function(e){e.$historyId=ionic.Utils.nextUid()},createView:function(e){var t=new s;return t.initialize(e)},getCurrentView:function(){return e.$viewHistory.currentView},getBackView:function(){return e.$viewHistory.backView},getForwardView:function(){return e.$viewHistory.forwardView},getNavDirection:function(){return e.$viewHistory.navDirection},getCurrentStateName:function(){return t&&t.current?t.current.name:null},isCurrentStateNavView:function(e){return t&&t.current&&t.current.views&&t.current.views[e]?!0:!1},getCurrentStateParams:function(){var e;if(t&&t.params)for(var n in t.params)t.params.hasOwnProperty(n)&&(e=e||{},e[n]=t.params[n]);return e},getCurrentStateId:function(){var e;if(t&&t.current&&t.current.name){if(e=t.current.name,t.params)for(var n in t.params)t.params.hasOwnProperty(n)&&t.params[n]&&(e+="_"+n+"="+t.params[n]);return e}return ionic.Utils.nextUid()},goToHistoryRoot:function(t){if(t){var n=e.$viewHistory.histories[t];if(n&&n.stack.length){if(e.$viewHistory.currentView&&e.$viewHistory.currentView.viewId===n.stack[0].viewId)return;e.$viewHistory.forcedNav={viewId:n.stack[0].viewId,navAction:"moveBack",navDirection:"back"},n.stack[0].go()}}},_getViewById:function(t){return t?e.$viewHistory.views[t]:null},_getBackView:function(e){return e?this._getViewById(e.backViewId):null},_getForwardView:function(e){return e?this._getViewById(e.forwardViewId):null},_getHistoryById:function(t){return t?e.$viewHistory.histories[t]:null},_getHistory:function(t){var n=this._getParentHistoryObj(t);return e.$viewHistory.histories[n.historyId]||(e.$viewHistory.histories[n.historyId]={historyId:n.historyId,parentHistoryId:this._getParentHistoryObj(n.scope.$parent).historyId,stack:[],cursor:-1}),e.$viewHistory.histories[n.historyId]},_getParentHistoryObj:function(t){for(var n=t;n;){if(n.hasOwnProperty("$historyId"))return{historyId:n.$historyId,scope:n};n=n.$parent}return{historyId:"root",scope:e}},nextViewOptions:function(e){return arguments.length?void(this._nextOpts=e):this._nextOpts},getRenderer:function(e,t,n){function i(e){for(var t="";!t&&e;)t=e.getAttribute("animation"),e=e.parentElement;return t}function r(){l&&e[0].classList.add(l),"back"===a.navDirection?e[0].classList.add("reverse"):e[0].classList.remove("reverse")}var a,s,c=this,l=i(e[0]);return function(t){return{enter:function(n){return s&&t?(r(),n.addClass("ng-enter"),document.body.classList.add("disable-pointer-events"),void o.enter(n,e,null,function(){document.body.classList.remove("disable-pointer-events"),l&&e[0].classList.remove(l)})):void e.append(n)},leave:function(){var n=e.contents();return s&&t?(r(),void o.leave(n,function(){n.remove()})):void n.remove()},register:function(e){return a=c.register(n,e),s=null!==l&&null!==a.navDirection,a}}}},disableRegisterByTagName:function(t){e.$viewHistory.disabledRegistrableTagNames.push(t.toUpperCase())},isTagNameRegistrable:function(t){var n,i,r=e.$viewHistory.disabledRegistrableTagNames;for(n=0;n')(e),angular.element(a[0]).replaceWith(n)),i=o('

')(e),ionic.requestAnimationFrame(function(){n&&r.leave(angular.element(n));var o=n&&angular.element(n)||null;r.enter(i,t,o,function(){c._headerBarView.align()}),angular.forEach(a,function(e){e&&e.parentNode&&angular.element(e).remove()}),e.$digest(),ionic.requestAnimationFrame(function(){i[0].classList.remove("invisible")})})}}]),c.factory("$$scrollValueCache",function(){return{}}).controller("$ionicScroll",["$scope","scrollViewOptions","$timeout","$window","$$scrollValueCache","$location","$rootScope","$document","$ionicScrollDelegate",function(e,t,n,i,r,o,a,s,c){var l=this;this._scrollViewOptions=t;var u=this.element=t.el,d=this.$element=angular.element(u),h=this.scrollView=new ionic.views.Scroll(t);(d.parent().length?d.parent():d).data("$$ionicScrollController",this);var f=c._registerInstance(this,t.delegateHandle);angular.isDefined(t.bouncing)||ionic.Platform.ready(function(){h.options.bouncing=!ionic.Platform.isAndroid()});var p=angular.bind(h,h.resize);ionic.on("resize",p,i);var v=angular.noop;e.$on("$destroy",function(){f(),ionic.off("resize",p,i),i.removeEventListener("resize",p),v(),l._rememberScrollId&&(r[l._rememberScrollId]=h.getValues())}),d.on("scroll",function(t){var n=(t.originalEvent||t).detail||{};e.$onScroll&&e.$onScroll({event:t,scrollTop:n.scrollTop||0,scrollLeft:n.scrollLeft||0})}),e.$on("$viewContentLoaded",function(e,t){if(!e.defaultPrevented){e.preventDefault();var i=t&&t.viewId;i&&n(function(){l.rememberScrollPosition(i),l.scrollToRememberedPosition(),v=a.$on("$viewHistory.viewBack",function(e,t){i===t&&l.forgetScrollPosition()})},1,!1)}}),n(function(){h.run()}),this._rememberScrollId=null,this.getScrollView=function(){return this.scrollView},this.getScrollPosition=function(){return this.scrollView.getValues()},this.resize=function(){return n(p)},this.scrollTop=function(e){this.resize().then(function(){h.scrollTo(0,0,!!e)})},this.scrollBottom=function(e){this.resize().then(function(){var t=h.getScrollMax();h.scrollTo(t.left,t.top,!!e)})},this.scrollTo=function(e,t,n){this.resize().then(function(){h.scrollTo(e,t,!!n)})},this.scrollBy=function(e,t,n){this.resize().then(function(){h.scrollBy(e,t,!!n)})},this.anchorScroll=function(e){this.resize().then(function(){var t=o.hash(),n=t&&s[0].getElementById(t);if(t&&n){var i=ionic.DomUtil.getPositionInParent(n,l.$element);h.scrollTo(i.left,i.top,!!e)}else h.scrollTo(0,0,!!e)})},this.rememberScrollPosition=function(e){if(!e)throw new Error("Must supply an id to remember the scroll by!");this._rememberScrollId=e},this.forgetScrollPosition=function(){delete r[this._rememberScrollId],this._rememberScrollId=null},this.scrollToRememberedPosition=function(e){var t=r[this._rememberScrollId];t&&this.resize().then(function(){h.scrollTo(+t.left,+t.top,e)})},this._setRefresher=function(e,t){var n=this.refresher=t,i=l.refresher.clientHeight||0;h.activatePullToRefresh(i,function(){n.classList.add("active"),e.$onPulling()},function(){n.classList.remove("refreshing"),n.classList.remove("active")},function(){n.classList.add("refreshing"),e.$onRefresh()})}}]),c.controller("$ionicSideMenus",["$scope","$attrs","$ionicSideMenuDelegate","$ionicPlatform",function(e,t,n,i){var r=this;angular.extend(this,ionic.controllers.SideMenuController.prototype),this.$scope=e,ionic.controllers.SideMenuController.call(this,{left:{width:275},right:{width:275}}),this.canDragContent=function(t){return arguments.length&&(e.dragContent=!!t),e.dragContent},this.isDraggableTarget=function(t){return e.dragContent&&!t.gesture.srcEvent.defaultPrevented&&!t.target.tagName.match(/input|textarea|select|object|embed/i)&&!t.target.isContentEditable&&!(t.target.dataset?t.target.dataset.preventScroll:"true"==t.target.getAttribute("data-prevent-default"))},e.sideMenuContentTranslateX=0;var o=angular.noop,a=angular.bind(this,this.close);e.$watch(function(){return 0!==r.getOpenAmount()},function(e){o(),e&&(o=i.registerBackButtonAction(a,p))});var s=n._registerInstance(this,t.delegateHandle);e.$on("$destroy",function(){s(),o()})}]),c.controller("$ionicTab",["$scope","$ionicViewService","$attrs","$location","$state",function(e,t,n,i,r){this.$scope=e,this.hrefMatchesState=function(){return n.href&&0===i.path().indexOf(n.href.replace(/^#/,"").replace(/\/$/,""))},this.srefMatchesState=function(){return n.uiSref&&r.includes(n.uiSref.split("(")[0])},this.navNameMatchesState=function(){return this.navViewName&&t.isCurrentStateNavView(this.navViewName)},this.tabMatchesState=function(){return this.hrefMatchesState()||this.srefMatchesState()||this.navNameMatchesState()}}]),c.controller("$ionicTabs",["$scope","$ionicViewService","$element",function(e,t){var n=null,i=this;i.tabs=[],i.selectedIndex=function(){return i.tabs.indexOf(n)},i.selectedTab=function(){return n},i.add=function(e){t.registerHistory(e),i.tabs.push(e),1===i.tabs.length&&i.select(e)},i.remove=function(e){var t=i.tabs.indexOf(e);if(-1!==t){if(e.$tabSelected)if(i.deselect(e),1===i.tabs.length);else{var n=t===i.tabs.length-1?t-1:t+1;i.select(i.tabs[n])}i.tabs.splice(t,1)}},i.deselect=function(e){e.$tabSelected&&(n=null,e.$tabSelected=!1,(e.onDeselect||angular.noop)())},i.select=function(r,o){var a;if(angular.isNumber(r)?(a=r,r=i.tabs[a]):a=i.tabs.indexOf(r),!r||-1==a)throw new Error('Cannot select tab "'+a+'"!');if(n&&n.$historyId==r.$historyId)o&&t.goToHistoryRoot(r.$historyId);else if(angular.forEach(i.tabs,function(e){i.deselect(e)}),n=r,r.$tabSelected=!0,(r.onSelect||angular.noop)(),o){var s={type:"tab",tabIndex:a,historyId:r.$historyId,navViewName:r.navViewName,hasNavView:!!r.navViewName,title:r.title,url:r.href,uiSref:r.uiSref};e.$emit("viewState.changeHistory",s)}}}]),c.directive("ionActionSheet",["$document",function(e){return{restrict:"E",scope:!0,replace:!0,link:function(t,n){var i=function(e){27==e.which&&(t.cancel(),t.$apply())},r=function(e){e.target==n[0]&&(t.cancel(),t.$apply())};t.$on("$destroy",function(){n.remove(),e.unbind("keyup",i)}),e.bind("keyup",i),n.bind("click",r)},template:'
'}}]),c.directive("ionCheckbox",function(){return{restrict:"E",replace:!0,require:"?ngModel",scope:{ngModel:"=?",ngValue:"=?",ngChecked:"=?",ngDisabled:"=?",ngChange:"&"},transclude:!0,template:'',compile:function(e,t){var n=e.find("input");t.name&&n.attr("name",t.name),t.ngChecked&&n.attr("ng-checked",t.ngChecked),t.ngDisabled&&n.attr("ng-disabled",t.ngDisabled),t.ngTrueValue&&n.attr("ng-true-value",t.ngTrueValue),t.ngFalseValue&&n.attr("ng-false-value",t.ngFalseValue)}}});var w="Cannot create a collection-repeat within a scrollView that is scrollable on both x and y axis. Choose either x direction or y direction.",b="collection-repeat expected attribute collection-item-height to be a an expression that returns a number (in pixels) or percentage.",y="collection-repeat expected attribute collection-item-width to be a an expression that returns a number (in pixels) or percentage.",S="collection-repeat expected expression in form of '_item_ in _collection_[ track by _id_]' but got '%'";c.directive("collectionRepeat",["$collectionRepeatManager","$collectionDataSource","$parse",function(e,t,n){return{priority:1e3,transclude:"element",terminal:!0,$$tlb:!0,require:"^$ionicScroll",link:function(i,r,o,a,s){function c(e){u.resize(),I.setData(e),C.resize()}function l(){c(i.$eval($))}var u=a.scrollView;if(u.options.scrollingX&&u.options.scrollingY)throw new Error(w);var d=!!u.options.scrollingY;if(d&&!o.collectionItemHeight)throw new Error(b);if(!d&&!o.collectionItemWidth)throw new Error(y);o.collectionItemHeight=o.collectionItemHeight||'"100%"',o.collectionItemWidth=o.collectionItemWidth||'"100%"';var h=o.collectionItemHeight?n(o.collectionItemHeight):function(){return u.__clientHeight},f=o.collectionItemWidth?n(o.collectionItemWidth):function(){return u.__clientWidth},p=function(e,t){var n=h(e,t);return angular.isString(n)&&n.indexOf("%")>-1?Math.floor(parseInt(n,10)/100*u.__clientHeight):n},v=function(e,t){var n=f(e,t);return angular.isString(n)&&n.indexOf("%")>-1?Math.floor(parseInt(n,10)/100*u.__clientWidth):n},g=o.collectionRepeat.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);if(!g)throw new Error(S.replace("%",o.collectionRepeat));var m=g[1],$=g[2],k=g[3],I=new t({scope:i,transcludeFn:s,transcludeParent:r.parent(),keyExpr:m,listExpr:$,trackByExpr:k,heightGetter:p,widthGetter:v}),C=new e({dataSource:I,element:a.$element,scrollView:a.scrollView});i.$watchCollection($,function(e){if(e&&!angular.isArray(e))throw new Error("collection-repeat expects an array to repeat over, but instead got '"+typeof e+"'.");c(e)}),ionic.on("resize",l,window),i.$on("$destroy",function(){C.destroy(),I.destroy(),ionic.off("resize",l,window)})}}}]),c.directive("ionContent",["$timeout","$controller","$ionicBind",function(e,t,n){return{restrict:"E",require:"^?ionNavView",scope:!0,priority:800,compile:function(e,i){function r(e,r,a){var s=e.$parent;e.$watch(function(){return(s.$hasHeader?" has-header":"")+(s.$hasSubheader?" has-subheader":"")+(s.$hasFooter?" has-footer":"")+(s.$hasSubfooter?" has-subfooter":"")+(s.$hasTabs?" has-tabs":"")+(s.$hasTabsTop?" has-tabs-top":"")},function(e,t){r.removeClass(t),r.addClass(e)}),e.$hasHeader=e.$hasSubheader=e.$hasFooter=e.$hasSubfooter=e.$hasTabs=e.$hasTabsTop=!1,n(e,a,{$onScroll:"&onScroll",$onScrollComplete:"&onScrollComplete",hasBouncing:"@",scroll:"@",padding:"@",hasScrollX:"@",hasScrollY:"@",scrollbarX:"@",scrollbarY:"@",startX:"@",startY:"@",scrollEventInterval:"@"}),angular.isDefined(a.padding)&&e.$watch(a.padding,function(e){(o||r).toggleClass("padding",!!e)}),"false"===e.scroll||("true"===i.overflowScroll?r.addClass("overflow-scroll"):t("$ionicScroll",{$scope:e,scrollViewOptions:{el:r[0],delegateHandle:i.delegateHandle,bouncing:e.$eval(e.hasBouncing),startX:e.$eval(e.startX)||0,startY:e.$eval(e.startY)||0,scrollbarX:e.$eval(e.scrollbarX)!==!1,scrollbarY:e.$eval(e.scrollbarY)!==!1,scrollingX:e.$eval(e.hasScrollX)===!0,scrollingY:e.$eval(e.hasScrollY)!==!1,scrollEventInterval:parseInt(e.scrollEventInterval,10)||10,scrollingComplete:function(){e.$onScrollComplete({scrollTop:this.__scrollTop,scrollLeft:this.__scrollLeft})}}}))}var o;return e.addClass("scroll-content"),"false"!=i.scroll&&(o=angular.element('
'),o.append(e.contents()),e.append(o)),{pre:r}}}}]),c.directive("ionNavBar",r()).directive("ionHeaderBar",r()).directive("ionHeaderBar",o(!0)).directive("ionFooterBar",o(!1)),c.directive("ionInfiniteScroll",["$timeout",function(e){function t(e,t,n){return n?t*(1-parseInt(e,10)/100):t-parseInt(e,10)}return{restrict:"E",require:["^$ionicScroll","ionInfiniteScroll"],template:'
',scope:!0,controller:["$scope","$attrs",function(e,n){this.isLoading=!1,this.scrollView=null,this.getMaxScroll=function(){var e=(n.distance||"1%").trim(),i=-1!==e.indexOf("%"),r=this.scrollView.getScrollMax();return{left:this.scrollView.options.scrollingX?t(e,r.left,i):-1,top:this.scrollView.options.scrollingY?t(e,r.top,i):-1}}}],link:function(t,n,i,r){function o(){if(!s.isLoading){var e=c.getValues(),t=s.getMaxScroll();(-1!==t.left&&e.left>=t.left||-1!==t.top&&e.top>=t.top)&&l()}}var a=r[0],s=r[1],c=s.scrollView=a.scrollView;t.icon=function(){return angular.isDefined(i.icon)?i.icon:"ion-loading-d"};var l=function(){n[0].classList.add("active"),s.isLoading=!0,t.$parent&&t.$parent.$apply(i.onInfinite||"")},u=function(){n[0].classList.remove("active"),e(function(){c.resize()},0,!1),s.isLoading=!1};t.$on("scroll.infiniteScrollComplete",function(){u()}),t.$on("$destroy",function(){a.$element.off("scroll",d)});var d=ionic.animationFrameThrottle(o);setTimeout(d),a.$element.on("scroll",d)}}}]);var k='',I='
';c.directive("ionItem",["$animate","$compile",function(){return{restrict:"E",controller:["$scope","$element",function(e,t){this.$scope=e,this.$element=t}],scope:!0,compile:function(e,t){var n=angular.isDefined(t.href)||angular.isDefined(t.ngHref),i=n||/ion-(delete|option|reorder)-button/i.test(e.html());if(i){var r=angular.element(n?k:I);r.append(e.contents()),e.append(r),e.addClass("item item-complex")}else e.addClass("item");return function(e,t,n){e.$href=function(){return n.href||n.ngHref}}}}}]);var C='
';c.directive("ionDeleteButton",["$animate",function(e){return{restrict:"E",require:["^ionItem","^ionList"],priority:Number.MAX_VALUE,compile:function(t,n){return n.$set("class",(n["class"]||"")+" button icon button-icon",!0),function(t,n,i,r){var o=r[0],a=r[1],s=angular.element(C);s.append(n),o.$element.append(s).addClass("item-left-editable"),a.showDelete()&&e.removeClass(s,"ng-hide")}}}}]);var x='';c.directive("ionOptionButton",["$compile",function(){return{restrict:"E",require:"^ionItem",priority:Number.MAX_VALUE,compile:function(e,t){return t.$set("class",(t["class"]||"")+" button",!0),function(e,t,n,i){i.optionsContainer||(i.optionsContainer=angular.element(x),i.$element.append(i.optionsContainer)),i.optionsContainer.append(t),t.on("click",a)}}}}]);var T='
';c.directive("ionReorderButton",["$animate",function(e){return{restrict:"E",require:["^ionItem","^ionList"],priority:Number.MAX_VALUE,compile:function(t,n){return n.$set("class",(n["class"]||"")+" button icon button-icon",!0),t[0].setAttribute("data-prevent-scroll",!0),function(t,n,i,r){var o=r[0],a=r[1];t.$onReorder=function(e,n){t.$eval(i.onReorder,{$fromIndex:e,$toIndex:n})};var s=angular.element(T);s.append(n),o.$element.append(s).addClass("item-right-editable"),a.showReorder()&&e.removeClass(s,"ng-hide")}}}}]),c.directive("ionList",["$animate","$timeout",function(e,t){return{restrict:"E",require:["ionList","^?$ionicScroll"],controller:"$ionicList",compile:function(n,i){var r=angular.element('
').append(n.contents());return n.append(r),function(n,r,o,a){function s(){function t(t,n){angular.forEach(r[0].querySelectorAll(t),function(t){n?e.removeClass(angular.element(t),"ng-hide"):e.addClass(angular.element(t),"ng-hide")})}function o(e,t){var n=angular.element(r[0].querySelectorAll(e));t?n.attr("data-tap-disabled","true"):n.removeAttr("data-tap-disabled")}c.listView=new ionic.views.ListView({el:r[0],listEl:r.children()[0],scrollEl:l&&l.element,scrollView:l&&l.scrollView,onReorder:function(e,t,n){var i=angular.element(e).scope();i&&i.$onReorder&&i.$onReorder(t,n)},canSwipe:function(){return c.canSwipeItems()}});angular.isDefined(i.canSwipe)&&n.$watch("!!("+i.canSwipe+")",function(e){c.canSwipeItems(e)}),angular.isDefined(i.showDelete)&&n.$watch("!!("+i.showDelete+")",function(e){c.showDelete(e)}),angular.isDefined(i.showReorder)&&n.$watch("!!("+i.showReorder+")",function(e){c.showReorder(e)}),n.$watch(function(){return c.showDelete()},function(e,n){(e||n)&&(e&&c.closeOptionButtons(),c.canSwipeItems(!e),r.children().toggleClass("list-left-editing",e),t(".item-delete.item-left-edit",e),o(".item-content",e))}),n.$watch(function(){return c.showReorder()},function(e,n){(e||n)&&(e&&c.closeOptionButtons(),c.canSwipeItems(!e),r.children().toggleClass("list-right-editing",e),t(".item-reorder.item-right-edit",e),o(".item-content",e))})}var c=a[0],l=a[1];t(s)}}}}]),c.directive("menuClose",["$ionicViewService",function(){return{restrict:"AC",require:"^ionSideMenus",link:function(e,t,n,i){t.bind("click",function(){i.close()})}}}]),c.directive("menuToggle",["$ionicViewService",function(){return{restrict:"AC",require:"^ionSideMenus",link:function(e,t,n,i){var r=n.menuToggle||"left";t.bind("click",function(){"left"===r?i.toggleLeft():"right"===r&&i.toggleRight()})}}}]),c.directive("ionModal",[function(){return{restrict:"E",transclude:!0,replace:!0,template:''}}]),c.directive("ionNavBackButton",["$animate","$rootScope",function(e,t){var n=!1;return t.$on("$viewHistory.historyChange",function(e,t){n=!!t.showBack}),{restrict:"E",require:"^ionNavBar",compile:function(t){return t.addClass("button back-button ng-hide"),function(t,i,r,o){r.ngClick||(t.$navBack=o.back,i.on("click",function(e){t.$apply(function(){t.$navBack(e)})})),t.$watch(function(){return!(!n||!t.backButtonShown)},ionic.animationFrameThrottle(function(t){t?e.removeClass(i,"ng-hide"):e.addClass(i,"ng-hide")}))}}}}]),c.directive("ionNavBar",["$ionicViewService","$rootScope","$animate","$compile",function(){return{restrict:"E",controller:"$ionicNavBar",scope:!0,compile:function(e){function t(e,t,n,i){i._headerBarView=new ionic.views.HeaderBar({el:t[0],alignTitle:n.alignTitle||"center"}),e.backButtonShown=!1,e.shouldAnimate=!0,e.isReverse=!1,e.isInvisible=!0,e.$on("$destroy",function(){e.$parent.$hasHeader=!1}),e.$watch(function(){return(e.isReverse?" reverse":"")+(e.isInvisible?" invisible":"")+(e.shouldAnimate?"":" no-animation")},function(e,n){t.removeClass(n),t.addClass(e)})}return e.addClass("bar bar-header nav-bar").append('

'),{pre:t}}}}]),c.directive("ionNavButtons",["$compile","$animate",function(e,t){return{require:"^ionNavBar",restrict:"E",compile:function(n){var i=n.contents().remove();return function(n,r,o,a){var s="right"===o.side?a.rightButtonsElement:a.leftButtonsElement,c=angular.element("").append(i);r.append(c),e(c)(n),ionic.requestAnimationFrame(function(){t.enter(c,s)}),n.$on("$destroy",function(){t.leave(c)}),r.css("display","none")}}}}]),c.directive("navClear",["$ionicViewService","$state","$location","$window","$rootScope",function(e,t,n,i,r){return r.$on("$stateChangeError",function(){e.nextViewOptions(null)}),{priority:100,restrict:"AC",compile:function(){function t(t,n){function r(){o=t.$on("$stateChangeStart",function(){e.nextViewOptions({disableAnimate:!0,disableBack:!0}),o()}),i.setTimeout(o,300)}var o;n.on("click",r)}return{pre:t}}}}]),c.directive("ionNavView",["$ionicViewService","$state","$compile","$controller","$animate",function(e,t,n,i,r){var o=!1,a={restrict:"E",terminal:!0,priority:2e3,transclude:!0,controller:function(){},compile:function(s,c,l){return function(s,c,u){function d(o){r.enabled()===!1&&(o=!1);var a=t.$current&&t.$current.locals[p];if(a!==f){var l=e.getRenderer(c,u,s);if(h&&(h.$destroy(),h=null),!a)return f=null,$.state=null,c.append(g);var d=angular.element("
").html(a.$template).contents(),m=l().register(d);l(o).leave(),f=a,$.state=a.$$state,l(o).enter(d);var w=n(d);if(h=s.$new(),h.$navDirection=m.navDirection,a.$$controller){a.$scope=h;var b=i(a.$$controller,a);c.children().data("$ngControllerController",b)}w(h);var y=e._getViewById(m.viewId)||{};h.$broadcast("$viewContentLoaded",y),v&&h.$eval(v),d=null}}var h,f,p=u[a.name]||u.name||"",v=u.onload||"",g=l(s);c.append(g);var m=c.parent().inheritedData("$uiView");p.indexOf("@")<0&&(p=p+"@"+(m?m.state.name:""));var $={name:p,state:null};c.data("$uiView",$);var w=function(){if(!o){o=!0;try{d(!0)}catch(e){throw o=!1,e}o=!1}};s.$on("$stateChangeSuccess",w),d(!1)}}};return a}]),c.config(["$provide",function(e){e.decorator("ngClickDirective",["$delegate",function(e){return e.shift(),e}])}]).factory("$ionicNgClick",["$parse",function(e){return function(t,n,i){var r=e(i);n.on("click",function(e){t.$apply(function(){r(t,{$event:e})})}),n.onclick=function(){}}}]).directive("ngClick",["$ionicNgClick",function(e){return function(t,n,i){e(t,n,i.ngClick)}}]).directive("ionStopEvent",function(){return{restrict:"A",link:function(e,t,n){t.bind(n.ionStopEvent,a)}}}),c.directive("ionPane",function(){return{restrict:"E",link:function(e,t){t.addClass("pane")}}}),c.directive("ionRadio",function(){return{restrict:"E",replace:!0,require:"?ngModel",scope:{ngModel:"=?",ngValue:"=?",ngChange:"&",icon:"@",name:"@"},transclude:!0,template:'',compile:function(e,t){t.name&&e.children().eq(0).attr("name",t.name),t.icon&&e.children().eq(2).removeClass("ion-checkmark").addClass(t.icon)}}}),c.directive("ionRefresher",["$ionicBind",function(e){return{restrict:"E",replace:!0,require:"^$ionicScroll",template:'
',compile:function(t,n){return angular.isUndefined(n.pullingIcon)&&n.$set("pullingIcon","ion-arrow-down-c"),angular.isUndefined(n.refreshingIcon)&&n.$set("refreshingIcon","ion-loading-d"),function(t,n,i,r){e(t,i,{pullingIcon:"@",pullingText:"@",refreshingIcon:"@",refreshingText:"@",$onRefresh:"&onRefresh",$onPulling:"&onPulling"}),r._setRefresher(t,n[0]),t.$on("scroll.refreshComplete",function(){n[0].classList.remove("active"),r.scrollView.finishPullToRefresh()})}}}}]),c.directive("ionScroll",["$timeout","$controller","$ionicBind",function(e,t,n){return{restrict:"E",scope:!0,controller:function(){},compile:function(e){function i(e,i,o){var a,s;n(e,o,{direction:"@",paging:"@",$onScroll:"&onScroll",scroll:"@",scrollbarX:"@",scrollbarY:"@",zooming:"@",minZoom:"@",maxZoom:"@"}),angular.isDefined(o.padding)&&e.$watch(o.padding,function(e){r.toggleClass("padding",!!e)}),e.$eval(e.paging)===!0&&r.addClass("scroll-paging"),e.direction||(e.direction="y");var c=e.$eval(e.paging)===!0,l={el:i[0],delegateHandle:o.delegateHandle,paging:c,scrollbarX:e.$eval(e.scrollbarX)!==!1,scrollbarY:e.$eval(e.scrollbarY)!==!1,scrollingX:e.direction.indexOf("x")>=0,scrollingY:e.direction.indexOf("y")>=0,zooming:e.$eval(e.zooming)===!0,maxZoom:e.$eval(e.maxZoom)||3,minZoom:e.$eval(e.minZoom)||.5};c&&(l.speedMultiplier=.8,l.bouncing=!1),s=t("$ionicScroll",{$scope:e,scrollViewOptions:l}),a=e.$parent.scrollView=s.scrollView}e.addClass("scroll-view");var r=angular.element('
');return r.append(e.contents()),e.append(r),{pre:i}}}}]),c.directive("ionSideMenu",function(){return{restrict:"E",require:"^ionSideMenus",scope:!0,compile:function(e,t){return angular.isUndefined(t.isEnabled)&&t.$set("isEnabled","true"),angular.isUndefined(t.width)&&t.$set("width","275"),e.addClass("menu menu-"+t.side),function(e,t,n,i){e.side=n.side||"left";var r=i[e.side]=new ionic.views.SideMenu({width:275,el:t[0],isEnabled:!0});e.$watch(n.width,function(e){var t=+e;t&&t==e&&r.setWidth(+e)}),e.$watch(n.isEnabled,function(e){r.setIsEnabled(!!e)})}}}}),c.directive("ionSideMenuContent",["$timeout","$ionicGesture",function(e,t){return{restrict:"EA",require:"^ionSideMenus",scope:!0,compile:function(n,i){function r(n,r,o,a){function s(e){0!==a.getOpenAmount()&&(a.close(),e.gesture.srcEvent.preventDefault())}r.addClass("menu-content pane"),angular.isDefined(i.dragContent)?n.$watch(i.dragContent,function(e){a.canDragContent(e)}):a.canDragContent(!0);var c=!1,l=!1;ionic.on("tap",s,r[0]);var u=function(e){!c&&a.isDraggableTarget(e)&&(l=!0,a._handleDrag(e),e.gesture.srcEvent.preventDefault())},d=function(e){l&&e.gesture.srcEvent.preventDefault()},h=t.on("dragright",u,r),f=t.on("dragleft",u,r),p=t.on("dragup",d,r),v=t.on("dragdown",d,r),g=function(e){l=!1,c||a._endDrag(e),c=!1},m=t.on("release",g,r);a.setContent({onDrag:function(){},endDrag:function(){},getTranslateX:function(){return n.sideMenuContentTranslateX||0},setTranslateX:ionic.animationFrameThrottle(function(t){r[0].style[ionic.CSS.TRANSFORM]="translate3d("+t+"px, 0, 0)",e(function(){n.sideMenuContentTranslateX=t})}),enableAnimation:function(){n.animationEnabled=!0,r[0].classList.add("menu-animated")},disableAnimation:function(){n.animationEnabled=!1,r[0].classList.remove("menu-animated")}}),n.$on("$destroy",function(){t.off(f,"dragleft",u),t.off(h,"dragright",u),t.off(p,"dragup",u),t.off(v,"dragdown",u),t.off(m,"release",g),ionic.off("tap",s,r[0])})}return{pre:r}}}}]),c.directive("ionSideMenus",[function(){return{restrict:"ECA",replace:!0,transclude:!0,controller:"$ionicSideMenus",template:'
'}}]),c.directive("ionSlideBox",["$timeout","$compile","$ionicSlideBoxDelegate",function(e,t,n){return{restrict:"E",replace:!0,transclude:!0,scope:{doesContinue:"@",slideInterval:"@",showPager:"@",pagerClick:"&",disableScroll:"@",onSlideChanged:"&",activeSlide:"=?"},controller:["$scope","$element","$attrs",function(t,i,r){var o=t.$eval(t.doesContinue)===!0,a=o?t.$eval(t.slideInterval)||4e3:0,s=new ionic.views.Slider({el:i[0],auto:a,continuous:o,startSlide:t.activeSlide,slidesChanged:function(){t.currentSlide=s.currentIndex(),e(function(){})},callback:function(n){t.currentSlide=n,t.onSlideChanged({index:t.currentSlide}),t.$parent.$broadcast("slideBox.slideChanged",n),t.activeSlide=n,e(function(){})}});s.enableSlide(t.$eval(r.disableScroll)!==!0),t.$watch("activeSlide",function(e){angular.isDefined(e)&&s.slide(e)}),t.$on("slideBox.nextSlide",function(){s.next()}),t.$on("slideBox.prevSlide",function(){s.prev()}),t.$on("slideBox.setSlide",function(e,t){s.slide(t)}),this.__slider=s;var c=n._registerInstance(s,r.delegateHandle);t.$on("$destroy",c),this.slidesCount=function(){return s.slidesCount()},this.onPagerClick=function(e){t.pagerClick({index:e})},e(function(){s.load()})}],template:'
',link:function(e,n){if(e.$eval(e.showPager)!==!1){var i=e.$new(),r=angular.element("");n.append(r),t(r)(i)}}}}]).directive("ionSlide",function(){return{restrict:"E",require:"^ionSlideBox",compile:function(e){return e.addClass("slider-slide"),function(){}}}}).directive("ionPager",function(){return{restrict:"E",replace:!0,require:"^ionSlideBox",template:'
',link:function(e,t,n,i){var r=function(e){for(var n=t[0].children,i=n.length,r=0;i>r;r++)r==e?n[r].classList.add("active"):n[r].classList.remove("active")};e.pagerClick=function(e){i.onPagerClick(e)},e.numSlides=function(){return new Array(i.slidesCount())},e.$watch("currentSlide",function(e){r(e)})}}}),c.directive("ionTab",["$rootScope","$animate","$ionicBind","$compile",function(e,t,n,i){function r(e,t){return angular.isDefined(t)?" "+e+'="'+t+'"':""}return{restrict:"E",require:["^ionTabs","ionTab"],replace:!0,controller:"$ionicTab",scope:!0,compile:function(e,o){var a="",s=angular.element('
').append(e.contents().remove());return function(e,r,o,c){function l(){f.tabMatchesState()&&h.select(e)}var u,d,h=c[0],f=c[1],p=s[0].querySelector("ion-nav-view")||s[0].querySelector("data-ion-nav-view"),v=p&&p.getAttribute("name");n(e,o,{animate:"=",onSelect:"&",onDeselect:"&",title:"@",uiSref:"@",href:"@"}),h.add(e),e.$on("$destroy",function(){h.remove(e),g.isolateScope().$destroy(),g.remove()}),r[0].removeAttribute("title"),v&&(f.navViewName=v),e.$on("$stateChangeSuccess",l),l();var g=angular.element(a);g.data("$ionTabsController",h),g.data("$ionTabController",f),h.$tabsElement.append(i(g)(e)),e.$watch("$tabSelected",function(n){u&&u.$destroy(),u=null,d&&t.leave(d),d=null,n&&(u=e.$new(),d=s.clone(),t.enter(d,h.$element),i(d)(u))})}}}}]),c.directive("ionTabNav",[function(){return{restrict:"E",replace:!0,require:["^ionTabs","^ionTab"],template:'{{badge}}',scope:{title:"@",icon:"@",iconOn:"@",iconOff:"@",badge:"=",badgeStyle:"@"},compile:function(){return function(e,t,n,i){var r=i[0],o=i[1];t[0].removeAttribute("title"),e.selectTab=function(e){e.preventDefault(),r.select(o.$scope,!0)},n.ngClick||t.on("click",function(t){e.$apply(function(){e.selectTab(t)})}),e.getIconOn=function(){return e.iconOn||e.icon},e.getIconOff=function(){return e.iconOff||e.icon},e.isTabActive=function(){return r.selectedTab()===o.$scope}}}}}]),c.directive("ionTabs",["$ionicViewService","$ionicTabsDelegate",function(e,t){return{restrict:"E",scope:!0,controller:"$ionicTabs",compile:function(e){function n(e,n,i,r){var o=t._registerInstance(r,i.delegateHandle);e.$on("$destroy",o),r.$scope=e,r.$element=n,r.$tabsElement=angular.element(n[0].querySelector(".tabs"));var a=n[0];e.$watch(function(){return a.className},function(t){var n=-1!==t.indexOf("tabs-top"),i=-1!==t.indexOf("tabs-item-hide");e.$hasTabs=!n&&!i,e.$hasTabsTop=n&&!i}),e.$on("$destroy",function(){delete e.$hasTabs,delete e.$hasTabsTop})}e.addClass("view");var i=angular.element('
');return i.append(e.contents()),e.append(i),{pre:n}}}}]),c.directive("ionToggle",["$ionicGesture","$timeout",function(){return{restrict:"E",replace:!0,require:"?ngModel",scope:{ngModel:"=?",ngValue:"=?",ngChecked:"=?",ngChange:"&",ngDisabled:"=?"},transclude:!0,template:'
',compile:function(e,t){var n=e.find("input");return t.name&&n.attr("name",t.name),t.ngChecked&&n.attr("ng-checked","ngChecked"),t.ngTrueValue&&n.attr("ng-true-value",t.ngTrueValue),t.ngFalseValue&&n.attr("ng-false-value",t.ngFalseValue),t.toggleClass&&e[0].getElementsByTagName("label")[0].classList.add(t.toggleClass),function(e,t){var n,i,r,o;n=t[0].getElementsByTagName("label")[0],i=n.children[0],r=n.children[1],o=r.children[0];var a=angular.element(i).controller("ngModel");e.toggle=new ionic.views.Toggle({el:n,track:r,checkbox:i,handle:o,onChange:function(){a.$setViewValue(i.checked?!0:!1),e.$apply()}}),e.$on("$destroy",function(){e.toggle.destroy() +})}}}}]),c.directive("ionView",["$ionicViewService","$rootScope","$animate",function(){return{restrict:"EA",priority:1e3,require:"^?ionNavBar",compile:function(e){return e.addClass("pane"),e[0].removeAttribute("title"),function(e,t,n,i){if(i){if(angular.isDefined(n.title)){var r=n.title;i.changeTitle(r,e.$navDirection),n.$observe("title",function(e){e!==r&&i.setTitle(e)})}var o=angular.isDefined(n.hideBackButton)?n.hideBackButton:"false";e.$watch(o,function(e){i.showBackButton(!e)});var a=angular.isDefined(n.hideNavBar)?n.hideNavBar:"false";e.$watch(a,function(e){i.showBar(!e)})}}}}}])}(); \ No newline at end of file diff --git a/release/js/ionic.js b/release/js/ionic.js index 0b5b57cd44f..3539dfad7a5 100644 --- a/release/js/ionic.js +++ b/release/js/ionic.js @@ -2,7 +2,7 @@ * Copyright 2014 Drifty Co. * http://drifty.com/ * - * Ionic, v1.0.0-beta.3 + * Ionic, v1.0.0-beta.4 * A powerful HTML5 mobile app framework. * http://ionicframework.com/ * @@ -19,7 +19,7 @@ window.ionic = { controllers: {}, views: {}, - version: '1.0.0-beta.3' + version: '1.0.0-beta.4' }; (function(ionic) { @@ -412,36 +412,31 @@ window.ionic = { (function(ionic) { // Custom event polyfill - if(!window.CustomEvent) { - (function() { - var CustomEvent; - - CustomEvent = function(event, params) { - var evt; - params = params || { - bubbles: false, - cancelable: false, - detail: undefined - }; - try { - evt = document.createEvent("CustomEvent"); - evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); - } catch (error) { - // fallback for browsers that don't support createEvent('CustomEvent') - evt = document.createEvent("Event"); - for (var param in params) { - evt[param] = params[param]; - } - evt.initEvent(event, params.bubbles, params.cancelable); - } - return evt; + ionic.CustomEvent = window.CustomEvent || (function() { + var CustomEvent; + CustomEvent = function(event, params) { + var evt; + params = params || { + bubbles: false, + cancelable: false, + detail: undefined }; - - CustomEvent.prototype = window.Event.prototype; - - window.CustomEvent = CustomEvent; - })(); - } + try { + evt = document.createEvent("CustomEvent"); + evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); + } catch (error) { + // fallback for browsers that don't support createEvent('CustomEvent') + evt = document.createEvent("Event"); + for (var param in params) { + evt[param] = params[param]; + } + evt.initEvent(event, params.bubbles, params.cancelable); + } + return evt; + } + CustomEvent.prototype = window.Event.prototype; + return CustomEvent; + })(); /** @@ -464,7 +459,7 @@ window.ionic = { */ // Trigger a new event trigger: function(eventType, data, bubbles, cancelable) { - var event = new CustomEvent(eventType, { + var event = new ionic.CustomEvent(eventType, { detail: data, bubbles: !!bubbles, cancelable: !!cancelable @@ -2053,6 +2048,8 @@ window.ionic = { if(this.isWebView()) { this.platforms.push('webview'); this.platforms.push('cordova'); + } else { + this.platforms.push('browser'); } if(this.isIPad()) this.platforms.push('ipad'); @@ -2092,7 +2089,10 @@ window.ionic = { * @returns {boolean} Whether we are running on iPad. */ isIPad: function() { - return this.ua.toLowerCase().indexOf('ipad') >= 0; + if( /iPad/i.test(window.navigator.platform) ) { + return true; + } + return /iPad/i.test(this.ua); }, /** * @ngdoc method @@ -2133,7 +2133,7 @@ window.ionic = { } else if(this.ua.indexOf('iPhone') > -1 || this.ua.indexOf('iPad') > -1 || this.ua.indexOf('iPod') > -1) { platformName = 'ios'; } else { - platformName = ''; + platformName = window.navigator.platform && window.navigator.platform.toLowerCase().split(' ')[0] || ''; } }, @@ -2375,34 +2375,64 @@ window.ionic = { })(document, ionic); +/** + * @ngdoc page + * @name tap + * @module ionic + * @description + * On touch devices such as a phone or tablet, some browsers implement a 300ms delay between + * the time the user stops touching the display and the moment the browser executes the + * click. This delay was initially introduced so the browser can know whether the user wants to + * double-tap to zoom in on the webpage. Basically, the browser waits roughly 300ms to see if + * the user is double-tapping, or just tapping on the display once. + * + * Out of the box, Ionic automatically removes the 300ms delay in order to make Ionic apps + * feel more "native" like. Resultingly, other solutions such as + * [fastclick](https://github.com/ftlabs/fastclick) and Angular's + * [ngTouch](https://docs.angularjs.org/api/ngTouch) should not be included, to avoid conflicts. + * + * In some cases, third-party libraries may also be working with touch events which can interfere + * with the tap system. For example, mapping libraries like Google or Leaflet Maps often implement + * a touch detection system which conflicts with Ionic's tap system. + * + * ### Disabling the tap system + * + * To disable the tap for an element and all of its children elements, + * add the attribute `data-tap-disabled="true"`. + * + * ```html + *
+ *
+ *
+ * ``` + * + * ### Additional Notes: + * + * - Ionic tap works with Ionic's JavaScript scrolling + * - Elements can come and go from the DOM and Ionic tap doesn't keep adding and removing + * listeners + * - No "tap delay" after the first "tap" (you can tap as fast as you want, they all click) + * - Minimal events listeners, only being added to document + * - Correct focus in/out on each input type (select, textearea, range) on each platform/device + * - Shows and hides virtual keyboard correctly for each platform/device + * - Works with labels surrounding inputs + * - Does not fire off a click if the user moves the pointer too far + * - Adds and removes an 'activated' css class + * - Multiple [unit tests](https://github.com/driftyco/ionic/blob/master/test/unit/utils/tap.unit.js) for each scenario + * + */ /* IONIC TAP --------------- - Both touch and mouse events are added to the document.body on DOM ready - - If a touch event happens, it removes the mouse event listeners (temporarily) - - Remembers the last touchstart event + - If a touch event happens, it does not use mouse event listeners - On touchend, if the distance between start and end was small, trigger a click - In the triggered click event, add a 'isIonicTap' property - The triggered click receives the same x,y coordinates as as the end event - On document.body click listener (with useCapture=true), only allow clicks with 'isIonicTap' - - After XXms, bring back the mouse event listeners incase they switch from touch and mouse - - If no touch events and only mouse, then touch events never fire, only mouse - Triggering clicks with mouse events work the same as touch, except with mousedown/mouseup - Tapping inputs is disabled during scrolling - - - Does not require other libraries to hook into ionic.tap, it just works - - Elements can come and go from the DOM and it doesn't have to keep adding and removing listeners - - No "tap delay" after the first "tap" (you can tap as fast as you want, they all click) - - Minimal events listeners, only being added to document.body - - Correct focus in/out on each input type on each platform/device - - Shows and hides virtual keyboard correctly for each platform/device - - No user-agent sniffing - - Works with labels surrounding inputs - - Does not fire off a click if the user moves the pointer too far - - Adds and removes an 'activated' css class - - Multiple unit tests for each scenario - */ var tapDoc; // the element which the listeners are on (document.body) @@ -2460,7 +2490,7 @@ ionic.tap = { ignoreScrollStart: function(e) { return (e.defaultPrevented) || // defaultPrevented has been assigned by another component handling the event (e.target.isContentEditable) || - (e.target.type === 'range') || + (/file|range/i).test(e.target.type) || (e.target.dataset ? e.target.dataset.preventScroll : e.target.getAttribute('data-prevent-default')) == 'true' || // manually set within an elements attributes (!!(/object|embed/i).test(e.target.tagName)); // flash/movie/object touches should not try to scroll }, @@ -2525,6 +2555,22 @@ ionic.tap = { previousInputFocus[x].focus(); } }); + }, + + requiresNativeClick: function(ele) { + if(!ele || ele.disabled || (/file|range/i).test(ele.type) || (/object|video/i).test(ele.tagName) ) { + return true; + } + if(ele.nodeType === 1) { + var element = ele; + while(element) { + if( (element.dataset ? element.dataset.tapDisabled : element.getAttribute('data-tap-disabled')) == 'true' ) { + return true; + } + element = element.parentElement; + } + } + return false; } }; @@ -2542,7 +2588,7 @@ function tapClick(e) { var container = tapContainingElement(e.target); var ele = tapTargetElement(container); - if( tapRequiresNativeClick(ele) || tapPointerMoved ) return false; + if( ionic.tap.requiresNativeClick(ele) || tapPointerMoved ) return false; var c = getPointerCoordinates(e); @@ -2569,7 +2615,7 @@ function tapClickGateKeeper(e) { // do not allow through any click events that were not created by ionic.tap if( (ionic.scroll.isScrolling && ionic.tap.containsOrIsTextInput(e.target) ) || - (!e.isIonicTap && !tapRequiresNativeClick(e.target)) ) { + (!e.isIonicTap && !ionic.tap.requiresNativeClick(e.target)) ) { void 0; e.stopPropagation(); @@ -2581,22 +2627,6 @@ function tapClickGateKeeper(e) { } } -function tapRequiresNativeClick(ele) { - if(!ele || ele.disabled || (/file|range/i).test(ele.type) || (/object|video/i).test(ele.tagName) ) { - return true; - } - if(ele.nodeType === 1) { - var element = ele; - while(element) { - if( (element.dataset ? element.dataset.tapDisabled : element.getAttribute('data-tap-disabled')) == 'true' ) { - return true; - } - element = element.parentElement; - } - } - return false; -} - // MOUSE function tapMouseDown(e) { if(e.isIonicTap || tapIgnoreEvent(e)) return; @@ -2630,7 +2660,7 @@ function tapMouseUp(e) { return false; } - if( tapIgnoreEvent(e) ) return; + if( tapIgnoreEvent(e) || e.target.tagName === 'SELECT' ) return false; if( !tapHasPointerMoved(e) ) { tapClick(e); @@ -2864,7 +2894,7 @@ ionic.DomUtil.ready(function(){ // when an element is touched/clicked, it climbs up a few // parents to see if it is an .item or .button element ionic.requestAnimationFrame(function(){ - if (tapRequiresNativeClick(e.target)) return; + if ( ionic.tap.requiresNativeClick(e.target) ) return; var ele = e.target; var eleToActivate; @@ -2918,7 +2948,6 @@ ionic.DomUtil.ready(function(){ } function activateElements() { - // console.log('ACTIVATING'); // activate all elements in the queue for(var key in queueElements) { if(queueElements[key]) { @@ -3138,30 +3167,36 @@ var keyboardIsOpen; var keyboardActiveElement; var keyboardFocusOutTimer; var keyboardFocusInTimer; +var keyboardLastShow = 0; var KEYBOARD_OPEN_CSS = 'keyboard-open'; var SCROLL_CONTAINER_CSS = 'scroll'; ionic.keyboard = { isOpen: false, - height: null + height: null, + landscape: false, }; function keyboardInit() { if( keyboardHasPlugin() ) { window.addEventListener('native.showkeyboard', keyboardNativeShow); + window.addEventListener('native.hidekeyboard', keyboardFocusOut); + } + else { + document.body.addEventListener('focusout', keyboardFocusOut); } document.body.addEventListener('ionic.focusin', keyboardBrowserFocusIn); document.body.addEventListener('focusin', keyboardBrowserFocusIn); - document.body.addEventListener('focusout', keyboardFocusOut); document.body.addEventListener('orientationchange', keyboardOrientationChange); document.removeEventListener('touchstart', keyboardInit); } function keyboardNativeShow(e) { + clearTimeout(keyboardFocusOutTimer); ionic.keyboard.height = e.keyboardHeight; } @@ -3183,10 +3218,27 @@ function keyboardSetShow(e) { clearTimeout(keyboardFocusOutTimer); keyboardFocusInTimer = setTimeout(function(){ - var keyboardHeight = keyboardGetHeight(); + if ( keyboardLastShow + 350 > Date.now() ) return; + keyboardLastShow = Date.now(); + var keyboardHeight; var elementBounds = keyboardActiveElement.getBoundingClientRect(); + var count = 0; - keyboardShow(e.target, elementBounds.top, elementBounds.bottom, keyboardViewportHeight, keyboardHeight); + var pollKeyboardHeight = setInterval(function(){ + + keyboardHeight = keyboardGetHeight(); + if (count > 10){ + clearInterval(pollKeyboardHeight); + //waited long enough, just guess + keyboardHeight = 275; + } + if (keyboardHeight){ + keyboardShow(e.target, elementBounds.top, elementBounds.bottom, keyboardViewportHeight, keyboardHeight); + clearInterval(pollKeyboardHeight); + } + count++; + + }, 100); }, 32); } @@ -3198,15 +3250,9 @@ function keyboardShow(element, elementTop, elementBottom, viewportHeight, keyboa keyboardHeight: keyboardHeight }; - if( keyboardIsOverWebView() ) { - // keyboard sits on top of the view, but doesn't adjust the view's height - // lower the content height by subtracting the keyboard height from the view height - details.contentHeight = viewportHeight - keyboardHeight; - } else { - // view's height was shrunk down and the keyboard takes up the space the view doesn't fill - // do not add extra padding at the bottom of the scroll view, native already did that - details.contentHeight = viewportHeight; - } + details.hasPlugin = keyboardHasPlugin(); + + details.contentHeight = viewportHeight - keyboardHeight; void 0; @@ -3277,32 +3323,70 @@ function keyboardPreventDefault(e) { } function keyboardOrientationChange() { - keyboardViewportHeight = window.innerHeight; - setTimeout(function(){ - keyboardViewportHeight = window.innerHeight; - }, 999); + var updatedViewportHeight = window.innerHeight; + + //too slow, have to wait for updated height + if (updatedViewportHeight === keyboardViewportHeight){ + var count = 0; + var pollViewportHeight = setInterval(function(){ + //give up + if (count > 10){ + clearInterval(pollViewportHeight); + } + + updatedViewportHeight = window.innerHeight; + + if (updatedViewportHeight !== keyboardViewportHeight){ + if (updatedViewportHeight < keyboardViewportHeight){ + ionic.keyboard.landscape = true; + } + else { + ionic.keyboard.landscape = false; + } + keyboardViewportHeight = updatedViewportHeight; + clearInterval(pollViewportHeight); + } + count++; + + }, 50); + } + else { + keyboardViewportHeight = updatedViewportHeight; + } } function keyboardGetHeight() { // check if we are already have a keyboard height from the plugin - if (ionic.keyboard.height ) { + if ( ionic.keyboard.height ) { return ionic.keyboard.height; } + if ( ionic.Platform.isAndroid() ){ + //should be using the plugin, no way to know how big the keyboard is, so guess + if ( ionic.Platform.isFullScreen ){ + return 275; + } + //otherwise, wait for the screen to resize + if ( window.innerHeight < keyboardViewportHeight ){ + return keyboardViewportHeight - window.innerHeight; + } + else { + return 0; + } + } + // fallback for when its the webview without the plugin // or for just the standard web browser if( ionic.Platform.isIOS() ) { - if( ionic.Platform.isWebView() ) { - return 260; - } - return 216; - } else if( ionic.Platform.isAndroid() ) { - if( ionic.Platform.isWebView() ) { - return 220; + if ( ionic.keyboard.landscape ){ + return 206; } - if( ionic.Platform.version() <= 4.3) { - return 230; + + if (!ionic.Platform.isWebView()){ + return 216; } + + return 260; } // safe guess @@ -3319,11 +3403,6 @@ function keyboardIsWithinScroll(ele) { return false; } -function keyboardIsOverWebView() { - return ( ionic.Platform.isIOS() ) || - ( ionic.Platform.isAndroid() && !ionic.Platform.isWebView() ); -} - function keyboardHasPlugin() { return !!(window.cordova && cordova.plugins && cordova.plugins.Keyboard); } @@ -3345,6 +3424,14 @@ ionic.Platform.ready(function() { var viewportTag; var viewportProperties = {}; +ionic.viewport = { + orientation: function() { + // 0 = Portrait + // 90 = Landscape + // not using window.orientation because each device has a different implementation + return (window.innerWidth > window.innerHeight ? 90 : 0); + } +}; function viewportLoadTag() { var x; @@ -3360,43 +3447,112 @@ function viewportLoadTag() { var props = viewportTag.content.toLowerCase().replace(/\s+/g, '').split(','); var keyValue; for(x=0; x 1 ? keyValue[1] : '_'); + } } - viewportInitWebView(); + viewportUpdate(); } } -function viewportInitWebView() { - var hasViewportChange = false; +function viewportUpdate() { + // unit tests in viewport.unit.js + + var initWidth = viewportProperties.width; + var initHeight = viewportProperties.height; + var p = ionic.Platform; + var version = p.version(); + var DEVICE_WIDTH = 'device-width'; + var DEVICE_HEIGHT = 'device-height'; + var orientation = ionic.viewport.orientation(); + + // Most times we're removing the height and adding the width + // So this is the default to start with, then modify per platform/version/oreintation + delete viewportProperties.height; + viewportProperties.width = DEVICE_WIDTH; + + if( p.isIPad() ) { + // iPad + + if( version > 7 ) { + // iPad >= 7.1 + // https://issues.apache.org/jira/browse/CB-4323 + delete viewportProperties.width; + + } else { + // iPad <= 7.0 + + if( p.isWebView() ) { + // iPad <= 7.0 WebView - if( ionic.Platform.isWebView() ) { - if( viewportProperties.height != 'device-height' ) { - viewportProperties.height = 'device-height'; - hasViewportChange = true; + if( orientation == 90 ) { + // iPad <= 7.0 WebView Landscape + viewportProperties.height = '0'; + + } else if(version == 7) { + // iPad <= 7.0 WebView Portait + viewportProperties.height = DEVICE_HEIGHT; + } + } else { + // iPad <= 6.1 Browser + if(version < 7) { + viewportProperties.height = '0'; + } + } + } + + } else if( p.isIOS() ) { + // iPhone + + if( p.isWebView() ) { + // iPhone WebView + + if(version > 7) { + // iPhone >= 7.1 WebView + delete viewportProperties.width; + + } else if(version < 7) { + // iPhone <= 6.1 WebView + // if height was set it needs to get removed with this hack for <= 6.1 + if( initHeight ) viewportProperties.height = '0'; + } + + } else { + // iPhone Browser + + if (version < 7) { + // iPhone <= 6.1 Browser + // if height was set it needs to get removed with this hack for <= 6.1 + if( initHeight ) viewportProperties.height = '0'; + } } - } else if( viewportProperties.height ) { - delete viewportProperties.height; - hasViewportChange = true; - } - if(hasViewportChange) viewportUpdate(); -} -function viewportUpdate(updates) { - if(!viewportTag) return; + } - ionic.Utils.extend(viewportProperties, updates); + // only update the viewport tag if there was a change + if(initWidth !== viewportProperties.width || initHeight !== viewportProperties.height) { + viewportTagUpdate(); + } +} +function viewportTagUpdate() { var key, props = []; for(key in viewportProperties) { - if(viewportProperties[key]) props.push(key + '=' + viewportProperties[key]); + if( viewportProperties[key] ) { + props.push(key + (viewportProperties[key] == '_' ? '' : '=' + viewportProperties[key]) ); + } } - viewportTag.content = props.join(','); + viewportTag.content = props.join(', '); } -ionic.DomUtil.ready(function() { +ionic.Platform.ready(function() { viewportLoadTag(); + + window.addEventListener("orientationchange", function(){ + setTimeout(viewportUpdate, 1000); + }, false); }); (function(ionic) { @@ -3795,7 +3951,7 @@ ionic.views.Scroll = ionic.views.View.inherit({ self.resize(); }, 1000, true); - this.onScroll = function(scrollTop) { + this.onScroll = function() { if(!ionic.scroll.isScrolling) { setTimeout(self.setScrollStart, 50); @@ -3818,6 +3974,7 @@ ionic.views.Scroll = ionic.views.View.inherit({ }; this.triggerScrollEvent = ionic.throttle(function() { + self.onScroll(); ionic.trigger('scroll', { scrollTop: self.__scrollTop, scrollLeft: self.__scrollLeft, @@ -4037,15 +4194,26 @@ ionic.views.Scroll = ionic.views.View.inherit({ if( !self.isScrolledIntoView ) { // shrink scrollview so we can actually scroll if the input is hidden // if it isn't shrink so we can scroll to inputs under the keyboard - container.style.height = (container.clientHeight - e.detail.keyboardHeight) + "px"; - container.style.overflow = "visible"; + if (ionic.Platform.isIOS() || ionic.Platform.isFullScreen){ + container.style.height = (container.clientHeight - e.detail.keyboardHeight) + "px"; + container.style.overflow = "visible"; + //update scroll view + self.resize(); + } self.isScrolledIntoView = true; - //update scroll view - self.resize(); } //If the element is positioned under the keyboard... if( e.detail.isElementUnderKeyboard ) { + var delay; + // Wait on android for scroll view to resize + if ( !ionic.Platform.isFullScreen && e.detail.hasPlugin ) { + delay = 350; + } + else { + delay = 80; + } + //Put element in middle of visible screen //Wait for resize() to reset scroll position ionic.scroll.isScrolling = true; @@ -4057,9 +4225,7 @@ ionic.views.Scroll = ionic.views.View.inherit({ ionic.tap.cloneFocusedInput(container, self); self.scrollBy(0, scrollTop, true); self.onScroll(); - }, - (ionic.Platform.isIOS() ? 80 : 350) - ); + }, delay); } //Only the first scrollView parent of the element that broadcasted this event @@ -4208,11 +4374,14 @@ ionic.views.Scroll = ionic.views.View.inherit({ self.__fadeScrollbars('out'); }, 100, false); - document.addEventListener("mousewheel", function(e) { + //For Firefox + document.addEventListener('mousewheel', onMouseWheel); + function onMouseWheel(e) { + self.hintResize(); wheelShowBarFn(); self.scrollBy(e.wheelDeltaX/self.options.wheelDampen, -e.wheelDeltaY/self.options.wheelDampen); wheelHideBarFn(); - }); + } } }, @@ -5691,6 +5860,9 @@ ionic.scroll = { var margin = Math.max(leftWidth, rightWidth) + 10; + //Reset left and right before setting again + titleEl.style.left = titleEl.style.right = ''; + // Size and align the header titleEl based on the sizes of the left and // right children, and the desired alignment mode if(align == 'center') { @@ -6162,7 +6334,7 @@ ionic.scroll = { // Return the list item from the given target _getItem: function(target) { while(target) { - if(target.classList.contains(ITEM_CLASS)) { + if(target.classList && target.classList.contains(ITEM_CLASS)) { return target; } target = target.parentNode; @@ -7447,4 +7619,5044 @@ ionic.views.Slider = ionic.views.View.inherit({ })(ionic); +(function(window) { + var time = Date.now || function() { + return +new Date(); + }; + var desiredFrames = 60; + var millisecondsPerSecond = 1000; + var running = {}; + var counter = 1; + + // Namespace + ionic.Animation = {}; + + /** + * The main animation system manager. Treated as a singleton. + */ + ionic.Animation = { + create: function(opts) { + return new ionic.Animation.Animation(opts); + }, + + animationStarted: function(instance) { + var id = counter++; + + // Compacting running db automatically every few new animations + if (id % 20 === 0) { + var newRunning = {}; + for (var usedId in running) { + newRunning[usedId] = true; + } + running = newRunning; + } + + // Mark as running + running[id] = true; + + instance.isRunning = true; + instance._animationId = id; + + // Return unique animation ID + return id; + }, + + animationStopped: function(instance) { + instance.isRunning = false; + } + + /* TODO: Move animation set management here instead of instance + anims: [], + add: function(animation) { + this.anims.push(animation); + }, + remove: function(animation) { + var i, j; + for(i = 0, j = this.anims.length; i < j; i++) { + if(this.anims[i] === animation) { + return this.anims.splice(i, 1); + } + } + }, + clear: function(shouldStop) { + while(this.anims.length) { + var anim = this.anims.pop(); + if(shouldStop === true) { + anim.stop(); + } + } + }, + */ + + /** + * Stops the given animation. + * + * @param id {Integer} Unique animation ID + * @return {Boolean} Whether the animation was stopped (aka, was running before) + * TODO: Requires above fix + stop: function(id) { + var cleared = running[id] != null; + if (cleared) { + running[id] = null; + } + + return cleared; + }, + */ + + + /** + * Whether the given animation is still running. + * + * @param id {Integer} Unique animation ID + * @return {Boolean} Whether the animation is still running + isRunning: function(id) { + return running[id] != null; + }, + */ + + }; + + /** + * Animation instance + */ + ionic.Animation.Animation = function(opts) { + ionic.extend(this, opts); + + if(opts.useSlowAnimations) { + void 0; + this.delay *= 3; + this.duration *= 3; + } + }; + + ionic.Animation.Animation.prototype = { + el: null, + curve: 'linear', + duration: 500, + delay: 0, + repeat: -1, + reverse: false, + autoReverse: false, + + step: function(percent) {}, + + stop: function() { + this.isRunning = false; + this.shouldEnd = true; + }, + play: function() { + this.isPaused = false; + this.start(); + }, + pause: function() { + this.isPaused = true; + }, + _saveState: function(percent, iteration, reverse) { + this._pauseState = { + percent: percent, + iteration: iteration, + reverse: reverse + } + }, + restart: function() { + }, + + start: function() { + var self = this; + + var tf; + + void 0; + + + // Grab the timing function + if(typeof this.curve === 'string') { + tf = ionic.Animation.TimingFn[this.curve] || ionic.Animation.TimingFn['linear']; + } else { + tf = this.curve; + } + + // Get back a timing function for the given duration (used for precision) + tf = tf(this.duration); + + // Set up the initial animation state + var animState = { + startPercent: this.reverse === true ? 1 : 0, + endPercent: this.reverse === true ? 0 : 1, + duration: this.duration, + easingMethod: tf, + delay: this.delay, + reverse: this.reverse, + repeat: this.repeat, + autoReverse: this.autoReverse + } + + + if(this._pauseState) { + // We were paused, so update the fields + ionic.extend(animState, this._pauseState); + this._pauseState = null; + } + + ionic.Animation.animationStarted(this); + + return this._run(function(percent, now, render) { + if(render) { + self.step(percent); + } + }, function(droppedFrames, finishedAnimation) { + ionic.Animation.animationStopped(self); + void 0; + }, animState); + }, + + /** + * Start the animation. + * + * @param stepCallback {Function} Pointer to function which is executed on every step. + * Signature of the method should be `function(percent, now, virtual) { return continueWithAnimation; }` + * @param completedCallback {Function} + * Signature of the method should be `function(droppedFrames, finishedAnimation) {}` + * @param duration {Integer} Milliseconds to run the animation + * @param easingMethod {Function} Pointer to easing function + * Signature of the method should be `function(percent) { return modifiedValue; }` + * @return {Integer} Identifier of animation. Can be used to stop it any time. + */ + _run: function(stepCallback, completedCallback, state) { + + var self = this; + var start = time(); + var lastFrame = start; + var startTime = start + state.delay; + var percent = state.startPercent; + var startPercent = state.startPercent; + var endPercent = state.endPercent; + var autoReverse = state.autoReverse; + var delay = state.delay; + var duration = state.duration; + var easingMethod = state.easingMethod; + var repeat = state.repeat; + var reverse = state.reverse; + + var dropCounter = 0; + var iteration = 0; + + var perhapsAutoreverse = function() { + // Check if we hit the end and should auto reverse + if(percent === endPercent && autoReverse) { + // Flip the start and end values + var sp = endPercent; + reverse = !reverse; + endPercent = startPercent; + startPercent = sp; + + if(repeat === 0) { + autoReverse = false; + } + } else { + // Otherwise, just start over + percent = startPercent; + } + // Start fresh either way + start = time(); + ionic.requestAnimationFrame(step); + } + + + // This is the internal step method which is called every few milliseconds + var step = function(virtual) { + + // Normalize virtual value + var render = virtual !== true; + + // Get current time + var now = time(); + var diff = now - start; + + // Verification is executed before next animation step + if(self.isPaused) { + self._saveState(percent, iteration, reverse); + return; + } + + if (!self.isRunning) {// || (verifyCallback && !verifyCallback(id))) { + + completedCallback && completedCallback(desiredFrames - (dropCounter / ((now - start) / millisecondsPerSecond)), self._animationId, false); + return; + + } + + + // For the current rendering to apply let's update omitted steps in memory. + // This is important to bring internal state variables up-to-date with progress in time. + if (render) { + + var droppedFrames = Math.round((now - lastFrame) / (millisecondsPerSecond / desiredFrames)) - 1; + for (var j = 0; j < Math.min(droppedFrames, 4); j++) { + step(true); + dropCounter++; + } + + } + + // Compute percent value + if (diff > delay && duration) { + percent = (diff - delay) / duration; + if(reverse === true) { + percent = 1 - percent; + if (percent < 0) { + percent = 0; + } + } else { + if (percent > 1) { + percent = 1; + } + } + } + + // Execute step callback, then... + var value = easingMethod ? easingMethod(percent) : percent; + if ((stepCallback(value, now, render) === false || percent === endPercent) && render) { + if(repeat === -1) { + perhapsAutoreverse(); + } else if(iteration < repeat) { + // Track iterations + iteration++; + perhapsAutoreverse(); + } else if(repeat === 0 && autoReverse) { + perhapsAutoreverse(); + } else { + completedCallback && completedCallback(desiredFrames - (dropCounter / ((now - start) / millisecondsPerSecond)), self._animationId, percent === endPercent || duration == null); + } + } else if (render) { + lastFrame = now; + ionic.requestAnimationFrame(step); + } + }; + + + // Init first step + ionic.requestAnimationFrame(step); + + } + }; + + +})(window); + +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +(function(ionic) { + + var bezierCoord = function (x,y) { + if(!x) x=0; + if(!y) y=0; + return {x: x, y: y}; + }; + + function B1(t) { return t*t*t; } + function B2(t) { return 3*t*t*(1-t); } + function B3(t) { return 3*t*(1-t)*(1-t); } + function B4(t) { return (1-t)*(1-t)*(1-t); } + + ionic.Animation = ionic.Animation || {} + + + /** + * JavaScript port of Webkit implementation of CSS cubic-bezier(p1x.p1y,p2x,p2y) by http://mck.me + * http://svn.webkit.org/repository/webkit/trunk/Source/WebCore/platform/graphics/UnitBezier.h + */ + ionic.Animation.Bezier = (function(){ + 'use strict'; + + /** + * Duration value to use when one is not specified (400ms is a common value). + * @const + * @type {number} + */ + var DEFAULT_DURATION = 400;//ms + + /** + * The epsilon value we pass to UnitBezier::solve given that the animation is going to run over |dur| seconds. + * The longer the animation, the more precision we need in the timing function result to avoid ugly discontinuities. + * http://svn.webkit.org/repository/webkit/trunk/Source/WebCore/page/animation/AnimationBase.cpp + */ + var solveEpsilon = function(duration) { + return 1.0 / (200.0 * duration); + }; + + /** + * Defines a cubic-bezier curve given the middle two control points. + * NOTE: first and last control points are implicitly (0,0) and (1,1). + * @param p1x {number} X component of control point 1 + * @param p1y {number} Y component of control point 1 + * @param p2x {number} X component of control point 2 + * @param p2y {number} Y component of control point 2 + */ + var unitBezier = function(p1x, p1y, p2x, p2y) { + + // private members -------------------------------------------- + + // Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1). + + /** + * X component of Bezier coefficient C + * @const + * @type {number} + */ + var cx = 3.0 * p1x; + + /** + * X component of Bezier coefficient B + * @const + * @type {number} + */ + var bx = 3.0 * (p2x - p1x) - cx; + + /** + * X component of Bezier coefficient A + * @const + * @type {number} + */ + var ax = 1.0 - cx -bx; + + /** + * Y component of Bezier coefficient C + * @const + * @type {number} + */ + var cy = 3.0 * p1y; + + /** + * Y component of Bezier coefficient B + * @const + * @type {number} + */ + var by = 3.0 * (p2y - p1y) - cy; + + /** + * Y component of Bezier coefficient A + * @const + * @type {number} + */ + var ay = 1.0 - cy - by; + + /** + * @param t {number} parametric timing value + * @return {number} + */ + var sampleCurveX = function(t) { + // `ax t^3 + bx t^2 + cx t' expanded using Horner's rule. + return ((ax * t + bx) * t + cx) * t; + }; + + /** + * @param t {number} parametric timing value + * @return {number} + */ + var sampleCurveY = function(t) { + return ((ay * t + by) * t + cy) * t; + }; + + /** + * @param t {number} parametric timing value + * @return {number} + */ + var sampleCurveDerivativeX = function(t) { + return (3.0 * ax * t + 2.0 * bx) * t + cx; + }; + + /** + * Given an x value, find a parametric value it came from. + * @param x {number} value of x along the bezier curve, 0.0 <= x <= 1.0 + * @param epsilon {number} accuracy limit of t for the given x + * @return {number} the t value corresponding to x + */ + var solveCurveX = function(x, epsilon) { + var t0; + var t1; + var t2; + var x2; + var d2; + var i; + + // First try a few iterations of Newton's method -- normally very fast. + for (t2 = x, i = 0; i < 8; i++) { + x2 = sampleCurveX(t2) - x; + if (Math.abs (x2) < epsilon) { + return t2; + } + d2 = sampleCurveDerivativeX(t2); + if (Math.abs(d2) < 1e-6) { + break; + } + t2 = t2 - x2 / d2; + } + + // Fall back to the bisection method for reliability. + t0 = 0.0; + t1 = 1.0; + t2 = x; + + if (t2 < t0) { + return t0; + } + if (t2 > t1) { + return t1; + } + + while (t0 < t1) { + x2 = sampleCurveX(t2); + if (Math.abs(x2 - x) < epsilon) { + return t2; + } + if (x > x2) { + t0 = t2; + } else { + t1 = t2; + } + t2 = (t1 - t0) * 0.5 + t0; + } + + // Failure. + return t2; + }; + + /** + * @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0 + * @param epsilon {number} the accuracy of t for the given x + * @return {number} the y value along the bezier curve + */ + var solve = function(x, epsilon) { + return sampleCurveY(solveCurveX(x, epsilon)); + }; + + // public interface -------------------------------------------- + + /** + * Find the y of the cubic-bezier for a given x with accuracy determined by the animation duration. + * @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0 + * @param duration {number} the duration of the animation in milliseconds + * @return {number} the y value along the bezier curve + */ + return function(x, duration) { + return solve(x, solveEpsilon(+duration || DEFAULT_DURATION)); + }; + }; + + // http://www.w3.org/TR/css3-transitions/#transition-timing-function + return { + /** + * @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0 + * @param duration {number} the duration of the animation in milliseconds + * @return {number} the y value along the bezier curve + */ + linear: unitBezier(0.0, 0.0, 1.0, 1.0), + + /** + * @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0 + * @param duration {number} the duration of the animation in milliseconds + * @return {number} the y value along the bezier curve + */ + ease: unitBezier(0.25, 0.1, 0.25, 1.0), + + /** + * @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0 + * @param duration {number} the duration of the animation in milliseconds + * @return {number} the y value along the bezier curve + */ + easeIn: unitBezier(0.42, 0, 1.0, 1.0), + + /** + * @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0 + * @param duration {number} the duration of the animation in milliseconds + * @return {number} the y value along the bezier curve + */ + easeOut: unitBezier(0, 0, 0.58, 1.0), + + /** + * @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0 + * @param duration {number} the duration of the animation in milliseconds + * @return {number} the y value along the bezier curve + */ + easeInOut: unitBezier(0.42, 0, 0.58, 1.0), + + /** + * @param p1x {number} X component of control point 1 + * @param p1y {number} Y component of control point 1 + * @param p2x {number} X component of control point 2 + * @param p2y {number} Y component of control point 2 + * @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0 + * @param duration {number} the duration of the animation in milliseconds + * @return {number} the y value along the bezier curve + */ + cubicBezier: function(p1x, p1y, p2x, p2y, x, duration) { + return unitBezier(p1x, p1y, p2x, p2y)(x, duration); + } + }; + })(); + +/** + * Various fast approximations and alternates to cubic-bezier easing functions. + * http://www.w3.org/TR/css3-transitions/#transition-timing-function + */ +var Easing = (function(){ + 'use strict'; + + /** + * @const + */ + var EASE_IN_OUT_CONST = 0.5 * Math.pow(0.5, 1.925); + + return { + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + linear: function(x) { + return x; + }, + +// /** +// * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 +// * @return {number} the y value along the curve +// */ +// ease: function(x) { +// // TODO: find fast approximations +// return x; +// }, + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + easeInApprox: function(x) { + // very close approximation to cubic-bezier(0.42, 0, 1.0, 1.0) + return Math.pow(x, 1.685); + }, + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + easeInQuadratic: function(x) { + return (x * x); + }, + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + easeInCubic: function(x) { + return (x * x * x); + }, + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + easeOutApprox: function(x) { + // very close approximation to cubic-bezier(0, 0, 0.58, 1.0) + return 1 - Math.pow(1-x, 1.685); + }, + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + easeOutQuadratic: function(x) { + x -= 1; + return 1 - (x * x); + }, + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + easeOutCubic: function(x) { + x -= 1; + return 1 + (x * x * x); + }, + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + easeInOutApprox: function(x) { + // very close approximation to cubic-bezier(0.42, 0, 0.58, 1.0) + if (x < 0.5) { + return EASE_IN_OUT_CONST * Math.pow(x, 1.925); + + } else { + return 1 - EASE_IN_OUT_CONST * Math.pow(1-x, 1.925); + } + }, + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + easeInOutQuadratic: function(x) { + if (x < 0.5) { + return (2 * x * x); + + } else { + x -= 1; + return 1 - (2 * x * x); + } + }, + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + easeInOutCubic: function(x) { + if (x < 0.5) { + return (4 * x * x * x); + + } else { + x -= 1; + return 1 + (4 * x * x * x); + } + }, + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + easeInOutQuartic: function(x) { + if (x < 0.5) { + return (8 * x * x * x * x); + + } else { + x -= 1; + return 1 + (8 * x * x * x * x); + } + }, + + /** + * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0 + * @return {number} the y value along the curve + */ + easeInOutQuintic: function(x) { + if (x < 0.5) { + return (16 * x * x * x * x * x); + + } else { + x -= 1; + return 1 + (16 * x * x * x * x * x); + } + } + }; +})(); +})(ionic); + +/** + * @fileoverview gl-matrix - High performance matrix and vector operations + * @author Brandon Jones + * @author Colin MacKenzie IV + * @version 2.2.1 + */ + +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + + +(function(_global) { + "use strict"; + + var shim = {}; + if (typeof(exports) === 'undefined') { + if(typeof define == 'function' && typeof define.amd == 'object' && define.amd) { + shim.exports = {}; + define(function() { + return shim.exports; + }); + } else { + // gl-matrix lives in a browser, define its namespaces in global + shim.exports = typeof(window) !== 'undefined' ? window : _global; + } + } + else { + // gl-matrix lives in commonjs, define its namespaces in exports + shim.exports = exports; + } + + (function(exports) { + /* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + + +if(!GLMAT_EPSILON) { + var GLMAT_EPSILON = 0.000001; +} + +if(!GLMAT_ARRAY_TYPE) { + var GLMAT_ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array; +} + +if(!GLMAT_RANDOM) { + var GLMAT_RANDOM = Math.random; +} + +/** + * @class Common utilities + * @name glMatrix + */ +var glMatrix = {}; + +/** + * Sets the type of array used when creating new vectors and matricies + * + * @param {Type} type Array type, such as Float32Array or Array + */ +glMatrix.setMatrixArrayType = function(type) { + GLMAT_ARRAY_TYPE = type; +} + +if(typeof(exports) !== 'undefined') { + exports.glMatrix = glMatrix; +} + +var degree = Math.PI / 180; + +/** +* Convert Degree To Radian +* +* @param {Number} Angle in Degrees +*/ +glMatrix.toRadian = function(a){ + return a * degree; +} +; +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class 2 Dimensional Vector + * @name vec2 + */ + +var vec2 = {}; + +/** + * Creates a new, empty vec2 + * + * @returns {vec2} a new 2D vector + */ +vec2.create = function() { + var out = new GLMAT_ARRAY_TYPE(2); + out[0] = 0; + out[1] = 0; + return out; +}; + +/** + * Creates a new vec2 initialized with values from an existing vector + * + * @param {vec2} a vector to clone + * @returns {vec2} a new 2D vector + */ +vec2.clone = function(a) { + var out = new GLMAT_ARRAY_TYPE(2); + out[0] = a[0]; + out[1] = a[1]; + return out; +}; + +/** + * Creates a new vec2 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @returns {vec2} a new 2D vector + */ +vec2.fromValues = function(x, y) { + var out = new GLMAT_ARRAY_TYPE(2); + out[0] = x; + out[1] = y; + return out; +}; + +/** + * Copy the values from one vec2 to another + * + * @param {vec2} out the receiving vector + * @param {vec2} a the source vector + * @returns {vec2} out + */ +vec2.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + return out; +}; + +/** + * Set the components of a vec2 to the given values + * + * @param {vec2} out the receiving vector + * @param {Number} x X component + * @param {Number} y Y component + * @returns {vec2} out + */ +vec2.set = function(out, x, y) { + out[0] = x; + out[1] = y; + return out; +}; + +/** + * Adds two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.add = function(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + return out; +}; + +/** + * Subtracts vector b from vector a + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.subtract = function(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + return out; +}; + +/** + * Alias for {@link vec2.subtract} + * @function + */ +vec2.sub = vec2.subtract; + +/** + * Multiplies two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.multiply = function(out, a, b) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + return out; +}; + +/** + * Alias for {@link vec2.multiply} + * @function + */ +vec2.mul = vec2.multiply; + +/** + * Divides two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.divide = function(out, a, b) { + out[0] = a[0] / b[0]; + out[1] = a[1] / b[1]; + return out; +}; + +/** + * Alias for {@link vec2.divide} + * @function + */ +vec2.div = vec2.divide; + +/** + * Returns the minimum of two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.min = function(out, a, b) { + out[0] = Math.min(a[0], b[0]); + out[1] = Math.min(a[1], b[1]); + return out; +}; + +/** + * Returns the maximum of two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.max = function(out, a, b) { + out[0] = Math.max(a[0], b[0]); + out[1] = Math.max(a[1], b[1]); + return out; +}; + +/** + * Scales a vec2 by a scalar number + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {vec2} out + */ +vec2.scale = function(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + return out; +}; + +/** + * Adds two vec2's after scaling the second operand by a scalar value + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @param {Number} scale the amount to scale b by before adding + * @returns {vec2} out + */ +vec2.scaleAndAdd = function(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + return out; +}; + +/** + * Calculates the euclidian distance between two vec2's + * + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {Number} distance between a and b + */ +vec2.distance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1]; + return Math.sqrt(x*x + y*y); +}; + +/** + * Alias for {@link vec2.distance} + * @function + */ +vec2.dist = vec2.distance; + +/** + * Calculates the squared euclidian distance between two vec2's + * + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {Number} squared distance between a and b + */ +vec2.squaredDistance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1]; + return x*x + y*y; +}; + +/** + * Alias for {@link vec2.squaredDistance} + * @function + */ +vec2.sqrDist = vec2.squaredDistance; + +/** + * Calculates the length of a vec2 + * + * @param {vec2} a vector to calculate length of + * @returns {Number} length of a + */ +vec2.length = function (a) { + var x = a[0], + y = a[1]; + return Math.sqrt(x*x + y*y); +}; + +/** + * Alias for {@link vec2.length} + * @function + */ +vec2.len = vec2.length; + +/** + * Calculates the squared length of a vec2 + * + * @param {vec2} a vector to calculate squared length of + * @returns {Number} squared length of a + */ +vec2.squaredLength = function (a) { + var x = a[0], + y = a[1]; + return x*x + y*y; +}; + +/** + * Alias for {@link vec2.squaredLength} + * @function + */ +vec2.sqrLen = vec2.squaredLength; + +/** + * Negates the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to negate + * @returns {vec2} out + */ +vec2.negate = function(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + return out; +}; + +/** + * Normalize a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to normalize + * @returns {vec2} out + */ +vec2.normalize = function(out, a) { + var x = a[0], + y = a[1]; + var len = x*x + y*y; + if (len > 0) { + //TODO: evaluate use of glm_invsqrt here? + len = 1 / Math.sqrt(len); + out[0] = a[0] * len; + out[1] = a[1] * len; + } + return out; +}; + +/** + * Calculates the dot product of two vec2's + * + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {Number} dot product of a and b + */ +vec2.dot = function (a, b) { + return a[0] * b[0] + a[1] * b[1]; +}; + +/** + * Computes the cross product of two vec2's + * Note that the cross product must by definition produce a 3D vector + * + * @param {vec3} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec3} out + */ +vec2.cross = function(out, a, b) { + var z = a[0] * b[1] - a[1] * b[0]; + out[0] = out[1] = 0; + out[2] = z; + return out; +}; + +/** + * Performs a linear interpolation between two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {vec2} out + */ +vec2.lerp = function (out, a, b, t) { + var ax = a[0], + ay = a[1]; + out[0] = ax + t * (b[0] - ax); + out[1] = ay + t * (b[1] - ay); + return out; +}; + +/** + * Generates a random vector with the given scale + * + * @param {vec2} out the receiving vector + * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned + * @returns {vec2} out + */ +vec2.random = function (out, scale) { + scale = scale || 1.0; + var r = GLMAT_RANDOM() * 2.0 * Math.PI; + out[0] = Math.cos(r) * scale; + out[1] = Math.sin(r) * scale; + return out; +}; + +/** + * Transforms the vec2 with a mat2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat2} m matrix to transform with + * @returns {vec2} out + */ +vec2.transformMat2 = function(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[2] * y; + out[1] = m[1] * x + m[3] * y; + return out; +}; + +/** + * Transforms the vec2 with a mat2d + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat2d} m matrix to transform with + * @returns {vec2} out + */ +vec2.transformMat2d = function(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[2] * y + m[4]; + out[1] = m[1] * x + m[3] * y + m[5]; + return out; +}; + +/** + * Transforms the vec2 with a mat3 + * 3rd vector component is implicitly '1' + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat3} m matrix to transform with + * @returns {vec2} out + */ +vec2.transformMat3 = function(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[3] * y + m[6]; + out[1] = m[1] * x + m[4] * y + m[7]; + return out; +}; + +/** + * Transforms the vec2 with a mat4 + * 3rd vector component is implicitly '0' + * 4th vector component is implicitly '1' + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat4} m matrix to transform with + * @returns {vec2} out + */ +vec2.transformMat4 = function(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[4] * y + m[12]; + out[1] = m[1] * x + m[5] * y + m[13]; + return out; +}; + +/** + * Perform some operation over an array of vec2s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ +vec2.forEach = (function() { + var vec = vec2.create(); + + return function(a, stride, offset, count, fn, arg) { + var i, l; + if(!stride) { + stride = 2; + } + + if(!offset) { + offset = 0; + } + + if(count) { + l = Math.min((count * stride) + offset, a.length); + } else { + l = a.length; + } + + for(i = offset; i < l; i += stride) { + vec[0] = a[i]; vec[1] = a[i+1]; + fn(vec, vec, arg); + a[i] = vec[0]; a[i+1] = vec[1]; + } + + return a; + }; +})(); + +/** + * Returns a string representation of a vector + * + * @param {vec2} vec vector to represent as a string + * @returns {String} string representation of the vector + */ +vec2.str = function (a) { + return 'vec2(' + a[0] + ', ' + a[1] + ')'; +}; + +if(typeof(exports) !== 'undefined') { + exports.vec2 = vec2; +} +; +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class 3 Dimensional Vector + * @name vec3 + */ + +var vec3 = {}; + +/** + * Creates a new, empty vec3 + * + * @returns {vec3} a new 3D vector + */ +vec3.create = function() { + var out = new GLMAT_ARRAY_TYPE(3); + out[0] = 0; + out[1] = 0; + out[2] = 0; + return out; +}; + +/** + * Creates a new vec3 initialized with values from an existing vector + * + * @param {vec3} a vector to clone + * @returns {vec3} a new 3D vector + */ +vec3.clone = function(a) { + var out = new GLMAT_ARRAY_TYPE(3); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + return out; +}; + +/** + * Creates a new vec3 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @returns {vec3} a new 3D vector + */ +vec3.fromValues = function(x, y, z) { + var out = new GLMAT_ARRAY_TYPE(3); + out[0] = x; + out[1] = y; + out[2] = z; + return out; +}; + +/** + * Copy the values from one vec3 to another + * + * @param {vec3} out the receiving vector + * @param {vec3} a the source vector + * @returns {vec3} out + */ +vec3.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + return out; +}; + +/** + * Set the components of a vec3 to the given values + * + * @param {vec3} out the receiving vector + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @returns {vec3} out + */ +vec3.set = function(out, x, y, z) { + out[0] = x; + out[1] = y; + out[2] = z; + return out; +}; + +/** + * Adds two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.add = function(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + return out; +}; + +/** + * Subtracts vector b from vector a + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.subtract = function(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + return out; +}; + +/** + * Alias for {@link vec3.subtract} + * @function + */ +vec3.sub = vec3.subtract; + +/** + * Multiplies two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.multiply = function(out, a, b) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + out[2] = a[2] * b[2]; + return out; +}; + +/** + * Alias for {@link vec3.multiply} + * @function + */ +vec3.mul = vec3.multiply; + +/** + * Divides two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.divide = function(out, a, b) { + out[0] = a[0] / b[0]; + out[1] = a[1] / b[1]; + out[2] = a[2] / b[2]; + return out; +}; + +/** + * Alias for {@link vec3.divide} + * @function + */ +vec3.div = vec3.divide; + +/** + * Returns the minimum of two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.min = function(out, a, b) { + out[0] = Math.min(a[0], b[0]); + out[1] = Math.min(a[1], b[1]); + out[2] = Math.min(a[2], b[2]); + return out; +}; + +/** + * Returns the maximum of two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.max = function(out, a, b) { + out[0] = Math.max(a[0], b[0]); + out[1] = Math.max(a[1], b[1]); + out[2] = Math.max(a[2], b[2]); + return out; +}; + +/** + * Scales a vec3 by a scalar number + * + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {vec3} out + */ +vec3.scale = function(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + return out; +}; + +/** + * Adds two vec3's after scaling the second operand by a scalar value + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @param {Number} scale the amount to scale b by before adding + * @returns {vec3} out + */ +vec3.scaleAndAdd = function(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + out[2] = a[2] + (b[2] * scale); + return out; +}; + +/** + * Calculates the euclidian distance between two vec3's + * + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {Number} distance between a and b + */ +vec3.distance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1], + z = b[2] - a[2]; + return Math.sqrt(x*x + y*y + z*z); +}; + +/** + * Alias for {@link vec3.distance} + * @function + */ +vec3.dist = vec3.distance; + +/** + * Calculates the squared euclidian distance between two vec3's + * + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {Number} squared distance between a and b + */ +vec3.squaredDistance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1], + z = b[2] - a[2]; + return x*x + y*y + z*z; +}; + +/** + * Alias for {@link vec3.squaredDistance} + * @function + */ +vec3.sqrDist = vec3.squaredDistance; + +/** + * Calculates the length of a vec3 + * + * @param {vec3} a vector to calculate length of + * @returns {Number} length of a + */ +vec3.length = function (a) { + var x = a[0], + y = a[1], + z = a[2]; + return Math.sqrt(x*x + y*y + z*z); +}; + +/** + * Alias for {@link vec3.length} + * @function + */ +vec3.len = vec3.length; + +/** + * Calculates the squared length of a vec3 + * + * @param {vec3} a vector to calculate squared length of + * @returns {Number} squared length of a + */ +vec3.squaredLength = function (a) { + var x = a[0], + y = a[1], + z = a[2]; + return x*x + y*y + z*z; +}; + +/** + * Alias for {@link vec3.squaredLength} + * @function + */ +vec3.sqrLen = vec3.squaredLength; + +/** + * Negates the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to negate + * @returns {vec3} out + */ +vec3.negate = function(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + return out; +}; + +/** + * Normalize a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to normalize + * @returns {vec3} out + */ +vec3.normalize = function(out, a) { + var x = a[0], + y = a[1], + z = a[2]; + var len = x*x + y*y + z*z; + if (len > 0) { + //TODO: evaluate use of glm_invsqrt here? + len = 1 / Math.sqrt(len); + out[0] = a[0] * len; + out[1] = a[1] * len; + out[2] = a[2] * len; + } + return out; +}; + +/** + * Calculates the dot product of two vec3's + * + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {Number} dot product of a and b + */ +vec3.dot = function (a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; +}; + +/** + * Computes the cross product of two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.cross = function(out, a, b) { + var ax = a[0], ay = a[1], az = a[2], + bx = b[0], by = b[1], bz = b[2]; + + out[0] = ay * bz - az * by; + out[1] = az * bx - ax * bz; + out[2] = ax * by - ay * bx; + return out; +}; + +/** + * Performs a linear interpolation between two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {vec3} out + */ +vec3.lerp = function (out, a, b, t) { + var ax = a[0], + ay = a[1], + az = a[2]; + out[0] = ax + t * (b[0] - ax); + out[1] = ay + t * (b[1] - ay); + out[2] = az + t * (b[2] - az); + return out; +}; + +/** + * Generates a random vector with the given scale + * + * @param {vec3} out the receiving vector + * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned + * @returns {vec3} out + */ +vec3.random = function (out, scale) { + scale = scale || 1.0; + + var r = GLMAT_RANDOM() * 2.0 * Math.PI; + var z = (GLMAT_RANDOM() * 2.0) - 1.0; + var zScale = Math.sqrt(1.0-z*z) * scale; + + out[0] = Math.cos(r) * zScale; + out[1] = Math.sin(r) * zScale; + out[2] = z * scale; + return out; +}; + +/** + * Transforms the vec3 with a mat4. + * 4th vector component is implicitly '1' + * + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to transform + * @param {mat4} m matrix to transform with + * @returns {vec3} out + */ +vec3.transformMat4 = function(out, a, m) { + var x = a[0], y = a[1], z = a[2]; + out[0] = m[0] * x + m[4] * y + m[8] * z + m[12]; + out[1] = m[1] * x + m[5] * y + m[9] * z + m[13]; + out[2] = m[2] * x + m[6] * y + m[10] * z + m[14]; + return out; +}; + +/** + * Transforms the vec3 with a mat3. + * + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to transform + * @param {mat4} m the 3x3 matrix to transform with + * @returns {vec3} out + */ +vec3.transformMat3 = function(out, a, m) { + var x = a[0], y = a[1], z = a[2]; + out[0] = x * m[0] + y * m[3] + z * m[6]; + out[1] = x * m[1] + y * m[4] + z * m[7]; + out[2] = x * m[2] + y * m[5] + z * m[8]; + return out; +}; + +/** + * Transforms the vec3 with a quat + * + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to transform + * @param {quat} q quaternion to transform with + * @returns {vec3} out + */ +vec3.transformQuat = function(out, a, q) { + // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations + + var x = a[0], y = a[1], z = a[2], + qx = q[0], qy = q[1], qz = q[2], qw = q[3], + + // calculate quat * vec + ix = qw * x + qy * z - qz * y, + iy = qw * y + qz * x - qx * z, + iz = qw * z + qx * y - qy * x, + iw = -qx * x - qy * y - qz * z; + + // calculate result * inverse quat + out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; + out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; + out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; + return out; +}; + +/* +* Rotate a 3D vector around the x-axis +* @param {vec3} out The receiving vec3 +* @param {vec3} a The vec3 point to rotate +* @param {vec3} b The origin of the rotation +* @param {Number} c The angle of rotation +* @returns {vec3} out +*/ +vec3.rotateX = function(out, a, b, c){ + var p = [], r=[]; + //Translate point to the origin + p[0] = a[0] - b[0]; + p[1] = a[1] - b[1]; + p[2] = a[2] - b[2]; + + //perform rotation + r[0] = p[0]; + r[1] = p[1]*Math.cos(c) - p[2]*Math.sin(c); + r[2] = p[1]*Math.sin(c) + p[2]*Math.cos(c); + + //translate to correct position + out[0] = r[0] + b[0]; + out[1] = r[1] + b[1]; + out[2] = r[2] + b[2]; + + return out; +}; + +/* +* Rotate a 3D vector around the y-axis +* @param {vec3} out The receiving vec3 +* @param {vec3} a The vec3 point to rotate +* @param {vec3} b The origin of the rotation +* @param {Number} c The angle of rotation +* @returns {vec3} out +*/ +vec3.rotateY = function(out, a, b, c){ + var p = [], r=[]; + //Translate point to the origin + p[0] = a[0] - b[0]; + p[1] = a[1] - b[1]; + p[2] = a[2] - b[2]; + + //perform rotation + r[0] = p[2]*Math.sin(c) + p[0]*Math.cos(c); + r[1] = p[1]; + r[2] = p[2]*Math.cos(c) - p[0]*Math.sin(c); + + //translate to correct position + out[0] = r[0] + b[0]; + out[1] = r[1] + b[1]; + out[2] = r[2] + b[2]; + + return out; +}; + +/* +* Rotate a 3D vector around the z-axis +* @param {vec3} out The receiving vec3 +* @param {vec3} a The vec3 point to rotate +* @param {vec3} b The origin of the rotation +* @param {Number} c The angle of rotation +* @returns {vec3} out +*/ +vec3.rotateZ = function(out, a, b, c){ + var p = [], r=[]; + //Translate point to the origin + p[0] = a[0] - b[0]; + p[1] = a[1] - b[1]; + p[2] = a[2] - b[2]; + + //perform rotation + r[0] = p[0]*Math.cos(c) - p[1]*Math.sin(c); + r[1] = p[0]*Math.sin(c) + p[1]*Math.cos(c); + r[2] = p[2]; + + //translate to correct position + out[0] = r[0] + b[0]; + out[1] = r[1] + b[1]; + out[2] = r[2] + b[2]; + + return out; +}; + +/** + * Perform some operation over an array of vec3s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ +vec3.forEach = (function() { + var vec = vec3.create(); + + return function(a, stride, offset, count, fn, arg) { + var i, l; + if(!stride) { + stride = 3; + } + + if(!offset) { + offset = 0; + } + + if(count) { + l = Math.min((count * stride) + offset, a.length); + } else { + l = a.length; + } + + for(i = offset; i < l; i += stride) { + vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; + fn(vec, vec, arg); + a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; + } + + return a; + }; +})(); + +/** + * Returns a string representation of a vector + * + * @param {vec3} vec vector to represent as a string + * @returns {String} string representation of the vector + */ +vec3.str = function (a) { + return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')'; +}; + +if(typeof(exports) !== 'undefined') { + exports.vec3 = vec3; +} +; +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class 4 Dimensional Vector + * @name vec4 + */ + +var vec4 = {}; + +/** + * Creates a new, empty vec4 + * + * @returns {vec4} a new 4D vector + */ +vec4.create = function() { + var out = new GLMAT_ARRAY_TYPE(4); + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 0; + return out; +}; + +/** + * Creates a new vec4 initialized with values from an existing vector + * + * @param {vec4} a vector to clone + * @returns {vec4} a new 4D vector + */ +vec4.clone = function(a) { + var out = new GLMAT_ARRAY_TYPE(4); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +}; + +/** + * Creates a new vec4 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {vec4} a new 4D vector + */ +vec4.fromValues = function(x, y, z, w) { + var out = new GLMAT_ARRAY_TYPE(4); + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = w; + return out; +}; + +/** + * Copy the values from one vec4 to another + * + * @param {vec4} out the receiving vector + * @param {vec4} a the source vector + * @returns {vec4} out + */ +vec4.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +}; + +/** + * Set the components of a vec4 to the given values + * + * @param {vec4} out the receiving vector + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {vec4} out + */ +vec4.set = function(out, x, y, z, w) { + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = w; + return out; +}; + +/** + * Adds two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.add = function(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + return out; +}; + +/** + * Subtracts vector b from vector a + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.subtract = function(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + return out; +}; + +/** + * Alias for {@link vec4.subtract} + * @function + */ +vec4.sub = vec4.subtract; + +/** + * Multiplies two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.multiply = function(out, a, b) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + out[2] = a[2] * b[2]; + out[3] = a[3] * b[3]; + return out; +}; + +/** + * Alias for {@link vec4.multiply} + * @function + */ +vec4.mul = vec4.multiply; + +/** + * Divides two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.divide = function(out, a, b) { + out[0] = a[0] / b[0]; + out[1] = a[1] / b[1]; + out[2] = a[2] / b[2]; + out[3] = a[3] / b[3]; + return out; +}; + +/** + * Alias for {@link vec4.divide} + * @function + */ +vec4.div = vec4.divide; + +/** + * Returns the minimum of two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.min = function(out, a, b) { + out[0] = Math.min(a[0], b[0]); + out[1] = Math.min(a[1], b[1]); + out[2] = Math.min(a[2], b[2]); + out[3] = Math.min(a[3], b[3]); + return out; +}; + +/** + * Returns the maximum of two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.max = function(out, a, b) { + out[0] = Math.max(a[0], b[0]); + out[1] = Math.max(a[1], b[1]); + out[2] = Math.max(a[2], b[2]); + out[3] = Math.max(a[3], b[3]); + return out; +}; + +/** + * Scales a vec4 by a scalar number + * + * @param {vec4} out the receiving vector + * @param {vec4} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {vec4} out + */ +vec4.scale = function(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + return out; +}; + +/** + * Adds two vec4's after scaling the second operand by a scalar value + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @param {Number} scale the amount to scale b by before adding + * @returns {vec4} out + */ +vec4.scaleAndAdd = function(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + out[2] = a[2] + (b[2] * scale); + out[3] = a[3] + (b[3] * scale); + return out; +}; + +/** + * Calculates the euclidian distance between two vec4's + * + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {Number} distance between a and b + */ +vec4.distance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1], + z = b[2] - a[2], + w = b[3] - a[3]; + return Math.sqrt(x*x + y*y + z*z + w*w); +}; + +/** + * Alias for {@link vec4.distance} + * @function + */ +vec4.dist = vec4.distance; + +/** + * Calculates the squared euclidian distance between two vec4's + * + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {Number} squared distance between a and b + */ +vec4.squaredDistance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1], + z = b[2] - a[2], + w = b[3] - a[3]; + return x*x + y*y + z*z + w*w; +}; + +/** + * Alias for {@link vec4.squaredDistance} + * @function + */ +vec4.sqrDist = vec4.squaredDistance; + +/** + * Calculates the length of a vec4 + * + * @param {vec4} a vector to calculate length of + * @returns {Number} length of a + */ +vec4.length = function (a) { + var x = a[0], + y = a[1], + z = a[2], + w = a[3]; + return Math.sqrt(x*x + y*y + z*z + w*w); +}; + +/** + * Alias for {@link vec4.length} + * @function + */ +vec4.len = vec4.length; + +/** + * Calculates the squared length of a vec4 + * + * @param {vec4} a vector to calculate squared length of + * @returns {Number} squared length of a + */ +vec4.squaredLength = function (a) { + var x = a[0], + y = a[1], + z = a[2], + w = a[3]; + return x*x + y*y + z*z + w*w; +}; + +/** + * Alias for {@link vec4.squaredLength} + * @function + */ +vec4.sqrLen = vec4.squaredLength; + +/** + * Negates the components of a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to negate + * @returns {vec4} out + */ +vec4.negate = function(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = -a[3]; + return out; +}; + +/** + * Normalize a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to normalize + * @returns {vec4} out + */ +vec4.normalize = function(out, a) { + var x = a[0], + y = a[1], + z = a[2], + w = a[3]; + var len = x*x + y*y + z*z + w*w; + if (len > 0) { + len = 1 / Math.sqrt(len); + out[0] = a[0] * len; + out[1] = a[1] * len; + out[2] = a[2] * len; + out[3] = a[3] * len; + } + return out; +}; + +/** + * Calculates the dot product of two vec4's + * + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {Number} dot product of a and b + */ +vec4.dot = function (a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; +}; + +/** + * Performs a linear interpolation between two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {vec4} out + */ +vec4.lerp = function (out, a, b, t) { + var ax = a[0], + ay = a[1], + az = a[2], + aw = a[3]; + out[0] = ax + t * (b[0] - ax); + out[1] = ay + t * (b[1] - ay); + out[2] = az + t * (b[2] - az); + out[3] = aw + t * (b[3] - aw); + return out; +}; + +/** + * Generates a random vector with the given scale + * + * @param {vec4} out the receiving vector + * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned + * @returns {vec4} out + */ +vec4.random = function (out, scale) { + scale = scale || 1.0; + + //TODO: This is a pretty awful way of doing this. Find something better. + out[0] = GLMAT_RANDOM(); + out[1] = GLMAT_RANDOM(); + out[2] = GLMAT_RANDOM(); + out[3] = GLMAT_RANDOM(); + vec4.normalize(out, out); + vec4.scale(out, out, scale); + return out; +}; + +/** + * Transforms the vec4 with a mat4. + * + * @param {vec4} out the receiving vector + * @param {vec4} a the vector to transform + * @param {mat4} m matrix to transform with + * @returns {vec4} out + */ +vec4.transformMat4 = function(out, a, m) { + var x = a[0], y = a[1], z = a[2], w = a[3]; + out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w; + out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w; + out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w; + out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w; + return out; +}; + +/** + * Transforms the vec4 with a quat + * + * @param {vec4} out the receiving vector + * @param {vec4} a the vector to transform + * @param {quat} q quaternion to transform with + * @returns {vec4} out + */ +vec4.transformQuat = function(out, a, q) { + var x = a[0], y = a[1], z = a[2], + qx = q[0], qy = q[1], qz = q[2], qw = q[3], + + // calculate quat * vec + ix = qw * x + qy * z - qz * y, + iy = qw * y + qz * x - qx * z, + iz = qw * z + qx * y - qy * x, + iw = -qx * x - qy * y - qz * z; + + // calculate result * inverse quat + out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; + out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; + out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; + return out; +}; + +/** + * Perform some operation over an array of vec4s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ +vec4.forEach = (function() { + var vec = vec4.create(); + + return function(a, stride, offset, count, fn, arg) { + var i, l; + if(!stride) { + stride = 4; + } + + if(!offset) { + offset = 0; + } + + if(count) { + l = Math.min((count * stride) + offset, a.length); + } else { + l = a.length; + } + + for(i = offset; i < l; i += stride) { + vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3]; + fn(vec, vec, arg); + a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3]; + } + + return a; + }; +})(); + +/** + * Returns a string representation of a vector + * + * @param {vec4} vec vector to represent as a string + * @returns {String} string representation of the vector + */ +vec4.str = function (a) { + return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; +}; + +if(typeof(exports) !== 'undefined') { + exports.vec4 = vec4; +} +; +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class 2x2 Matrix + * @name mat2 + */ + +var mat2 = {}; + +/** + * Creates a new identity mat2 + * + * @returns {mat2} a new 2x2 matrix + */ +mat2.create = function() { + var out = new GLMAT_ARRAY_TYPE(4); + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; +}; + +/** + * Creates a new mat2 initialized with values from an existing matrix + * + * @param {mat2} a matrix to clone + * @returns {mat2} a new 2x2 matrix + */ +mat2.clone = function(a) { + var out = new GLMAT_ARRAY_TYPE(4); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +}; + +/** + * Copy the values from one mat2 to another + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ +mat2.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +}; + +/** + * Set a mat2 to the identity matrix + * + * @param {mat2} out the receiving matrix + * @returns {mat2} out + */ +mat2.identity = function(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; +}; + +/** + * Transpose the values of a mat2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ +mat2.transpose = function(out, a) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (out === a) { + var a1 = a[1]; + out[1] = a[2]; + out[2] = a1; + } else { + out[0] = a[0]; + out[1] = a[2]; + out[2] = a[1]; + out[3] = a[3]; + } + + return out; +}; + +/** + * Inverts a mat2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ +mat2.invert = function(out, a) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], + + // Calculate the determinant + det = a0 * a3 - a2 * a1; + + if (!det) { + return null; + } + det = 1.0 / det; + + out[0] = a3 * det; + out[1] = -a1 * det; + out[2] = -a2 * det; + out[3] = a0 * det; + + return out; +}; + +/** + * Calculates the adjugate of a mat2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ +mat2.adjoint = function(out, a) { + // Caching this value is nessecary if out == a + var a0 = a[0]; + out[0] = a[3]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = a0; + + return out; +}; + +/** + * Calculates the determinant of a mat2 + * + * @param {mat2} a the source matrix + * @returns {Number} determinant of a + */ +mat2.determinant = function (a) { + return a[0] * a[3] - a[2] * a[1]; +}; + +/** + * Multiplies two mat2's + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the first operand + * @param {mat2} b the second operand + * @returns {mat2} out + */ +mat2.multiply = function (out, a, b) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; + var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; + out[0] = a0 * b0 + a2 * b1; + out[1] = a1 * b0 + a3 * b1; + out[2] = a0 * b2 + a2 * b3; + out[3] = a1 * b2 + a3 * b3; + return out; +}; + +/** + * Alias for {@link mat2.multiply} + * @function + */ +mat2.mul = mat2.multiply; + +/** + * Rotates a mat2 by the given angle + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat2} out + */ +mat2.rotate = function (out, a, rad) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], + s = Math.sin(rad), + c = Math.cos(rad); + out[0] = a0 * c + a2 * s; + out[1] = a1 * c + a3 * s; + out[2] = a0 * -s + a2 * c; + out[3] = a1 * -s + a3 * c; + return out; +}; + +/** + * Scales the mat2 by the dimensions in the given vec2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the matrix to rotate + * @param {vec2} v the vec2 to scale the matrix by + * @returns {mat2} out + **/ +mat2.scale = function(out, a, v) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], + v0 = v[0], v1 = v[1]; + out[0] = a0 * v0; + out[1] = a1 * v0; + out[2] = a2 * v1; + out[3] = a3 * v1; + return out; +}; + +/** + * Returns a string representation of a mat2 + * + * @param {mat2} mat matrix to represent as a string + * @returns {String} string representation of the matrix + */ +mat2.str = function (a) { + return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; +}; + +/** + * Returns Frobenius norm of a mat2 + * + * @param {mat2} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ +mat2.frob = function (a) { + return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2))) +}; + +/** + * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix + * @param {mat2} L the lower triangular matrix + * @param {mat2} D the diagonal matrix + * @param {mat2} U the upper triangular matrix + * @param {mat2} a the input matrix to factorize + */ + +mat2.LDU = function (L, D, U, a) { + L[2] = a[2]/a[0]; + U[0] = a[0]; + U[1] = a[1]; + U[3] = a[3] - L[2] * U[1]; + return [L, D, U]; +}; + +if(typeof(exports) !== 'undefined') { + exports.mat2 = mat2; +} +; +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class 2x3 Matrix + * @name mat2d + * + * @description + * A mat2d contains six elements defined as: + *
+ * [a, c, tx,
+ *  b, d, ty]
+ * 
+ * This is a short form for the 3x3 matrix: + *
+ * [a, c, tx,
+ *  b, d, ty,
+ *  0, 0, 1]
+ * 
+ * The last row is ignored so the array is shorter and operations are faster. + */ + +var mat2d = {}; + +/** + * Creates a new identity mat2d + * + * @returns {mat2d} a new 2x3 matrix + */ +mat2d.create = function() { + var out = new GLMAT_ARRAY_TYPE(6); + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = 0; + out[5] = 0; + return out; +}; + +/** + * Creates a new mat2d initialized with values from an existing matrix + * + * @param {mat2d} a matrix to clone + * @returns {mat2d} a new 2x3 matrix + */ +mat2d.clone = function(a) { + var out = new GLMAT_ARRAY_TYPE(6); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + return out; +}; + +/** + * Copy the values from one mat2d to another + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the source matrix + * @returns {mat2d} out + */ +mat2d.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + return out; +}; + +/** + * Set a mat2d to the identity matrix + * + * @param {mat2d} out the receiving matrix + * @returns {mat2d} out + */ +mat2d.identity = function(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = 0; + out[5] = 0; + return out; +}; + +/** + * Inverts a mat2d + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the source matrix + * @returns {mat2d} out + */ +mat2d.invert = function(out, a) { + var aa = a[0], ab = a[1], ac = a[2], ad = a[3], + atx = a[4], aty = a[5]; + + var det = aa * ad - ab * ac; + if(!det){ + return null; + } + det = 1.0 / det; + + out[0] = ad * det; + out[1] = -ab * det; + out[2] = -ac * det; + out[3] = aa * det; + out[4] = (ac * aty - ad * atx) * det; + out[5] = (ab * atx - aa * aty) * det; + return out; +}; + +/** + * Calculates the determinant of a mat2d + * + * @param {mat2d} a the source matrix + * @returns {Number} determinant of a + */ +mat2d.determinant = function (a) { + return a[0] * a[3] - a[1] * a[2]; +}; + +/** + * Multiplies two mat2d's + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the first operand + * @param {mat2d} b the second operand + * @returns {mat2d} out + */ +mat2d.multiply = function (out, a, b) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], + b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5]; + out[0] = a0 * b0 + a2 * b1; + out[1] = a1 * b0 + a3 * b1; + out[2] = a0 * b2 + a2 * b3; + out[3] = a1 * b2 + a3 * b3; + out[4] = a0 * b4 + a2 * b5 + a4; + out[5] = a1 * b4 + a3 * b5 + a5; + return out; +}; + +/** + * Alias for {@link mat2d.multiply} + * @function + */ +mat2d.mul = mat2d.multiply; + + +/** + * Rotates a mat2d by the given angle + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat2d} out + */ +mat2d.rotate = function (out, a, rad) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], + s = Math.sin(rad), + c = Math.cos(rad); + out[0] = a0 * c + a2 * s; + out[1] = a1 * c + a3 * s; + out[2] = a0 * -s + a2 * c; + out[3] = a1 * -s + a3 * c; + out[4] = a4; + out[5] = a5; + return out; +}; + +/** + * Scales the mat2d by the dimensions in the given vec2 + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the matrix to translate + * @param {vec2} v the vec2 to scale the matrix by + * @returns {mat2d} out + **/ +mat2d.scale = function(out, a, v) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], + v0 = v[0], v1 = v[1]; + out[0] = a0 * v0; + out[1] = a1 * v0; + out[2] = a2 * v1; + out[3] = a3 * v1; + out[4] = a4; + out[5] = a5; + return out; +}; + +/** + * Translates the mat2d by the dimensions in the given vec2 + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the matrix to translate + * @param {vec2} v the vec2 to translate the matrix by + * @returns {mat2d} out + **/ +mat2d.translate = function(out, a, v) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], + v0 = v[0], v1 = v[1]; + out[0] = a0; + out[1] = a1; + out[2] = a2; + out[3] = a3; + out[4] = a0 * v0 + a2 * v1 + a4; + out[5] = a1 * v0 + a3 * v1 + a5; + return out; +}; + +/** + * Returns a string representation of a mat2d + * + * @param {mat2d} a matrix to represent as a string + * @returns {String} string representation of the matrix + */ +mat2d.str = function (a) { + return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + + a[3] + ', ' + a[4] + ', ' + a[5] + ')'; +}; + +/** + * Returns Frobenius norm of a mat2d + * + * @param {mat2d} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ +mat2d.frob = function (a) { + return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + 1)) +}; + +if(typeof(exports) !== 'undefined') { + exports.mat2d = mat2d; +} +; +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class 3x3 Matrix + * @name mat3 + */ + +var mat3 = {}; + +/** + * Creates a new identity mat3 + * + * @returns {mat3} a new 3x3 matrix + */ +mat3.create = function() { + var out = new GLMAT_ARRAY_TYPE(9); + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 1; + out[5] = 0; + out[6] = 0; + out[7] = 0; + out[8] = 1; + return out; +}; + +/** + * Copies the upper-left 3x3 values into the given mat3. + * + * @param {mat3} out the receiving 3x3 matrix + * @param {mat4} a the source 4x4 matrix + * @returns {mat3} out + */ +mat3.fromMat4 = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[4]; + out[4] = a[5]; + out[5] = a[6]; + out[6] = a[8]; + out[7] = a[9]; + out[8] = a[10]; + return out; +}; + +/** + * Creates a new mat3 initialized with values from an existing matrix + * + * @param {mat3} a matrix to clone + * @returns {mat3} a new 3x3 matrix + */ +mat3.clone = function(a) { + var out = new GLMAT_ARRAY_TYPE(9); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + return out; +}; + +/** + * Copy the values from one mat3 to another + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out + */ +mat3.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + return out; +}; + +/** + * Set a mat3 to the identity matrix + * + * @param {mat3} out the receiving matrix + * @returns {mat3} out + */ +mat3.identity = function(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 1; + out[5] = 0; + out[6] = 0; + out[7] = 0; + out[8] = 1; + return out; +}; + +/** + * Transpose the values of a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out + */ +mat3.transpose = function(out, a) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (out === a) { + var a01 = a[1], a02 = a[2], a12 = a[5]; + out[1] = a[3]; + out[2] = a[6]; + out[3] = a01; + out[5] = a[7]; + out[6] = a02; + out[7] = a12; + } else { + out[0] = a[0]; + out[1] = a[3]; + out[2] = a[6]; + out[3] = a[1]; + out[4] = a[4]; + out[5] = a[7]; + out[6] = a[2]; + out[7] = a[5]; + out[8] = a[8]; + } + + return out; +}; + +/** + * Inverts a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out + */ +mat3.invert = function(out, a) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8], + + b01 = a22 * a11 - a12 * a21, + b11 = -a22 * a10 + a12 * a20, + b21 = a21 * a10 - a11 * a20, + + // Calculate the determinant + det = a00 * b01 + a01 * b11 + a02 * b21; + + if (!det) { + return null; + } + det = 1.0 / det; + + out[0] = b01 * det; + out[1] = (-a22 * a01 + a02 * a21) * det; + out[2] = (a12 * a01 - a02 * a11) * det; + out[3] = b11 * det; + out[4] = (a22 * a00 - a02 * a20) * det; + out[5] = (-a12 * a00 + a02 * a10) * det; + out[6] = b21 * det; + out[7] = (-a21 * a00 + a01 * a20) * det; + out[8] = (a11 * a00 - a01 * a10) * det; + return out; +}; + +/** + * Calculates the adjugate of a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out + */ +mat3.adjoint = function(out, a) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8]; + + out[0] = (a11 * a22 - a12 * a21); + out[1] = (a02 * a21 - a01 * a22); + out[2] = (a01 * a12 - a02 * a11); + out[3] = (a12 * a20 - a10 * a22); + out[4] = (a00 * a22 - a02 * a20); + out[5] = (a02 * a10 - a00 * a12); + out[6] = (a10 * a21 - a11 * a20); + out[7] = (a01 * a20 - a00 * a21); + out[8] = (a00 * a11 - a01 * a10); + return out; +}; + +/** + * Calculates the determinant of a mat3 + * + * @param {mat3} a the source matrix + * @returns {Number} determinant of a + */ +mat3.determinant = function (a) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8]; + + return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20); +}; + +/** + * Multiplies two mat3's + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the first operand + * @param {mat3} b the second operand + * @returns {mat3} out + */ +mat3.multiply = function (out, a, b) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8], + + b00 = b[0], b01 = b[1], b02 = b[2], + b10 = b[3], b11 = b[4], b12 = b[5], + b20 = b[6], b21 = b[7], b22 = b[8]; + + out[0] = b00 * a00 + b01 * a10 + b02 * a20; + out[1] = b00 * a01 + b01 * a11 + b02 * a21; + out[2] = b00 * a02 + b01 * a12 + b02 * a22; + + out[3] = b10 * a00 + b11 * a10 + b12 * a20; + out[4] = b10 * a01 + b11 * a11 + b12 * a21; + out[5] = b10 * a02 + b11 * a12 + b12 * a22; + + out[6] = b20 * a00 + b21 * a10 + b22 * a20; + out[7] = b20 * a01 + b21 * a11 + b22 * a21; + out[8] = b20 * a02 + b21 * a12 + b22 * a22; + return out; +}; + +/** + * Alias for {@link mat3.multiply} + * @function + */ +mat3.mul = mat3.multiply; + +/** + * Translate a mat3 by the given vector + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the matrix to translate + * @param {vec2} v vector to translate by + * @returns {mat3} out + */ +mat3.translate = function(out, a, v) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8], + x = v[0], y = v[1]; + + out[0] = a00; + out[1] = a01; + out[2] = a02; + + out[3] = a10; + out[4] = a11; + out[5] = a12; + + out[6] = x * a00 + y * a10 + a20; + out[7] = x * a01 + y * a11 + a21; + out[8] = x * a02 + y * a12 + a22; + return out; +}; + +/** + * Rotates a mat3 by the given angle + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat3} out + */ +mat3.rotate = function (out, a, rad) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8], + + s = Math.sin(rad), + c = Math.cos(rad); + + out[0] = c * a00 + s * a10; + out[1] = c * a01 + s * a11; + out[2] = c * a02 + s * a12; + + out[3] = c * a10 - s * a00; + out[4] = c * a11 - s * a01; + out[5] = c * a12 - s * a02; + + out[6] = a20; + out[7] = a21; + out[8] = a22; + return out; +}; + +/** + * Scales the mat3 by the dimensions in the given vec2 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the matrix to rotate + * @param {vec2} v the vec2 to scale the matrix by + * @returns {mat3} out + **/ +mat3.scale = function(out, a, v) { + var x = v[0], y = v[1]; + + out[0] = x * a[0]; + out[1] = x * a[1]; + out[2] = x * a[2]; + + out[3] = y * a[3]; + out[4] = y * a[4]; + out[5] = y * a[5]; + + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + return out; +}; + +/** + * Copies the values from a mat2d into a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat2d} a the matrix to copy + * @returns {mat3} out + **/ +mat3.fromMat2d = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = 0; + + out[3] = a[2]; + out[4] = a[3]; + out[5] = 0; + + out[6] = a[4]; + out[7] = a[5]; + out[8] = 1; + return out; +}; + +/** +* Calculates a 3x3 matrix from the given quaternion +* +* @param {mat3} out mat3 receiving operation result +* @param {quat} q Quaternion to create matrix from +* +* @returns {mat3} out +*/ +mat3.fromQuat = function (out, q) { + var x = q[0], y = q[1], z = q[2], w = q[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, + + xx = x * x2, + yx = y * x2, + yy = y * y2, + zx = z * x2, + zy = z * y2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; + + out[0] = 1 - yy - zz; + out[3] = yx - wz; + out[6] = zx + wy; + + out[1] = yx + wz; + out[4] = 1 - xx - zz; + out[7] = zy - wx; + + out[2] = zx - wy; + out[5] = zy + wx; + out[8] = 1 - xx - yy; + + return out; +}; + +/** +* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix +* +* @param {mat3} out mat3 receiving operation result +* @param {mat4} a Mat4 to derive the normal matrix from +* +* @returns {mat3} out +*/ +mat3.normalFromMat4 = function (out, a) { + var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], + + b00 = a00 * a11 - a01 * a10, + b01 = a00 * a12 - a02 * a10, + b02 = a00 * a13 - a03 * a10, + b03 = a01 * a12 - a02 * a11, + b04 = a01 * a13 - a03 * a11, + b05 = a02 * a13 - a03 * a12, + b06 = a20 * a31 - a21 * a30, + b07 = a20 * a32 - a22 * a30, + b08 = a20 * a33 - a23 * a30, + b09 = a21 * a32 - a22 * a31, + b10 = a21 * a33 - a23 * a31, + b11 = a22 * a33 - a23 * a32, + + // Calculate the determinant + det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; + + if (!det) { + return null; + } + det = 1.0 / det; + + out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; + out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det; + out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det; + + out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det; + out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det; + out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det; + + out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det; + out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det; + out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det; + + return out; +}; + +/** + * Returns a string representation of a mat3 + * + * @param {mat3} mat matrix to represent as a string + * @returns {String} string representation of the matrix + */ +mat3.str = function (a) { + return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + + a[6] + ', ' + a[7] + ', ' + a[8] + ')'; +}; + +/** + * Returns Frobenius norm of a mat3 + * + * @param {mat3} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ +mat3.frob = function (a) { + return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2))) +}; + + +if(typeof(exports) !== 'undefined') { + exports.mat3 = mat3; +} +; +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class 4x4 Matrix + * @name mat4 + */ + +var mat4 = {}; + +/** + * Creates a new identity mat4 + * + * @returns {mat4} a new 4x4 matrix + */ +mat4.create = function() { + var out = new GLMAT_ARRAY_TYPE(16); + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; +}; + +/** + * Creates a new mat4 initialized with values from an existing matrix + * + * @param {mat4} a matrix to clone + * @returns {mat4} a new 4x4 matrix + */ +mat4.clone = function(a) { + var out = new GLMAT_ARRAY_TYPE(16); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; +}; + +/** + * Copy the values from one mat4 to another + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +mat4.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; +}; + +/** + * Set a mat4 to the identity matrix + * + * @param {mat4} out the receiving matrix + * @returns {mat4} out + */ +mat4.identity = function(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; +}; + +/** + * Transpose the values of a mat4 + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +mat4.transpose = function(out, a) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (out === a) { + var a01 = a[1], a02 = a[2], a03 = a[3], + a12 = a[6], a13 = a[7], + a23 = a[11]; + + out[1] = a[4]; + out[2] = a[8]; + out[3] = a[12]; + out[4] = a01; + out[6] = a[9]; + out[7] = a[13]; + out[8] = a02; + out[9] = a12; + out[11] = a[14]; + out[12] = a03; + out[13] = a13; + out[14] = a23; + } else { + out[0] = a[0]; + out[1] = a[4]; + out[2] = a[8]; + out[3] = a[12]; + out[4] = a[1]; + out[5] = a[5]; + out[6] = a[9]; + out[7] = a[13]; + out[8] = a[2]; + out[9] = a[6]; + out[10] = a[10]; + out[11] = a[14]; + out[12] = a[3]; + out[13] = a[7]; + out[14] = a[11]; + out[15] = a[15]; + } + + return out; +}; + +/** + * Inverts a mat4 + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +mat4.invert = function(out, a) { + var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], + + b00 = a00 * a11 - a01 * a10, + b01 = a00 * a12 - a02 * a10, + b02 = a00 * a13 - a03 * a10, + b03 = a01 * a12 - a02 * a11, + b04 = a01 * a13 - a03 * a11, + b05 = a02 * a13 - a03 * a12, + b06 = a20 * a31 - a21 * a30, + b07 = a20 * a32 - a22 * a30, + b08 = a20 * a33 - a23 * a30, + b09 = a21 * a32 - a22 * a31, + b10 = a21 * a33 - a23 * a31, + b11 = a22 * a33 - a23 * a32, + + // Calculate the determinant + det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; + + if (!det) { + return null; + } + det = 1.0 / det; + + out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; + out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; + out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; + out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; + out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; + out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; + out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; + out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; + out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; + out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; + out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; + out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; + out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; + out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; + out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; + out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; + + return out; +}; + +/** + * Calculates the adjugate of a mat4 + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +mat4.adjoint = function(out, a) { + var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; + + out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22)); + out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22)); + out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12)); + out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12)); + out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22)); + out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22)); + out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12)); + out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12)); + out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21)); + out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21)); + out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11)); + out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11)); + out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21)); + out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21)); + out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11)); + out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11)); + return out; +}; + +/** + * Calculates the determinant of a mat4 + * + * @param {mat4} a the source matrix + * @returns {Number} determinant of a + */ +mat4.determinant = function (a) { + var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], + + b00 = a00 * a11 - a01 * a10, + b01 = a00 * a12 - a02 * a10, + b02 = a00 * a13 - a03 * a10, + b03 = a01 * a12 - a02 * a11, + b04 = a01 * a13 - a03 * a11, + b05 = a02 * a13 - a03 * a12, + b06 = a20 * a31 - a21 * a30, + b07 = a20 * a32 - a22 * a30, + b08 = a20 * a33 - a23 * a30, + b09 = a21 * a32 - a22 * a31, + b10 = a21 * a33 - a23 * a31, + b11 = a22 * a33 - a23 * a32; + + // Calculate the determinant + return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; +}; + +/** + * Multiplies two mat4's + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the first operand + * @param {mat4} b the second operand + * @returns {mat4} out + */ +mat4.multiply = function (out, a, b) { + var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; + + // Cache only the current line of the second matrix + var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; + out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; + out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; + out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; + out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + return out; +}; + +/** + * Alias for {@link mat4.multiply} + * @function + */ +mat4.mul = mat4.multiply; + +/** + * Translate a mat4 by the given vector + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to translate + * @param {vec3} v vector to translate by + * @returns {mat4} out + */ +mat4.translate = function (out, a, v) { + var x = v[0], y = v[1], z = v[2], + a00, a01, a02, a03, + a10, a11, a12, a13, + a20, a21, a22, a23; + + if (a === out) { + out[12] = a[0] * x + a[4] * y + a[8] * z + a[12]; + out[13] = a[1] * x + a[5] * y + a[9] * z + a[13]; + out[14] = a[2] * x + a[6] * y + a[10] * z + a[14]; + out[15] = a[3] * x + a[7] * y + a[11] * z + a[15]; + } else { + a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; + a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; + a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; + + out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03; + out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13; + out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23; + + out[12] = a00 * x + a10 * y + a20 * z + a[12]; + out[13] = a01 * x + a11 * y + a21 * z + a[13]; + out[14] = a02 * x + a12 * y + a22 * z + a[14]; + out[15] = a03 * x + a13 * y + a23 * z + a[15]; + } + + return out; +}; + +/** + * Scales the mat4 by the dimensions in the given vec3 + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to scale + * @param {vec3} v the vec3 to scale the matrix by + * @returns {mat4} out + **/ +mat4.scale = function(out, a, v) { + var x = v[0], y = v[1], z = v[2]; + + out[0] = a[0] * x; + out[1] = a[1] * x; + out[2] = a[2] * x; + out[3] = a[3] * x; + out[4] = a[4] * y; + out[5] = a[5] * y; + out[6] = a[6] * y; + out[7] = a[7] * y; + out[8] = a[8] * z; + out[9] = a[9] * z; + out[10] = a[10] * z; + out[11] = a[11] * z; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; +}; + +/** + * Rotates a mat4 by the given angle + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @param {vec3} axis the axis to rotate around + * @returns {mat4} out + */ +mat4.rotate = function (out, a, rad, axis) { + var x = axis[0], y = axis[1], z = axis[2], + len = Math.sqrt(x * x + y * y + z * z), + s, c, t, + a00, a01, a02, a03, + a10, a11, a12, a13, + a20, a21, a22, a23, + b00, b01, b02, + b10, b11, b12, + b20, b21, b22; + + if (Math.abs(len) < GLMAT_EPSILON) { return null; } + + len = 1 / len; + x *= len; + y *= len; + z *= len; + + s = Math.sin(rad); + c = Math.cos(rad); + t = 1 - c; + + a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; + a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; + a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; + + // Construct the elements of the rotation matrix + b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s; + b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s; + b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c; + + // Perform rotation-specific matrix multiplication + out[0] = a00 * b00 + a10 * b01 + a20 * b02; + out[1] = a01 * b00 + a11 * b01 + a21 * b02; + out[2] = a02 * b00 + a12 * b01 + a22 * b02; + out[3] = a03 * b00 + a13 * b01 + a23 * b02; + out[4] = a00 * b10 + a10 * b11 + a20 * b12; + out[5] = a01 * b10 + a11 * b11 + a21 * b12; + out[6] = a02 * b10 + a12 * b11 + a22 * b12; + out[7] = a03 * b10 + a13 * b11 + a23 * b12; + out[8] = a00 * b20 + a10 * b21 + a20 * b22; + out[9] = a01 * b20 + a11 * b21 + a21 * b22; + out[10] = a02 * b20 + a12 * b21 + a22 * b22; + out[11] = a03 * b20 + a13 * b21 + a23 * b22; + + if (a !== out) { // If the source and destination differ, copy the unchanged last row + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } + return out; +}; + +/** + * Rotates a matrix by the given angle around the X axis + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +mat4.rotateX = function (out, a, rad) { + var s = Math.sin(rad), + c = Math.cos(rad), + a10 = a[4], + a11 = a[5], + a12 = a[6], + a13 = a[7], + a20 = a[8], + a21 = a[9], + a22 = a[10], + a23 = a[11]; + + if (a !== out) { // If the source and destination differ, copy the unchanged rows + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } + + // Perform axis-specific matrix multiplication + out[4] = a10 * c + a20 * s; + out[5] = a11 * c + a21 * s; + out[6] = a12 * c + a22 * s; + out[7] = a13 * c + a23 * s; + out[8] = a20 * c - a10 * s; + out[9] = a21 * c - a11 * s; + out[10] = a22 * c - a12 * s; + out[11] = a23 * c - a13 * s; + return out; +}; + +/** + * Rotates a matrix by the given angle around the Y axis + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +mat4.rotateY = function (out, a, rad) { + var s = Math.sin(rad), + c = Math.cos(rad), + a00 = a[0], + a01 = a[1], + a02 = a[2], + a03 = a[3], + a20 = a[8], + a21 = a[9], + a22 = a[10], + a23 = a[11]; + + if (a !== out) { // If the source and destination differ, copy the unchanged rows + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } + + // Perform axis-specific matrix multiplication + out[0] = a00 * c - a20 * s; + out[1] = a01 * c - a21 * s; + out[2] = a02 * c - a22 * s; + out[3] = a03 * c - a23 * s; + out[8] = a00 * s + a20 * c; + out[9] = a01 * s + a21 * c; + out[10] = a02 * s + a22 * c; + out[11] = a03 * s + a23 * c; + return out; +}; + +/** + * Rotates a matrix by the given angle around the Z axis + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +mat4.rotateZ = function (out, a, rad) { + var s = Math.sin(rad), + c = Math.cos(rad), + a00 = a[0], + a01 = a[1], + a02 = a[2], + a03 = a[3], + a10 = a[4], + a11 = a[5], + a12 = a[6], + a13 = a[7]; + + if (a !== out) { // If the source and destination differ, copy the unchanged last row + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } + + // Perform axis-specific matrix multiplication + out[0] = a00 * c + a10 * s; + out[1] = a01 * c + a11 * s; + out[2] = a02 * c + a12 * s; + out[3] = a03 * c + a13 * s; + out[4] = a10 * c - a00 * s; + out[5] = a11 * c - a01 * s; + out[6] = a12 * c - a02 * s; + out[7] = a13 * c - a03 * s; + return out; +}; + +/** + * Creates a matrix from a quaternion rotation and vector translation + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.translate(dest, vec); + * var quatMat = mat4.create(); + * quat4.toMat4(quat, quatMat); + * mat4.multiply(dest, quatMat); + * + * @param {mat4} out mat4 receiving operation result + * @param {quat4} q Rotation quaternion + * @param {vec3} v Translation vector + * @returns {mat4} out + */ +mat4.fromRotationTranslation = function (out, q, v) { + // Quaternion math + var x = q[0], y = q[1], z = q[2], w = q[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, + + xx = x * x2, + xy = x * y2, + xz = x * z2, + yy = y * y2, + yz = y * z2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; + + out[0] = 1 - (yy + zz); + out[1] = xy + wz; + out[2] = xz - wy; + out[3] = 0; + out[4] = xy - wz; + out[5] = 1 - (xx + zz); + out[6] = yz + wx; + out[7] = 0; + out[8] = xz + wy; + out[9] = yz - wx; + out[10] = 1 - (xx + yy); + out[11] = 0; + out[12] = v[0]; + out[13] = v[1]; + out[14] = v[2]; + out[15] = 1; + + return out; +}; + +mat4.fromQuat = function (out, q) { + var x = q[0], y = q[1], z = q[2], w = q[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, + + xx = x * x2, + yx = y * x2, + yy = y * y2, + zx = z * x2, + zy = z * y2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; + + out[0] = 1 - yy - zz; + out[1] = yx + wz; + out[2] = zx - wy; + out[3] = 0; + + out[4] = yx - wz; + out[5] = 1 - xx - zz; + out[6] = zy + wx; + out[7] = 0; + + out[8] = zx + wy; + out[9] = zy - wx; + out[10] = 1 - xx - yy; + out[11] = 0; + + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + + return out; +}; + +/** + * Generates a frustum matrix with the given bounds + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {Number} left Left bound of the frustum + * @param {Number} right Right bound of the frustum + * @param {Number} bottom Bottom bound of the frustum + * @param {Number} top Top bound of the frustum + * @param {Number} near Near bound of the frustum + * @param {Number} far Far bound of the frustum + * @returns {mat4} out + */ +mat4.frustum = function (out, left, right, bottom, top, near, far) { + var rl = 1 / (right - left), + tb = 1 / (top - bottom), + nf = 1 / (near - far); + out[0] = (near * 2) * rl; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = (near * 2) * tb; + out[6] = 0; + out[7] = 0; + out[8] = (right + left) * rl; + out[9] = (top + bottom) * tb; + out[10] = (far + near) * nf; + out[11] = -1; + out[12] = 0; + out[13] = 0; + out[14] = (far * near * 2) * nf; + out[15] = 0; + return out; +}; + +/** + * Generates a perspective projection matrix with the given bounds + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {number} fovy Vertical field of view in radians + * @param {number} aspect Aspect ratio. typically viewport width/height + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @returns {mat4} out + */ +mat4.perspective = function (out, fovy, aspect, near, far) { + var f = 1.0 / Math.tan(fovy / 2), + nf = 1 / (near - far); + out[0] = f / aspect; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = f; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = (far + near) * nf; + out[11] = -1; + out[12] = 0; + out[13] = 0; + out[14] = (2 * far * near) * nf; + out[15] = 0; + return out; +}; + +/** + * Generates a orthogonal projection matrix with the given bounds + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {number} left Left bound of the frustum + * @param {number} right Right bound of the frustum + * @param {number} bottom Bottom bound of the frustum + * @param {number} top Top bound of the frustum + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @returns {mat4} out + */ +mat4.ortho = function (out, left, right, bottom, top, near, far) { + var lr = 1 / (left - right), + bt = 1 / (bottom - top), + nf = 1 / (near - far); + out[0] = -2 * lr; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = -2 * bt; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 2 * nf; + out[11] = 0; + out[12] = (left + right) * lr; + out[13] = (top + bottom) * bt; + out[14] = (far + near) * nf; + out[15] = 1; + return out; +}; + +/** + * Generates a look-at matrix with the given eye position, focal point, and up axis + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {vec3} eye Position of the viewer + * @param {vec3} center Point the viewer is looking at + * @param {vec3} up vec3 pointing up + * @returns {mat4} out + */ +mat4.lookAt = function (out, eye, center, up) { + var x0, x1, x2, y0, y1, y2, z0, z1, z2, len, + eyex = eye[0], + eyey = eye[1], + eyez = eye[2], + upx = up[0], + upy = up[1], + upz = up[2], + centerx = center[0], + centery = center[1], + centerz = center[2]; + + if (Math.abs(eyex - centerx) < GLMAT_EPSILON && + Math.abs(eyey - centery) < GLMAT_EPSILON && + Math.abs(eyez - centerz) < GLMAT_EPSILON) { + return mat4.identity(out); + } + + z0 = eyex - centerx; + z1 = eyey - centery; + z2 = eyez - centerz; + + len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2); + z0 *= len; + z1 *= len; + z2 *= len; + + x0 = upy * z2 - upz * z1; + x1 = upz * z0 - upx * z2; + x2 = upx * z1 - upy * z0; + len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2); + if (!len) { + x0 = 0; + x1 = 0; + x2 = 0; + } else { + len = 1 / len; + x0 *= len; + x1 *= len; + x2 *= len; + } + + y0 = z1 * x2 - z2 * x1; + y1 = z2 * x0 - z0 * x2; + y2 = z0 * x1 - z1 * x0; + + len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2); + if (!len) { + y0 = 0; + y1 = 0; + y2 = 0; + } else { + len = 1 / len; + y0 *= len; + y1 *= len; + y2 *= len; + } + + out[0] = x0; + out[1] = y0; + out[2] = z0; + out[3] = 0; + out[4] = x1; + out[5] = y1; + out[6] = z1; + out[7] = 0; + out[8] = x2; + out[9] = y2; + out[10] = z2; + out[11] = 0; + out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); + out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); + out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); + out[15] = 1; + + return out; +}; + +/** + * Returns a string representation of a mat4 + * + * @param {mat4} mat matrix to represent as a string + * @returns {String} string representation of the matrix + */ +mat4.str = function (a) { + return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + + a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' + + a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')'; +}; + +/** + * Returns Frobenius norm of a mat4 + * + * @param {mat4} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ +mat4.frob = function (a) { + return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2) + Math.pow(a[9], 2) + Math.pow(a[10], 2) + Math.pow(a[11], 2) + Math.pow(a[12], 2) + Math.pow(a[13], 2) + Math.pow(a[14], 2) + Math.pow(a[15], 2) )) +}; + + +if(typeof(exports) !== 'undefined') { + exports.mat4 = mat4; +} +; +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class Quaternion + * @name quat + */ + +var quat = {}; + +/** + * Creates a new identity quat + * + * @returns {quat} a new quaternion + */ +quat.create = function() { + var out = new GLMAT_ARRAY_TYPE(4); + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; +}; + +/** + * Sets a quaternion to represent the shortest rotation from one + * vector to another. + * + * Both vectors are assumed to be unit length. + * + * @param {quat} out the receiving quaternion. + * @param {vec3} a the initial vector + * @param {vec3} b the destination vector + * @returns {quat} out + */ +quat.rotationTo = (function() { + var tmpvec3 = vec3.create(); + var xUnitVec3 = vec3.fromValues(1,0,0); + var yUnitVec3 = vec3.fromValues(0,1,0); + + return function(out, a, b) { + var dot = vec3.dot(a, b); + if (dot < -0.999999) { + vec3.cross(tmpvec3, xUnitVec3, a); + if (vec3.length(tmpvec3) < 0.000001) + vec3.cross(tmpvec3, yUnitVec3, a); + vec3.normalize(tmpvec3, tmpvec3); + quat.setAxisAngle(out, tmpvec3, Math.PI); + return out; + } else if (dot > 0.999999) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; + } else { + vec3.cross(tmpvec3, a, b); + out[0] = tmpvec3[0]; + out[1] = tmpvec3[1]; + out[2] = tmpvec3[2]; + out[3] = 1 + dot; + return quat.normalize(out, out); + } + }; +})(); + +/** + * Sets the specified quaternion with values corresponding to the given + * axes. Each axis is a vec3 and is expected to be unit length and + * perpendicular to all other specified axes. + * + * @param {vec3} view the vector representing the viewing direction + * @param {vec3} right the vector representing the local "right" direction + * @param {vec3} up the vector representing the local "up" direction + * @returns {quat} out + */ +quat.setAxes = (function() { + var matr = mat3.create(); + + return function(out, view, right, up) { + matr[0] = right[0]; + matr[3] = right[1]; + matr[6] = right[2]; + + matr[1] = up[0]; + matr[4] = up[1]; + matr[7] = up[2]; + + matr[2] = -view[0]; + matr[5] = -view[1]; + matr[8] = -view[2]; + + return quat.normalize(out, quat.fromMat3(out, matr)); + }; +})(); + +/** + * Creates a new quat initialized with values from an existing quaternion + * + * @param {quat} a quaternion to clone + * @returns {quat} a new quaternion + * @function + */ +quat.clone = vec4.clone; + +/** + * Creates a new quat initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {quat} a new quaternion + * @function + */ +quat.fromValues = vec4.fromValues; + +/** + * Copy the values from one quat to another + * + * @param {quat} out the receiving quaternion + * @param {quat} a the source quaternion + * @returns {quat} out + * @function + */ +quat.copy = vec4.copy; + +/** + * Set the components of a quat to the given values + * + * @param {quat} out the receiving quaternion + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {quat} out + * @function + */ +quat.set = vec4.set; + +/** + * Set a quat to the identity quaternion + * + * @param {quat} out the receiving quaternion + * @returns {quat} out + */ +quat.identity = function(out) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; +}; + +/** + * Sets a quat from the given angle and rotation axis, + * then returns it. + * + * @param {quat} out the receiving quaternion + * @param {vec3} axis the axis around which to rotate + * @param {Number} rad the angle in radians + * @returns {quat} out + **/ +quat.setAxisAngle = function(out, axis, rad) { + rad = rad * 0.5; + var s = Math.sin(rad); + out[0] = s * axis[0]; + out[1] = s * axis[1]; + out[2] = s * axis[2]; + out[3] = Math.cos(rad); + return out; +}; + +/** + * Adds two quat's + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @returns {quat} out + * @function + */ +quat.add = vec4.add; + +/** + * Multiplies two quat's + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @returns {quat} out + */ +quat.multiply = function(out, a, b) { + var ax = a[0], ay = a[1], az = a[2], aw = a[3], + bx = b[0], by = b[1], bz = b[2], bw = b[3]; + + out[0] = ax * bw + aw * bx + ay * bz - az * by; + out[1] = ay * bw + aw * by + az * bx - ax * bz; + out[2] = az * bw + aw * bz + ax * by - ay * bx; + out[3] = aw * bw - ax * bx - ay * by - az * bz; + return out; +}; + +/** + * Alias for {@link quat.multiply} + * @function + */ +quat.mul = quat.multiply; + +/** + * Scales a quat by a scalar number + * + * @param {quat} out the receiving vector + * @param {quat} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {quat} out + * @function + */ +quat.scale = vec4.scale; + +/** + * Rotates a quaternion by the given angle about the X axis + * + * @param {quat} out quat receiving operation result + * @param {quat} a quat to rotate + * @param {number} rad angle (in radians) to rotate + * @returns {quat} out + */ +quat.rotateX = function (out, a, rad) { + rad *= 0.5; + + var ax = a[0], ay = a[1], az = a[2], aw = a[3], + bx = Math.sin(rad), bw = Math.cos(rad); + + out[0] = ax * bw + aw * bx; + out[1] = ay * bw + az * bx; + out[2] = az * bw - ay * bx; + out[3] = aw * bw - ax * bx; + return out; +}; + +/** + * Rotates a quaternion by the given angle about the Y axis + * + * @param {quat} out quat receiving operation result + * @param {quat} a quat to rotate + * @param {number} rad angle (in radians) to rotate + * @returns {quat} out + */ +quat.rotateY = function (out, a, rad) { + rad *= 0.5; + + var ax = a[0], ay = a[1], az = a[2], aw = a[3], + by = Math.sin(rad), bw = Math.cos(rad); + + out[0] = ax * bw - az * by; + out[1] = ay * bw + aw * by; + out[2] = az * bw + ax * by; + out[3] = aw * bw - ay * by; + return out; +}; + +/** + * Rotates a quaternion by the given angle about the Z axis + * + * @param {quat} out quat receiving operation result + * @param {quat} a quat to rotate + * @param {number} rad angle (in radians) to rotate + * @returns {quat} out + */ +quat.rotateZ = function (out, a, rad) { + rad *= 0.5; + + var ax = a[0], ay = a[1], az = a[2], aw = a[3], + bz = Math.sin(rad), bw = Math.cos(rad); + + out[0] = ax * bw + ay * bz; + out[1] = ay * bw - ax * bz; + out[2] = az * bw + aw * bz; + out[3] = aw * bw - az * bz; + return out; +}; + +/** + * Calculates the W component of a quat from the X, Y, and Z components. + * Assumes that quaternion is 1 unit in length. + * Any existing W component will be ignored. + * + * @param {quat} out the receiving quaternion + * @param {quat} a quat to calculate W component of + * @returns {quat} out + */ +quat.calculateW = function (out, a) { + var x = a[0], y = a[1], z = a[2]; + + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); + return out; +}; + +/** + * Calculates the dot product of two quat's + * + * @param {quat} a the first operand + * @param {quat} b the second operand + * @returns {Number} dot product of a and b + * @function + */ +quat.dot = vec4.dot; + +/** + * Performs a linear interpolation between two quat's + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {quat} out + * @function + */ +quat.lerp = vec4.lerp; + +/** + * Performs a spherical linear interpolation between two quat + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {quat} out + */ +quat.slerp = function (out, a, b, t) { + // benchmarks: + // http://jsperf.com/quaternion-slerp-implementations + + var ax = a[0], ay = a[1], az = a[2], aw = a[3], + bx = b[0], by = b[1], bz = b[2], bw = b[3]; + + var omega, cosom, sinom, scale0, scale1; + + // calc cosine + cosom = ax * bx + ay * by + az * bz + aw * bw; + // adjust signs (if necessary) + if ( cosom < 0.0 ) { + cosom = -cosom; + bx = - bx; + by = - by; + bz = - bz; + bw = - bw; + } + // calculate coefficients + if ( (1.0 - cosom) > 0.000001 ) { + // standard case (slerp) + omega = Math.acos(cosom); + sinom = Math.sin(omega); + scale0 = Math.sin((1.0 - t) * omega) / sinom; + scale1 = Math.sin(t * omega) / sinom; + } else { + // "from" and "to" quaternions are very close + // ... so we can do a linear interpolation + scale0 = 1.0 - t; + scale1 = t; + } + // calculate final values + out[0] = scale0 * ax + scale1 * bx; + out[1] = scale0 * ay + scale1 * by; + out[2] = scale0 * az + scale1 * bz; + out[3] = scale0 * aw + scale1 * bw; + + return out; +}; + +/** + * Calculates the inverse of a quat + * + * @param {quat} out the receiving quaternion + * @param {quat} a quat to calculate inverse of + * @returns {quat} out + */ +quat.invert = function(out, a) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], + dot = a0*a0 + a1*a1 + a2*a2 + a3*a3, + invDot = dot ? 1.0/dot : 0; + + // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0 + + out[0] = -a0*invDot; + out[1] = -a1*invDot; + out[2] = -a2*invDot; + out[3] = a3*invDot; + return out; +}; + +/** + * Calculates the conjugate of a quat + * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result. + * + * @param {quat} out the receiving quaternion + * @param {quat} a quat to calculate conjugate of + * @returns {quat} out + */ +quat.conjugate = function (out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = a[3]; + return out; +}; + +/** + * Calculates the length of a quat + * + * @param {quat} a vector to calculate length of + * @returns {Number} length of a + * @function + */ +quat.length = vec4.length; + +/** + * Alias for {@link quat.length} + * @function + */ +quat.len = quat.length; + +/** + * Calculates the squared length of a quat + * + * @param {quat} a vector to calculate squared length of + * @returns {Number} squared length of a + * @function + */ +quat.squaredLength = vec4.squaredLength; + +/** + * Alias for {@link quat.squaredLength} + * @function + */ +quat.sqrLen = quat.squaredLength; + +/** + * Normalize a quat + * + * @param {quat} out the receiving quaternion + * @param {quat} a quaternion to normalize + * @returns {quat} out + * @function + */ +quat.normalize = vec4.normalize; + +/** + * Creates a quaternion from the given 3x3 rotation matrix. + * + * NOTE: The resultant quaternion is not normalized, so you should be sure + * to renormalize the quaternion yourself where necessary. + * + * @param {quat} out the receiving quaternion + * @param {mat3} m rotation matrix + * @returns {quat} out + * @function + */ +quat.fromMat3 = function(out, m) { + // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes + // article "Quaternion Calculus and Fast Animation". + var fTrace = m[0] + m[4] + m[8]; + var fRoot; + + if ( fTrace > 0.0 ) { + // |w| > 1/2, may as well choose w > 1/2 + fRoot = Math.sqrt(fTrace + 1.0); // 2w + out[3] = 0.5 * fRoot; + fRoot = 0.5/fRoot; // 1/(4w) + out[0] = (m[7]-m[5])*fRoot; + out[1] = (m[2]-m[6])*fRoot; + out[2] = (m[3]-m[1])*fRoot; + } else { + // |w| <= 1/2 + var i = 0; + if ( m[4] > m[0] ) + i = 1; + if ( m[8] > m[i*3+i] ) + i = 2; + var j = (i+1)%3; + var k = (i+2)%3; + + fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0); + out[i] = 0.5 * fRoot; + fRoot = 0.5 / fRoot; + out[3] = (m[k*3+j] - m[j*3+k]) * fRoot; + out[j] = (m[j*3+i] + m[i*3+j]) * fRoot; + out[k] = (m[k*3+i] + m[i*3+k]) * fRoot; + } + + return out; +}; + +/** + * Returns a string representation of a quatenion + * + * @param {quat} vec vector to represent as a string + * @returns {String} string representation of the vector + */ +quat.str = function (a) { + return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; +}; + +if(typeof(exports) !== 'undefined') { + exports.quat = quat; +} +; + + + + + + + + + + + + + + })(shim.exports); +})(this); + +(function(window) { + + // Namespace + ionic.Animation = ionic.Animation || {}; + + + ionic.Animation.TimingFn = { + 'linear': function(duration) { + return function(t) { + return ionic.Animation.Bezier.linear(t, duration); + } + }, + 'ease': function(duration) { + return function(t) { + return ionic.Animation.Bezier.ease(t, duration); + } + }, + 'ease-in': function(duration) { + return function(t) { + return ionic.Animation.Bezier.easeIn(t, duration); + } + }, + 'ease-out': function(duration) { + return function(t) { + return ionic.Animation.Bezier.easeOut(t, duration); + } + }, + 'ease-in-out': function(duration) { + return function(t) { + return ionic.Animation.Bezier.easeInOut(t, duration); + } + } + }; +})(window); + })(); \ No newline at end of file diff --git a/release/js/ionic.min.js b/release/js/ionic.min.js index cdc23558bcb..397d3ec8d2c 100644 --- a/release/js/ionic.min.js +++ b/release/js/ionic.min.js @@ -2,7 +2,7 @@ * Copyright 2014 Drifty Co. * http://drifty.com/ * - * Ionic, v1.0.0-beta.3 + * Ionic, v1.0.0-beta.4 * A powerful HTML5 mobile app framework. * http://ionicframework.com/ * @@ -12,6 +12,7 @@ * */ -!function(){function t(t,e,i){e!==!1?z.addEventListener(t,j[t],i):z.removeEventListener(t,j[t])}function e(t){var e=S(t.target),n=b(e);if(r(n)||U)return!1;var o=E(t);i("click",n,o.x,o.y),f(n)}function i(t,e,i,n){var r=document.createEvent("MouseEvents");r.initMouseEvent(t,!0,!0,window,1,0,0,i,n,!1,!1,!1,!1,0,null),r.isIonicTap=!0,e.dispatchEvent(r)}function n(t){return("submit"!=t.target.type||0!==t.detail)&&(ionic.scroll.isScrolling&&ionic.tap.containsOrIsTextInput(t.target)||!t.isIonicTap&&!r(t.target))?(t.stopPropagation(),ionic.tap.isLabelWithTextInput(t.target)||t.preventDefault(),!1):void 0}function r(t){if(!t||t.disabled||/file|range/i.test(t.type)||/object|video/i.test(t.tagName))return!0;if(1===t.nodeType)for(var e=t;e;){if("true"==(e.dataset?e.dataset.tapDisabled:e.getAttribute("data-tap-disabled")))return!0;e=e.parentElement}return!1}function o(e){if(!e.isIonicTap&&!_(e)){if(F)return e.stopPropagation(),ionic.tap.isTextInput(e.target)||e.preventDefault(),!1;U=!1,q=E(e),t("mousemove"),ionic.activator.start(e)}}function s(i){return F?(i.stopPropagation(),i.preventDefault(),!1):void(_(i)||(T(i)||e(i),t("mousemove",!1),ionic.activator.end(),U=!1))}function a(e){return T(e)?(t("mousemove",!1),ionic.activator.end(),U=!0,!1):void 0}function l(e){if(!_(e)&&(U=!1,d(),q=E(e),t("touchmove"),ionic.activator.start(e),ionic.Platform.isIOS()&&ionic.tap.isLabelWithTextInput(e.target))){var i=b(S(e.target));i!==H&&e.preventDefault()}}function c(t){_(t)||(d(),T(t)||e(t),h())}function u(e){return T(e)?(U=!0,t("touchmove",!1),ionic.activator.end(),!1):void 0}function h(){t("touchmove",!1),ionic.activator.end(),U=!1}function d(){F=!0,clearTimeout(W),W=setTimeout(function(){F=!1},2e3)}function _(t){return t.isTapHandled?!0:(t.isTapHandled=!0,ionic.scroll.isScrolling&&ionic.tap.containsOrIsTextInput(t.target)?(t.preventDefault(),!0):void 0)}function f(t){B=null;var e=!1;"SELECT"==t.tagName?(i("mousedown",t,0,0),t.focus&&t.focus(),e=!0):v()===t?e=!0:/input|textarea/i.test(t.tagName)?(e=!0,t.focus&&t.focus(),t.value=t.value,F&&(B=t)):p(),e&&(v(t),ionic.trigger("ionic.focusin",{target:t},!0))}function p(){var t=v();t&&/input|textarea|select/i.test(t.tagName)&&t.blur(),v(null)}function g(t){F&&ionic.tap.isTextInput(v())&&ionic.tap.isTextInput(B)&&B!==t.target&&(B.focus(),B=null),ionic.scroll.isScrolling=!1}function m(){v(null)}function v(t){return arguments.length&&(H=t),H||document.activeElement}function T(t){if(!t||!q||0===q.x&&0===q.y)return!1;var e=E(t);return Math.abs(q.x-e.x)>Z||Math.abs(q.y-e.y)>Z}function E(t){var e={x:0,y:0};if(t){var i=t.touches&&t.touches.length?t.touches:[t],n=t.changedTouches&&t.changedTouches[0]||i[0];n&&(e.x=n.clientX||n.pageX||0,e.y=n.clientY||n.pageY||0)}return e}function S(t,e){for(var i=t,n=0;6>n&&i;n++){if("LABEL"===i.tagName)return i;i=t.parentElement}return e!==!1?t:void 0}function b(t){if(t&&"LABEL"===t.tagName){if(t.control)return t.control;if(t.querySelector){var e=t.querySelector("input,textarea,select");if(e)return e}}return t}function y(){X()&&window.addEventListener("native.showkeyboard",w),document.body.addEventListener("ionic.focusin",D),document.body.addEventListener("focusin",D),document.body.addEventListener("focusout",M),document.body.addEventListener("orientationchange",I),document.removeEventListener("touchstart",y)}function w(t){ionic.keyboard.height=t.keyboardHeight}function D(t){t.target&&ionic.tap.isTextInput(t.target)&&P(t.target)&&(document.addEventListener("keydown",O,!1),document.body.scrollTop=0,document.body.querySelector(".scroll-content").scrollTop=0,K=t.target,x(t))}function x(t){clearTimeout(J),clearTimeout(Q),J=setTimeout(function(){var e=C(),i=K.getBoundingClientRect();L(t.target,i.top,i.bottom,$,e)},32)}function L(t,e,i,n,r){var o={target:t,elementTop:Math.round(e),elementBottom:Math.round(i),keyboardHeight:r};return o.contentHeight=R()?n-r:n,o.keyboardTopOffset=o.elementTop-o.contentHeight,o.isElementUnderKeyboard=o.elementBottom>o.contentHeight,ionic.keyboard.isOpen=!0,K=t,ionic.trigger("scrollChildIntoView",o,!0),ionic.requestAnimationFrame(function(){document.body.classList.add(te)}),document.addEventListener("touchmove",A,!1),o}function M(){clearTimeout(J),clearTimeout(Q),Q=setTimeout(G,350)}function G(){ionic.keyboard.isOpen=!1,ionic.trigger("resetScrollView",{target:K},!0),ionic.requestAnimationFrame(function(){document.body.classList.remove(te)}),document.removeEventListener("touchmove",A),document.removeEventListener("keydown",O)}function N(){window.innerHeight>$&&($=window.innerHeight)}function O(t){ionic.scroll.isScrolling&&A(t)}function A(t){t.preventDefault()}function I(){$=window.innerHeight,setTimeout(function(){$=window.innerHeight},999)}function C(){if(ionic.keyboard.height)return ionic.keyboard.height;if(ionic.Platform.isIOS())return ionic.Platform.isWebView()?260:216;if(ionic.Platform.isAndroid()){if(ionic.Platform.isWebView())return 220;if(ionic.Platform.version()<=4.3)return 230}return 275}function P(t){for(;t;){if(t.classList.contains(ee))return!0;t=t.parentElement}return!1}function R(){return ionic.Platform.isIOS()||ionic.Platform.isAndroid()&&!ionic.Platform.isWebView()}function X(){return!!(window.cordova&&cordova.plugins&&cordova.plugins.Keyboard)}function V(){var t;for(t=0;tc;c++){if(r=o(n)-u,Math.abs(r)n)return s(e);if(n>i)return s(i);for(;i>e;){if(r=o(n),Math.abs(r-u)r?e=n:i=n,n=.5*(i-e)+e}return s(n)}},animate:function(t){return{leave:function(){var e=function(){t.classList.remove("leave"),t.classList.remove("leave-active"),t.removeEventListener("webkitTransitionEnd",e),t.removeEventListener("transitionEnd",e)};return t.addEventListener("webkitTransitionEnd",e),t.addEventListener("transitionEnd",e),t.classList.add("leave"),t.classList.add("leave-active"),this},enter:function(){var e=function(){t.classList.remove("enter"),t.classList.remove("enter-active"),t.removeEventListener("webkitTransitionEnd",e),t.removeEventListener("transitionEnd",e)};return t.addEventListener("webkitTransitionEnd",e),t.addEventListener("transitionEnd",e),t.classList.add("enter"),t.classList.add("enter-active"),this}}}}}(ionic),function(t,e,i){function n(){o=!0;for(var t=0;tr;r++)if(i=n[r],i.nodeName&&i.nodeName.toLowerCase()==e){if(i==t)return o;o++}return Array.prototype.slice.call(t.parentNode.children).indexOf(t)},swapNodes:function(t,e){e.parentNode.insertBefore(t,e)},centerElementByMargin:function(t){t.style.marginLeft=-t.offsetWidth/2+"px",t.style.marginTop=-t.offsetHeight/2+"px"},centerElementByMarginTwice:function(t){i.requestAnimationFrame(function(){i.DomUtil.centerElementByMargin(t),i.requestAnimationFrame(function(){i.DomUtil.centerElementByMargin(t)})})},getParentWithClass:function(t,e,i){for(i=i||10;t.parentNode&&i--;){if(t.parentNode.classList&&t.parentNode.classList.contains(e))return t.parentNode;t=t.parentNode}return null},getParentOrSelfWithClass:function(t,e,i){for(i=i||10;t&&i--;){if(t.classList&&t.classList.contains(e))return t;t=t.parentNode}return null},rectContains:function(t,e,i,n,r,o){return i>t||t>r?!1:n>e||e>o?!1:!0}},i.requestAnimationFrame=i.DomUtil.requestAnimationFrame,i.animationFrameThrottle=i.DomUtil.animationFrameThrottle}(window,document,ionic),function(t){window.CustomEvent||!function(){var t;t=function(t,e){var i;e=e||{bubbles:!1,cancelable:!1,detail:void 0};try{i=document.createEvent("CustomEvent"),i.initCustomEvent(t,e.bubbles,e.cancelable,e.detail)}catch(n){i=document.createEvent("Event");for(var r in e)i[r]=e[r];i.initEvent(t,e.bubbles,e.cancelable)}return i},t.prototype=window.Event.prototype,window.CustomEvent=t}(),t.EventController={VIRTUALIZED_EVENTS:["tap","swipe","swiperight","swipeleft","drag","hold","release"],trigger:function(t,e,i,n){var r=new CustomEvent(t,{detail:e,bubbles:!!i,cancelable:!!n});e&&e.target&&e.target.dispatchEvent&&e.target.dispatchEvent(r)||window.dispatchEvent(r)},on:function(e,i,n){for(var r=n||window,o=0,s=this.VIRTUALIZED_EVENTS.length;s>o;o++)if(e==this.VIRTUALIZED_EVENTS[o]){var a=new t.Gesture(n);return a.on(e,i),a}r.addEventListener(e,i)},off:function(t,e,i){i.removeEventListener(t,e)},onGesture:function(e,i,n){var r=new t.Gesture(n);return r.on(e,i),r},offGesture:function(t,e,i){t.off(e,i)},handlePopState:function(){}},t.on=function(){t.EventController.on.apply(t.EventController,arguments)},t.off=function(){t.EventController.off.apply(t.EventController,arguments)},t.trigger=t.EventController.trigger,t.onGesture=function(){return t.EventController.onGesture.apply(t.EventController.onGesture,arguments)},t.offGesture=function(){return t.EventController.offGesture.apply(t.EventController.offGesture,arguments)}}(window.ionic),function(t){function e(){if(!t.Gestures.READY){t.Gestures.event.determineEventTypes();for(var e in t.Gestures.gestures)t.Gestures.gestures.hasOwnProperty(e)&&t.Gestures.detection.register(t.Gestures.gestures[e]);t.Gestures.event.onTouch(t.Gestures.DOCUMENT,t.Gestures.EVENT_MOVE,t.Gestures.detection.detect),t.Gestures.event.onTouch(t.Gestures.DOCUMENT,t.Gestures.EVENT_END,t.Gestures.detection.detect),t.Gestures.READY=!0}}t.Gesture=function(e,i){return new t.Gestures.Instance(e,i||{})},t.Gestures={},t.Gestures.defaults={stop_browser_behavior:"disable-user-behavior"},t.Gestures.HAS_POINTEREVENTS=window.navigator.pointerEnabled||window.navigator.msPointerEnabled,t.Gestures.HAS_TOUCHEVENTS="ontouchstart"in window,t.Gestures.MOBILE_REGEX=/mobile|tablet|ip(ad|hone|od)|android|silk/i,t.Gestures.NO_MOUSEEVENTS=t.Gestures.HAS_TOUCHEVENTS&&window.navigator.userAgent.match(t.Gestures.MOBILE_REGEX),t.Gestures.EVENT_TYPES={},t.Gestures.DIRECTION_DOWN="down",t.Gestures.DIRECTION_LEFT="left",t.Gestures.DIRECTION_UP="up",t.Gestures.DIRECTION_RIGHT="right",t.Gestures.POINTER_MOUSE="mouse",t.Gestures.POINTER_TOUCH="touch",t.Gestures.POINTER_PEN="pen",t.Gestures.EVENT_START="start",t.Gestures.EVENT_MOVE="move",t.Gestures.EVENT_END="end",t.Gestures.DOCUMENT=window.document,t.Gestures.plugins={},t.Gestures.READY=!1,t.Gestures.Instance=function(i,n){var r=this;if(null!==i)return e(),this.element=i,this.enabled=!0,this.options=t.Gestures.utils.extend(t.Gestures.utils.extend({},t.Gestures.defaults),n||{}),this.options.stop_browser_behavior&&t.Gestures.utils.stopDefaultBrowserBehavior(this.element,this.options.stop_browser_behavior),t.Gestures.event.onTouch(i,t.Gestures.EVENT_START,function(e){r.enabled&&t.Gestures.detection.startDetect(r,e)}),this},t.Gestures.Instance.prototype={on:function(t,e){for(var i=t.split(" "),n=0;n0&&o==t.Gestures.EVENT_END?o=t.Gestures.EVENT_MOVE:u||(o=t.Gestures.EVENT_END),(u||null===i)&&(i=l),s.call(t.Gestures.detection,a.collectEventData(e,o,a.getTouchList(i,o),l)),t.Gestures.HAS_POINTEREVENTS&&o==t.Gestures.EVENT_END&&(u=t.Gestures.PointerEvent.updatePointer(o,l))),u||(i=null,n=!1,r=!1,t.Gestures.PointerEvent.reset())}})},determineEventTypes:function(){var e;e=t.Gestures.HAS_POINTEREVENTS?t.Gestures.PointerEvent.getEvents():t.Gestures.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],t.Gestures.EVENT_TYPES[t.Gestures.EVENT_START]=e[0],t.Gestures.EVENT_TYPES[t.Gestures.EVENT_MOVE]=e[1],t.Gestures.EVENT_TYPES[t.Gestures.EVENT_END]=e[2]},getTouchList:function(e){return t.Gestures.HAS_POINTEREVENTS?t.Gestures.PointerEvent.getTouchList():e.touches?e.touches:(e.indentifier=1,[e])},collectEventData:function(e,i,n,r){var o=t.Gestures.POINTER_TOUCH;return(r.type.match(/mouse/)||t.Gestures.PointerEvent.matchType(t.Gestures.POINTER_MOUSE,r))&&(o=t.Gestures.POINTER_MOUSE),{center:t.Gestures.utils.getCenter(n),timeStamp:(new Date).getTime(),target:r.target,touches:n,eventType:i,pointerType:o,srcEvent:r,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return t.Gestures.detection.stopDetect()}}}},t.Gestures.PointerEvent={pointers:{},getTouchList:function(){var t=this,e=[];return Object.keys(t.pointers).sort().forEach(function(i){e.push(t.pointers[i])}),e},updatePointer:function(e,i){return e==t.Gestures.EVENT_END?this.pointers={}:(i.identifier=i.pointerId,this.pointers[i.pointerId]=i),Object.keys(this.pointers).length},matchType:function(e,i){if(!i.pointerType)return!1;var n={};return n[t.Gestures.POINTER_MOUSE]=i.pointerType==i.MSPOINTER_TYPE_MOUSE||i.pointerType==t.Gestures.POINTER_MOUSE,n[t.Gestures.POINTER_TOUCH]=i.pointerType==i.MSPOINTER_TYPE_TOUCH||i.pointerType==t.Gestures.POINTER_TOUCH,n[t.Gestures.POINTER_PEN]=i.pointerType==i.MSPOINTER_TYPE_PEN||i.pointerType==t.Gestures.POINTER_PEN,n[e]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},t.Gestures.utils={extend:function(t,e,i){for(var n in e)void 0!==t[n]&&i||(t[n]=e[n]);return t},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){for(var e=[],i=[],n=0,r=t.length;r>n;n++)e.push(t[n].pageX),i.push(t[n].pageY);return{pageX:(Math.min.apply(Math,e)+Math.max.apply(Math,e))/2,pageY:(Math.min.apply(Math,i)+Math.max.apply(Math,i))/2}},getVelocity:function(t,e,i){return{x:Math.abs(e/t)||0,y:Math.abs(i/t)||0}},getAngle:function(t,e){var i=e.pageY-t.pageY,n=e.pageX-t.pageX;return 180*Math.atan2(i,n)/Math.PI},getDirection:function(e,i){var n=Math.abs(e.pageX-i.pageX),r=Math.abs(e.pageY-i.pageY);return n>=r?e.pageX-i.pageX>0?t.Gestures.DIRECTION_LEFT:t.Gestures.DIRECTION_RIGHT:e.pageY-i.pageY>0?t.Gestures.DIRECTION_UP:t.Gestures.DIRECTION_DOWN},getDistance:function(t,e){var i=e.pageX-t.pageX,n=e.pageY-t.pageY;return Math.sqrt(i*i+n*n)},getScale:function(t,e){return t.length>=2&&e.length>=2?this.getDistance(e[0],e[1])/this.getDistance(t[0],t[1]):1},getRotation:function(t,e){return t.length>=2&&e.length>=2?this.getAngle(e[1],e[0])-this.getAngle(t[1],t[0]):0},isVertical:function(e){return e==t.Gestures.DIRECTION_UP||e==t.Gestures.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){t&&t.classList&&(t.classList.add(e),t.onselectstart=function(){return!1})}},t.Gestures.detection={gestures:[],current:null,previous:null,stopped:!1,startDetect:function(e,i){this.current||(this.stopped=!1,this.current={inst:e,startEvent:t.Gestures.utils.extend({},i),lastEvent:!1,name:""},this.detect(i))},detect:function(e){if(this.current&&!this.stopped){e=this.extendEventData(e);for(var i=this.current.inst.options,n=0,r=this.gestures.length;r>n;n++){var o=this.gestures[n];if(!this.stopped&&i[o.name]!==!1&&o.handler.call(o,e,this.current.inst)===!1){this.stopDetect();break}}return this.current&&(this.current.lastEvent=e),e.eventType==t.Gestures.EVENT_END&&!e.touches.length-1&&this.stopDetect(),e}},stopDetect:function(){this.previous=t.Gestures.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(e){var i=this.current.startEvent;if(i&&(e.touches.length!=i.touches.length||e.touches===i.touches)){i.touches=[];for(var n=0,r=e.touches.length;r>n;n++)i.touches.push(t.Gestures.utils.extend({},e.touches[n]))}var o=e.timeStamp-i.timeStamp,s=e.center.pageX-i.center.pageX,a=e.center.pageY-i.center.pageY,l=t.Gestures.utils.getVelocity(o,s,a);return t.Gestures.utils.extend(e,{deltaTime:o,deltaX:s,deltaY:a,velocityX:l.x,velocityY:l.y,distance:t.Gestures.utils.getDistance(i.center,e.center),angle:t.Gestures.utils.getAngle(i.center,e.center),direction:t.Gestures.utils.getDirection(i.center,e.center),scale:t.Gestures.utils.getScale(i.touches,e.touches),rotation:t.Gestures.utils.getRotation(i.touches,e.touches),startEvent:i}),e},register:function(e){var i=e.defaults||{};return void 0===i[e.name]&&(i[e.name]=!0),t.Gestures.utils.extend(t.Gestures.defaults,i,!0),e.index=e.index||1e3,this.gestures.push(e),this.gestures.sort(function(t,e){return t.indexe.index?1:0}),this.gestures}},t.Gestures.gestures=t.Gestures.gestures||{},t.Gestures.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(e,i){switch(e.eventType){case t.Gestures.EVENT_START:clearTimeout(this.timer),t.Gestures.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==t.Gestures.detection.current.name&&i.trigger("hold",e)},i.options.hold_timeout);break;case t.Gestures.EVENT_MOVE:e.distance>i.options.hold_threshold&&clearTimeout(this.timer);break;case t.Gestures.EVENT_END:clearTimeout(this.timer)}}},t.Gestures.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(e,i){if(e.eventType==t.Gestures.EVENT_END&&"touchcancel"!=e.srcEvent.type){var n=t.Gestures.detection.previous,r=!1;if(e.deltaTime>i.options.tap_max_touchtime||e.distance>i.options.tap_max_distance)return;n&&"tap"==n.name&&e.timeStamp-n.lastEvent.timeStamp0&&e.touches.length>i.options.swipe_max_touches)return;(e.velocityX>i.options.swipe_velocity||e.velocityY>i.options.swipe_velocity)&&(i.trigger(this.name,e),i.trigger(this.name+e.direction,e))}}},t.Gestures.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,correct_for_drag_min_distance:!0,drag_max_touches:1,drag_block_horizontal:!0,drag_block_vertical:!0,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(e,i){if(t.Gestures.detection.current.name!=this.name&&this.triggered)return i.trigger(this.name+"end",e),void(this.triggered=!1);if(!(i.options.drag_max_touches>0&&e.touches.length>i.options.drag_max_touches))switch(e.eventType){case t.Gestures.EVENT_START:this.triggered=!1;break;case t.Gestures.EVENT_MOVE:if(e.distancei.options.transform_min_rotation&&i.trigger("rotate",e),n>i.options.transform_min_scale&&(i.trigger("pinch",e),i.trigger("pinch"+(e.scale<1?"in":"out"),e));break;case t.Gestures.EVENT_END:this.triggered&&i.trigger(this.name+"end",e),this.triggered=!1}}},t.Gestures.gestures.Touch={name:"touch",index:-1/0,defaults:{prevent_default:!1,prevent_mouseevents:!1},handler:function(e,i){return i.options.prevent_mouseevents&&e.pointerType==t.Gestures.POINTER_MOUSE?void e.stopDetect():(i.options.prevent_default&&e.preventDefault(),void(e.eventType==t.Gestures.EVENT_START&&i.trigger(this.name,e)))}},t.Gestures.gestures.Release={name:"release",index:1/0,handler:function(e,i){e.eventType==t.Gestures.EVENT_END&&i.trigger(this.name,e)}}}(window.ionic),function(t,e,i){function n(){i.Platform.isWebView()?e.addEventListener("deviceready",r,!1):r(),t.removeEventListener("load",n,!1)}function r(){i.Platform.isReady=!0,i.Platform.detect();for(var t=0;t0?i=i.replace(".","_"):i+="_0",this.platforms.push(t+i.split("_")[0]),this.platforms.push(t+i),this.isAndroid()&&4.4>e&&(this.grade=4>e?"c":"b")}}},isWebView:function(){return!(!t.cordova&&!t.PhoneGap&&!t.phonegap)},isIPad:function(){return this.ua.toLowerCase().indexOf("ipad")>=0},isIOS:function(){return this.is("ios")},isAndroid:function(){return this.is("android")},platform:function(){return null===o&&this.setPlatform(this.device().platform),o},setPlatform:function(t){o="undefined"!=typeof t&&null!==t&&t.length?t.toLowerCase():this.ua.indexOf("Android")>0?"android":this.ua.indexOf("iPhone")>-1||this.ua.indexOf("iPad")>-1||this.ua.indexOf("iPod")>-1?"ios":""},version:function(){return null===s&&this.setVersion(this.device().version),s},setVersion:function(t){if("undefined"!=typeof t&&null!==t&&(t=t.split("."),t=parseFloat(t[0]+"."+(t.length>1?t[1]:0)),!isNaN(t)))return void(s=t);s=0;var e=this.platform(),i={android:/Android (\d+).(\d+)?/,ios:/OS (\d+)_(\d+)?/};i[e]&&(t=this.ua.match(i[e]),t.length>2&&(s=parseFloat(t[1]+"."+t[2])))},is:function(t){if(t=t.toLowerCase(),this.platforms)for(var e=0;e=0},exitApp:function(){this.ready(function(){navigator.app&&navigator.app.exitApp&&navigator.app.exitApp()})},showStatusBar:function(n){this._showStatusBar=n,this.ready(function(){i.requestAnimationFrame(function(){i.Platform._showStatusBar?(t.StatusBar&&t.StatusBar.show(),e.body.classList.remove("status-bar-hide")):(t.StatusBar&&t.StatusBar.hide(),e.body.classList.add("status-bar-hide"))})})},fullScreen:function(t,n){this.isFullScreen=t!==!1,i.DomUtil.ready(function(){i.requestAnimationFrame(function(){i.Platform.isFullScreen?e.body.classList.add("fullscreen"):e.body.classList.remove("fullscreen")}),i.Platform.showStatusBar(n===!0)})}};var o=null,s=null,a=[];t.addEventListener("load",n,!1)}(this,document,ionic),function(t,e){"use strict";e.CSS={},function(){var i,n=["webkitTransform","transform","-webkit-transform","webkit-transform","-moz-transform","moz-transform","MozTransform","mozTransform"];for(i=0;ic&&(a&&1===a.nodeType);c++){if(o&&a.classList.contains("item")){o=a;break}if(("A"==a.tagName||"BUTTON"==a.tagName||a.hasAttribute("ng-click"))&&(o=a),a.classList.contains("button")){o=a;break}a=a.parentElement}o&&(s[l]=o,"touchstart"===t.type?i._activateTimeout=setTimeout(n,80):e.requestAnimationFrame(n),l=l>19?0:l+1)}})},end:function(){clearTimeout(this._activateTimeout),setTimeout(i,200)}}}(document,ionic),function(t){var e=["0","0","0"];t.Utils={arrayMove:function(t,e,i){if(i>=t.length)for(var n=i-t.length;n--+1;)t.push(void 0);return t.splice(i,0,t.splice(e,1)[0]),t},proxy:function(t,e){var i=Array.prototype.slice.call(arguments,2);return function(){return t.apply(e,i.concat(Array.prototype.slice.call(arguments)))}},debounce:function(t,e,i){var n,r,o,s,a;return function(){o=this,r=arguments,s=new Date;var l=function(){var c=new Date-s;e>c?n=setTimeout(l,e-c):(n=null,i||(a=t.apply(o,r)))},c=i&&!n;return n||(n=setTimeout(l,e)),c&&(a=t.apply(o,r)),a}},throttle:function(t,e,i){var n,r,o,s=null,a=0;i||(i={});var l=function(){a=i.leading===!1?0:Date.now(),s=null,o=t.apply(n,r)};return function(){var c=Date.now();a||i.leading!==!1||(a=c);var u=e-(c-a);return n=this,r=arguments,0>=u?(clearTimeout(s),s=null,a=c,o=t.apply(n,r)):s||i.trailing===!1||(s=setTimeout(l,u)),o}},inherit:function(e,i){var n,r=this;n=e&&e.hasOwnProperty("constructor")?e.constructor:function(){return r.apply(this,arguments) -},t.extend(n,r,i);var o=function(){this.constructor=n};return o.prototype=r.prototype,n.prototype=new o,e&&t.extend(n.prototype,e),n.__super__=r.prototype,n},extend:function(t){for(var e=Array.prototype.slice.call(arguments,1),i=0;i2500&&(clearInterval(a),a=null)},1e3/n)),e}}(),stop:function(t){var e=null!=r[t];return e&&(r[t]=null),e},isRunning:function(t){return null!=r[t]},start:function(t,s,a,l,c,u){var h=e(),d=h,_=0,f=0,p=o++;if(u||(u=document.body),p%20===0){var g={};for(var m in r)g[m]=!0;r=g}var v=function(o){var g=o!==!0,m=e();if(!r[p]||s&&!s(p))return r[p]=null,void(a&&a(i-f/((m-h)/n),p,!1));if(g)for(var T=Math.round((m-d)/(n/i))-1,E=0;E1&&(_=1));var S=c?c(_):_;t(S,m,g)!==!1&&1!==_||!g?g&&(d=m,re.effect.Animate.requestAnimationFrame(v,u)):(r[p]=null,a&&a(i-f/((m-h)/n),p,1===_||null==l))};return r[p]=!0,re.effect.Animate.requestAnimationFrame(v,u),p}}}(this);!function(t){var e=function(){},i=function(t){return Math.pow(t-1,3)+1},n=function(t){return(t/=.5)<1?.5*Math.pow(t,3):.5*(Math.pow(t-2,3)+2)};t.views.Scroll=t.views.View.inherit({initialize:function(i){var n=this;this.__container=i.el,this.__content=i.el.firstElementChild,setTimeout(function(){n.__container&&n.__content&&(n.__container.scrollTop=0,n.__content.scrollTop=0)}),this.options={scrollingX:!1,scrollbarX:!0,scrollingY:!0,scrollbarY:!0,startX:0,startY:0,wheelDampen:6,minScrollbarSizeX:5,minScrollbarSizeY:5,scrollbarsFade:!0,scrollbarFadeDelay:300,scrollbarResizeFadeDelay:1e3,animating:!0,animationDuration:250,bouncing:!0,locking:!0,paging:!1,snapping:!1,zooming:!1,minZoom:.5,maxZoom:3,speedMultiplier:1,scrollingComplete:e,penetrationDeceleration:.03,penetrationAcceleration:.08,scrollEventInterval:10,getContentWidth:function(){return Math.max(n.__content.scrollWidth,n.__content.offsetWidth)},getContentHeight:function(){return Math.max(n.__content.scrollHeight,n.__content.offsetHeight)}};for(var r in i)this.options[r]=i[r];this.hintResize=t.debounce(function(){n.resize()},1e3,!0),this.onScroll=function(){t.scroll.isScrolling?(clearTimeout(n.scrollTimer),n.scrollTimer=setTimeout(n.setScrollStop,80)):setTimeout(n.setScrollStart,50)},this.setScrollStart=function(){t.scroll.isScrolling=Math.abs(t.scroll.lastTop-n.__scrollTop)>1,clearTimeout(n.scrollTimer),n.scrollTimer=setTimeout(n.setScrollStop,80)},this.setScrollStop=function(){t.scroll.isScrolling=!1,t.scroll.lastTop=n.__scrollTop},this.triggerScrollEvent=t.throttle(function(){t.trigger("scroll",{scrollTop:n.__scrollTop,scrollLeft:n.__scrollLeft,target:n.__container})},this.options.scrollEventInterval),this.triggerScrollEndEvent=function(){t.trigger("scrollend",{scrollTop:n.__scrollTop,scrollLeft:n.__scrollLeft,target:n.__container})},this.__scrollLeft=this.options.startX,this.__scrollTop=this.options.startY,this.__callback=this.getRenderFn(),this.__initEventHandlers(),this.__createScrollbars()},run:function(){this.resize(),this.__fadeScrollbars("out",this.options.scrollbarResizeFadeDelay)},__isSingleTouch:!1,__isTracking:!1,__didDecelerationComplete:!1,__isGesturing:!1,__isDragging:!1,__isDecelerating:!1,__isAnimating:!1,__clientLeft:0,__clientTop:0,__clientWidth:0,__clientHeight:0,__contentWidth:0,__contentHeight:0,__snapWidth:100,__snapHeight:100,__refreshHeight:null,__refreshActive:!1,__refreshActivate:null,__refreshDeactivate:null,__refreshStart:null,__zoomLevel:1,__scrollLeft:0,__scrollTop:0,__maxScrollLeft:0,__maxScrollTop:0,__scheduledLeft:0,__scheduledTop:0,__scheduledZoom:0,__lastTouchLeft:null,__lastTouchTop:null,__lastTouchMove:null,__positions:null,__minDecelerationScrollLeft:null,__minDecelerationScrollTop:null,__maxDecelerationScrollLeft:null,__maxDecelerationScrollTop:null,__decelerationVelocityX:null,__decelerationVelocityY:null,__transformProperty:null,__perspectiveProperty:null,__indicatorX:null,__indicatorY:null,__scrollbarFadeTimeout:null,__didWaitForSize:null,__sizerTimeout:null,__initEventHandlers:function(){var e=this,i=this.__container;if(i.addEventListener("scrollChildIntoView",function(n){e.isScrolledIntoView||(i.style.height=i.clientHeight-n.detail.keyboardHeight+"px",i.style.overflow="visible",e.isScrolledIntoView=!0,e.resize()),n.detail.isElementUnderKeyboard&&(t.scroll.isScrolling=!0,setTimeout(function(){var r=.5*i.clientHeight,o=n.detail.keyboardTopOffset+r;t.tap.cloneFocusedInput(i,e),e.scrollBy(0,o,!0),e.onScroll()},t.Platform.isIOS()?80:350)),n.stopPropagation()}),i.addEventListener("resetScrollView",function(){e.isScrolledIntoView=!1,i.style.height="",i.style.overflow="",e.resize(),t.scroll.isScrolling=!1}),e.touchStart=function(i){if(e.startCoordinates=E(i),!t.tap.ignoreScrollStart(i)){if(t.tap.containsOrIsTextInput(i.target))return void(e.__hasStarted=!1);e.__isSelectable=!0,e.__enableScrollY=!0,e.__hasStarted=!0,e.doTouchStart(i.touches,i.timeStamp),i.preventDefault()}},e.touchMove=function(n){if(!n.defaultPrevented){if(!e.__hasStarted&&t.tap.containsOrIsTextInput(n.target))return e.__hasStarted=!0,e.doTouchStart(n.touches,n.timeStamp),void n.preventDefault();if(e.startCoordinates){var r=E(n);e.__isSelectable&&t.tap.isTextInput(n.target)&&Math.abs(e.startCoordinates.x-r.x)>20&&(e.__enableScrollY=!1,e.__isSelectable=!0),e.__enableScrollY&&Math.abs(e.startCoordinates.y-r.y)>10&&(e.__isSelectable=!1,t.tap.cloneFocusedInput(i,e))}e.doTouchMove(n.touches,n.timeStamp,n.scale)}},e.touchEnd=function(n){e.doTouchEnd(n.timeStamp),e.__hasStarted=!1,e.__isSelectable=!0,e.__enableScrollY=!0,e.__isDragging||e.__isDecelerating||e.__isAnimating||t.tap.removeClonedInputs(i,e)},e.options.orgScrollingComplete=e.options.scrollingComplete,e.options.scrollingComplete=function(){t.tap.removeClonedInputs(i,e),e.options.orgScrollingComplete()},"ontouchstart"in window)i.addEventListener("touchstart",e.touchStart,!1),document.addEventListener("touchmove",e.touchMove,!1),document.addEventListener("touchend",e.touchEnd,!1),document.addEventListener("touchcancel",e.touchEnd,!1);else{var n=!1;i.addEventListener("mousedown",function(i){t.tap.ignoreScrollStart(i)||"SELECT"===i.target.tagName||(e.doTouchStart([{pageX:i.pageX,pageY:i.pageY}],i.timeStamp),i.preventDefault(),n=!0)},!1),document.addEventListener("mousemove",function(t){n&&!t.defaultPrevented&&(e.doTouchMove([{pageX:t.pageX,pageY:t.pageY}],t.timeStamp),n=!0)},!1),document.addEventListener("mouseup",function(t){n&&(e.doTouchEnd(t.timeStamp),n=!1)},!1);var r=t.debounce(function(){e.__fadeScrollbars("in")},500,!0),o=t.debounce(function(){e.__fadeScrollbars("out")},100,!1);document.addEventListener("mousewheel",function(t){r(),e.scrollBy(t.wheelDeltaX/e.options.wheelDampen,-t.wheelDeltaY/e.options.wheelDampen),o()})}},__createScrollbar:function(t){var e=document.createElement("div"),i=document.createElement("div");return i.className="scroll-bar-indicator",e.className="h"==t?"scroll-bar scroll-bar-h":"scroll-bar scroll-bar-v",e.appendChild(i),e},__createScrollbars:function(){var t,e;this.options.scrollingX&&(t={el:this.__createScrollbar("h"),sizeRatio:1},t.indicator=t.el.children[0],this.options.scrollbarX&&this.__container.appendChild(t.el),this.__indicatorX=t),this.options.scrollingY&&(e={el:this.__createScrollbar("v"),sizeRatio:1},e.indicator=e.el.children[0],this.options.scrollbarY&&this.__container.appendChild(e.el),this.__indicatorY=e)},__resizeScrollbars:function(){var t=this;if(t.__indicatorX){var e=Math.max(Math.round(t.__clientWidth*t.__clientWidth/t.__contentWidth),20);e>t.__contentWidth&&(e=0),t.__indicatorX.size=e,t.__indicatorX.minScale=this.options.minScrollbarSizeX/e,t.__indicatorX.indicator.style.width=e+"px",t.__indicatorX.maxPos=t.__clientWidth-e,t.__indicatorX.sizeRatio=t.__maxScrollLeft?t.__indicatorX.maxPos/t.__maxScrollLeft:1}if(t.__indicatorY){var i=Math.max(Math.round(t.__clientHeight*t.__clientHeight/t.__contentHeight),20);i>t.__contentHeight&&(i=0),t.__indicatorY.size=i,t.__indicatorY.minScale=this.options.minScrollbarSizeY/i,t.__indicatorY.maxPos=t.__clientHeight-i,t.__indicatorY.indicator.style.height=i+"px",t.__indicatorY.sizeRatio=t.__maxScrollTop?t.__indicatorY.maxPos/t.__maxScrollTop:1}},__repositionScrollbars:function(){var t,e,i,n,r,o=this,s=0,a=0;o.__indicatorX&&(o.__indicatorY&&(s=10),n=Math.round(o.__indicatorX.sizeRatio*o.__scrollLeft)||0,e=o.__scrollLeft-(o.__maxScrollLeft-s),o.__scrollLeft<0?(widthScale=Math.max(o.__indicatorX.minScale,(o.__indicatorX.size-Math.abs(o.__scrollLeft))/o.__indicatorX.size),n=0,o.__indicatorX.indicator.style[o.__transformOriginProperty]="left center"):e>0?(widthScale=Math.max(o.__indicatorX.minScale,(o.__indicatorX.size-e)/o.__indicatorX.size),n=o.__indicatorX.maxPos-s,o.__indicatorX.indicator.style[o.__transformOriginProperty]="right center"):(n=Math.min(o.__maxScrollLeft,Math.max(0,n)),widthScale=1),o.__indicatorX.indicator.style[o.__transformProperty]="translate3d("+n+"px, 0, 0) scaleX("+widthScale+")"),o.__indicatorY&&(r=Math.round(o.__indicatorY.sizeRatio*o.__scrollTop)||0,o.__indicatorX&&(a=10),i=o.__scrollTop-(o.__maxScrollTop-a),o.__scrollTop<0?(t=Math.max(o.__indicatorY.minScale,(o.__indicatorY.size-Math.abs(o.__scrollTop))/o.__indicatorY.size),r=0,o.__indicatorY.indicator.style[o.__transformOriginProperty]="center top"):i>0?(t=Math.max(o.__indicatorY.minScale,(o.__indicatorY.size-i)/o.__indicatorY.size),r=o.__indicatorY.maxPos-a,o.__indicatorY.indicator.style[o.__transformOriginProperty]="center bottom"):(r=Math.min(o.__maxScrollTop,Math.max(0,r)),t=1),o.__indicatorY.indicator.style[o.__transformProperty]="translate3d(0,"+r+"px, 0) scaleY("+t+")")},__fadeScrollbars:function(t,e){var i=this;if(this.options.scrollbarsFade){var n="scroll-bar-fade-out";i.options.scrollbarsFade===!0&&(clearTimeout(i.__scrollbarFadeTimeout),"in"==t?(i.__indicatorX&&i.__indicatorX.indicator.classList.remove(n),i.__indicatorY&&i.__indicatorY.indicator.classList.remove(n)):i.__scrollbarFadeTimeout=setTimeout(function(){i.__indicatorX&&i.__indicatorX.indicator.classList.add(n),i.__indicatorY&&i.__indicatorY.indicator.classList.add(n)},e||i.options.scrollbarFadeDelay))}},__scrollingComplete:function(){var t=this;t.options.scrollingComplete(),t.__fadeScrollbars("out")},resize:function(){this.setDimensions(this.__container.clientWidth,this.__container.clientHeight,this.options.getContentWidth(),this.options.getContentHeight())},getRenderFn:function(){var t,e=this,i=this.__content,n=document.documentElement.style;"MozAppearance"in n?t="gecko":"WebkitAppearance"in n?t="webkit":"string"==typeof navigator.cpuClass&&(t="trident");var r,o={trident:"ms",gecko:"Moz",webkit:"Webkit",presto:"O"}[t],s=document.createElement("div"),a=o+"Perspective",l=o+"Transform",c=o+"TransformOrigin";return e.__perspectiveProperty=l,e.__transformProperty=l,e.__transformOriginProperty=c,s.style[a]!==r?function(t,n,r,o){i.style[l]="translate3d("+-t+"px,"+-n+"px,0) scale("+r+")",e.__repositionScrollbars(),o||e.triggerScrollEvent()}:s.style[l]!==r?function(t,n,r,o){i.style[l]="translate("+-t+"px,"+-n+"px) scale("+r+")",e.__repositionScrollbars(),o||e.triggerScrollEvent()}:function(t,n,r,o){i.style.marginLeft=t?-t/r+"px":"",i.style.marginTop=n?-n/r+"px":"",i.style.zoom=r||"",e.__repositionScrollbars(),o||e.triggerScrollEvent()}},setDimensions:function(t,e,i,n){var r=this;t===+t&&(r.__clientWidth=t),e===+e&&(r.__clientHeight=e),i===+i&&(r.__contentWidth=i),n===+n&&(r.__contentHeight=n),r.__computeScrollMax(),r.__resizeScrollbars(),r.scrollTo(r.__scrollLeft,r.__scrollTop,!0,null,!0)},setPosition:function(t,e){var i=this;i.__clientLeft=t||0,i.__clientTop=e||0},setSnapSize:function(t,e){var i=this;i.__snapWidth=t,i.__snapHeight=e},activatePullToRefresh:function(t,e,i,n){var r=this;r.__refreshHeight=t,r.__refreshActivate=e,r.__refreshDeactivate=i,r.__refreshStart=n},triggerPullToRefresh:function(){this.__publish(this.__scrollLeft,-this.__refreshHeight,this.__zoomLevel,!0),this.__refreshStart&&this.__refreshStart()},finishPullToRefresh:function(){var t=this;t.__refreshActive=!1,t.__refreshDeactivate&&t.__refreshDeactivate(),t.scrollTo(t.__scrollLeft,t.__scrollTop,!0)},getValues:function(){var t=this;return{left:t.__scrollLeft,top:t.__scrollTop,zoom:t.__zoomLevel}},getScrollMax:function(){var t=this;return{left:t.__maxScrollLeft,top:t.__maxScrollTop}},zoomTo:function(t,e,i,n){var r=this;if(!r.options.zooming)throw new Error("Zooming is not enabled!");r.__isDecelerating&&(re.effect.Animate.stop(r.__isDecelerating),r.__isDecelerating=!1);var o=r.__zoomLevel;null==i&&(i=r.__clientWidth/2),null==n&&(n=r.__clientHeight/2),t=Math.max(Math.min(t,r.options.maxZoom),r.options.minZoom),r.__computeScrollMax(t);var s=(i+r.__scrollLeft)*t/o-i,a=(n+r.__scrollTop)*t/o-n;s>r.__maxScrollLeft?s=r.__maxScrollLeft:0>s&&(s=0),a>r.__maxScrollTop?a=r.__maxScrollTop:0>a&&(a=0),r.__publish(s,a,t,e)},zoomBy:function(t,e,i,n){var r=this;r.zoomTo(r.__zoomLevel*t,e,i,n)},scrollTo:function(t,e,i,n,r){var o=this;if(o.__isDecelerating&&(re.effect.Animate.stop(o.__isDecelerating),o.__isDecelerating=!1),null!=n&&n!==o.__zoomLevel){if(!o.options.zooming)throw new Error("Zooming is not enabled!");t*=n,e*=n,o.__computeScrollMax(n)}else n=o.__zoomLevel;o.options.scrollingX?o.options.paging?t=Math.round(t/o.__clientWidth)*o.__clientWidth:o.options.snapping&&(t=Math.round(t/o.__snapWidth)*o.__snapWidth):t=o.__scrollLeft,o.options.scrollingY?o.options.paging?e=Math.round(e/o.__clientHeight)*o.__clientHeight:o.options.snapping&&(e=Math.round(e/o.__snapHeight)*o.__snapHeight):e=o.__scrollTop,t=Math.max(Math.min(o.__maxScrollLeft,t),0),e=Math.max(Math.min(o.__maxScrollTop,e),0),t===o.__scrollLeft&&e===o.__scrollTop&&(i=!1),o.__publish(t,e,n,i,r)},scrollBy:function(t,e,i){var n=this,r=n.__isAnimating?n.__scheduledLeft:n.__scrollLeft,o=n.__isAnimating?n.__scheduledTop:n.__scrollTop;n.scrollTo(r+(t||0),o+(e||0),i)},doMouseZoom:function(t,e,i,n){var r=this,o=t>0?.97:1.03;return r.zoomTo(r.__zoomLevel*o,!1,i-r.__clientLeft,n-r.__clientTop)},doTouchStart:function(t,e){if(this.hintResize(),null==t.length)throw new Error("Invalid touch list: "+t);if(e instanceof Date&&(e=e.valueOf()),"number"!=typeof e)throw new Error("Invalid timestamp value: "+e);var i=this;i.__interruptedAnimation=!0,i.__isDecelerating&&(re.effect.Animate.stop(i.__isDecelerating),i.__isDecelerating=!1,i.__interruptedAnimation=!0),i.__isAnimating&&(re.effect.Animate.stop(i.__isAnimating),i.__isAnimating=!1,i.__interruptedAnimation=!0);var n,r,o=1===t.length;o?(n=t[0].pageX,r=t[0].pageY):(n=Math.abs(t[0].pageX+t[1].pageX)/2,r=Math.abs(t[0].pageY+t[1].pageY)/2),i.__initialTouchLeft=n,i.__initialTouchTop=r,i.__zoomLevelStart=i.__zoomLevel,i.__lastTouchLeft=n,i.__lastTouchTop=r,i.__lastTouchMove=e,i.__lastScale=1,i.__enableScrollX=!o&&i.options.scrollingX,i.__enableScrollY=!o&&i.options.scrollingY,i.__isTracking=!0,i.__didDecelerationComplete=!1,i.__isDragging=!o,i.__isSingleTouch=o,i.__positions=[]},doTouchMove:function(t,e,i){if(null==t.length)throw new Error("Invalid touch list: "+t);if(e instanceof Date&&(e=e.valueOf()),"number"!=typeof e)throw new Error("Invalid timestamp value: "+e);var n=this;if(n.__isTracking){var r,o;2===t.length?(r=Math.abs(t[0].pageX+t[1].pageX)/2,o=Math.abs(t[0].pageY+t[1].pageY)/2):(r=t[0].pageX,o=t[0].pageY);var s=n.__positions;if(n.__isDragging){var a=r-n.__lastTouchLeft,l=o-n.__lastTouchTop,c=n.__scrollLeft,u=n.__scrollTop,h=n.__zoomLevel;if(null!=i&&n.options.zooming){var d=h;if(h=h/n.__lastScale*i,h=Math.max(Math.min(h,n.options.maxZoom),n.options.minZoom),d!==h){var _=r-n.__clientLeft,f=o-n.__clientTop;c=(_+c)*h/d-_,u=(f+u)*h/d-f,n.__computeScrollMax(h)}}if(n.__enableScrollX){c-=a*this.options.speedMultiplier;var p=n.__maxScrollLeft;(c>p||0>c)&&(n.options.bouncing?c+=a/2*this.options.speedMultiplier:c=c>p?p:0)}if(n.__enableScrollY){u-=l*this.options.speedMultiplier;var g=n.__maxScrollTop;(u>g||0>u)&&(n.options.bouncing||n.__refreshHeight&&0>u?(u+=l/2*this.options.speedMultiplier,n.__enableScrollX||null==n.__refreshHeight||(!n.__refreshActive&&u<=-n.__refreshHeight?(n.__refreshActive=!0,n.__refreshActivate&&n.__refreshActivate()):n.__refreshActive&&u>-n.__refreshHeight&&(n.__refreshActive=!1,n.__refreshDeactivate&&n.__refreshDeactivate()))):u=u>g?g:0)}s.length>60&&s.splice(0,30),s.push(c,u,e),n.__publish(c,u,h)}else{var m=n.options.locking?3:0,v=5,T=Math.abs(r-n.__initialTouchLeft),E=Math.abs(o-n.__initialTouchTop);n.__enableScrollX=n.options.scrollingX&&T>=m,n.__enableScrollY=n.options.scrollingY&&E>=m,s.push(n.__scrollLeft,n.__scrollTop,e),n.__isDragging=(n.__enableScrollX||n.__enableScrollY)&&(T>=v||E>=v),n.__isDragging&&(n.__interruptedAnimation=!1,n.__fadeScrollbars("in"))}n.__lastTouchLeft=r,n.__lastTouchTop=o,n.__lastTouchMove=e,n.__lastScale=i}},doTouchEnd:function(t){if(t instanceof Date&&(t=t.valueOf()),"number"!=typeof t)throw new Error("Invalid timestamp value: "+t);var e=this;if(e.__isTracking){if(e.__isTracking=!1,e.__isDragging)if(e.__isDragging=!1,e.__isSingleTouch&&e.options.animating&&t-e.__lastTouchMove<=100){for(var i=e.__positions,n=i.length-1,r=n,o=n;o>0&&i[o]>e.__lastTouchMove-100;o-=3)r=o;if(r!==n){var s=i[n]-i[r],a=e.__scrollLeft-i[r-2],l=e.__scrollTop-i[r-1];e.__decelerationVelocityX=a/s*(1e3/60),e.__decelerationVelocityY=l/s*(1e3/60);var c=e.options.paging||e.options.snapping?4:1;(Math.abs(e.__decelerationVelocityX)>c||Math.abs(e.__decelerationVelocityY)>c)&&(e.__refreshActive||e.__startDeceleration(t))}else e.__scrollingComplete()}else t-e.__lastTouchMove>100&&e.__scrollingComplete();e.__isDecelerating||(e.__refreshActive&&e.__refreshStart?(e.__publish(e.__scrollLeft,-e.__refreshHeight,e.__zoomLevel,!0),e.__refreshStart&&e.__refreshStart()):((e.__interruptedAnimation||e.__isDragging)&&e.__scrollingComplete(),e.scrollTo(e.__scrollLeft,e.__scrollTop,!0,e.__zoomLevel),e.__refreshActive&&(e.__refreshActive=!1,e.__refreshDeactivate&&e.__refreshDeactivate()))),e.__positions.length=0}},__publish:function(t,e,r,o,s){var a=this,l=a.__isAnimating;if(l&&(re.effect.Animate.stop(l),a.__isAnimating=!1),o&&a.options.animating){a.__scheduledLeft=t,a.__scheduledTop=e,a.__scheduledZoom=r;var c=a.__scrollLeft,u=a.__scrollTop,h=a.__zoomLevel,d=t-c,_=e-u,f=r-h,p=function(t,e,i){i&&(a.__scrollLeft=c+d*t,a.__scrollTop=u+_*t,a.__zoomLevel=h+f*t,a.__callback&&a.__callback(a.__scrollLeft,a.__scrollTop,a.__zoomLevel,s))},g=function(t){return a.__isAnimating===t},m=function(t,e,i){e===a.__isAnimating&&(a.__isAnimating=!1),(a.__didDecelerationComplete||i)&&a.__scrollingComplete(),a.options.zooming&&a.__computeScrollMax()};a.__isAnimating=re.effect.Animate.start(p,g,m,a.options.animationDuration,l?i:n)}else a.__scheduledLeft=a.__scrollLeft=t,a.__scheduledTop=a.__scrollTop=e,a.__scheduledZoom=a.__zoomLevel=r,a.__callback&&a.__callback(t,e,r,s),a.options.zooming&&a.__computeScrollMax()},__computeScrollMax:function(t){var e=this;null==t&&(t=e.__zoomLevel),e.__maxScrollLeft=Math.max(e.__contentWidth*t-e.__clientWidth,0),e.__maxScrollTop=Math.max(e.__contentHeight*t-e.__clientHeight,0),e.__didWaitForSize||0!=e.__maxScrollLeft||0!=e.__maxScrollTop||(e.__didWaitForSize=!0,e.__waitForSize())},__waitForSize:function(){var t=this;clearTimeout(t.__sizerTimeout);var e=function(){t.resize(),t.options.scrollingX&&0==t.__maxScrollLeft||t.options.scrollingY&&0==t.__maxScrollTop};e(),t.__sizerTimeout=setTimeout(e,1e3)},__startDeceleration:function(){var t=this;if(t.options.paging){var e=Math.max(Math.min(t.__scrollLeft,t.__maxScrollLeft),0),i=Math.max(Math.min(t.__scrollTop,t.__maxScrollTop),0),n=t.__clientWidth,r=t.__clientHeight;t.__minDecelerationScrollLeft=Math.floor(e/n)*n,t.__minDecelerationScrollTop=Math.floor(i/r)*r,t.__maxDecelerationScrollLeft=Math.ceil(e/n)*n,t.__maxDecelerationScrollTop=Math.ceil(i/r)*r}else t.__minDecelerationScrollLeft=0,t.__minDecelerationScrollTop=0,t.__maxDecelerationScrollLeft=t.__maxScrollLeft,t.__maxDecelerationScrollTop=t.__maxScrollTop;var o=function(e,i,n){t.__stepThroughDeceleration(n)};t.__minVelocityToKeepDecelerating=t.options.snapping?4:.1;var s=function(){var e=Math.abs(t.__decelerationVelocityX)>=t.__minVelocityToKeepDecelerating||Math.abs(t.__decelerationVelocityY)>=t.__minVelocityToKeepDecelerating;return e||(t.__didDecelerationComplete=!0),e},a=function(){t.__isDecelerating=!1,t.__didDecelerationComplete&&t.__scrollingComplete(),t.options.paging&&t.scrollTo(t.__scrollLeft,t.__scrollTop,t.options.snapping)};t.__isDecelerating=re.effect.Animate.start(o,s,a)},__stepThroughDeceleration:function(t){var e=this,i=e.__scrollLeft+e.__decelerationVelocityX,n=e.__scrollTop+e.__decelerationVelocityY;if(!e.options.bouncing){var r=Math.max(Math.min(e.__maxDecelerationScrollLeft,i),e.__minDecelerationScrollLeft);r!==i&&(i=r,e.__decelerationVelocityX=0);var o=Math.max(Math.min(e.__maxDecelerationScrollTop,n),e.__minDecelerationScrollTop);o!==n&&(n=o,e.__decelerationVelocityY=0)}if(t?e.__publish(i,n,e.__zoomLevel):(e.__scrollLeft=i,e.__scrollTop=n),!e.options.paging){var s=.95;e.__decelerationVelocityX*=s,e.__decelerationVelocityY*=s}if(e.options.bouncing){var a=0,l=0,c=e.options.penetrationDeceleration,u=e.options.penetrationAcceleration;if(ie.__maxDecelerationScrollLeft&&(a=e.__maxDecelerationScrollLeft-i),ne.__maxDecelerationScrollTop&&(l=e.__maxDecelerationScrollTop-n),0!==a){var h=a*e.__decelerationVelocityX<=e.__minDecelerationScrollLeft;h&&(e.__decelerationVelocityX+=a*c);var d=Math.abs(e.__decelerationVelocityX)<=e.__minVelocityToKeepDecelerating;(!h||d)&&(e.__decelerationVelocityX=a*u)}if(0!==l){var _=l*e.__decelerationVelocityY<=e.__minDecelerationScrollTop;_&&(e.__decelerationVelocityY+=l*c);var f=Math.abs(e.__decelerationVelocityY)<=e.__minVelocityToKeepDecelerating;(!_||f)&&(e.__decelerationVelocityY=l*u)}}}}),t.scroll={isScrolling:!1,lastTop:0}}(ionic),function(t){"use strict";t.views.ActionSheet=t.views.View.inherit({initialize:function(t){this.el=t.el},show:function(){this.el.offsetWidth,this.el.classList.add("active")},hide:function(){this.el.offsetWidth,this.el.classList.remove("active")}})}(ionic),function(t){"use strict";t.views.HeaderBar=t.views.View.inherit({initialize:function(e){this.el=e.el,t.extend(this,{alignTitle:"center"},e),this.align()},align:function(e){e||(e=this.alignTitle);var i=this.el.querySelector(".title");if(i){var n=this;t.requestAnimationFrame(function(){var r,o,s,a=n.el.childNodes,l=0,c=0,u=!1;for(r=0;r10&&(i.style.left=h+"px",i.style.right=h+"px"),i.offsetWidth0&&(i.style.right=c+5+"px")):"left"==e?(i.classList.add("title-left"),l>0&&(i.style.left=l+15+"px")):"right"==e&&(i.classList.add("title-right"),c>0&&(i.style.right=c+15+"px"))})}}})}(ionic),function(t){"use strict";var e="item",i="item-content",n="item-sliding",r="item-options",o="item-placeholder",s="item-reordering",a="item-reorder",l=function(){};l.prototype={start:function(){},drag:function(){},end:function(){},isSameItem:function(){return!1}};var c=function(t){this.dragThresholdX=t.dragThresholdX||10,this.el=t.el,this.canSwipe=t.canSwipe};c.prototype=new l,c.prototype.start=function(o){var s,a,l,c;this.canSwipe()&&(s=o.target.classList.contains(i)?o.target:o.target.classList.contains(e)?o.target.querySelector("."+i):t.DomUtil.getParentWithClass(o.target,i),s&&(s.classList.remove(n),l=parseFloat(s.style[t.CSS.TRANSFORM].replace("translate3d(","").split(",")[0])||0,a=s.parentNode.querySelector("."+r),a&&(a.classList.remove("invisible"),c=a.offsetWidth,this._currentDrag={buttons:a,buttonsWidth:c,content:s,startOffsetX:l})))},c.prototype.isSameItem=function(t){return t._lastDrag&&this._currentDrag?this._currentDrag.content==t._lastDrag.content:!1},c.prototype.clean=function(){var e=this._lastDrag;e&&t.requestAnimationFrame(function(){e.content.style[t.CSS.TRANSITION]="",e.content.style[t.CSS.TRANSFORM]="",setTimeout(function(){e.buttons&&e.buttons.classList.add("invisible")},250)})},c.prototype.drag=t.animationFrameThrottle(function(e){var i;if(this._currentDrag&&(!this._isDragging&&(Math.abs(e.gesture.deltaX)>this.dragThresholdX||Math.abs(this._currentDrag.startOffsetX)>0)&&(this._isDragging=!0),this._isDragging)){i=this._currentDrag.buttonsWidth;var n=Math.min(0,this._currentDrag.startOffsetX+e.gesture.deltaX);-i>n&&(n=Math.min(-i,-i+.4*(e.gesture.deltaX+i))),this._currentDrag.content.style[t.CSS.TRANSFORM]="translate3d("+n+"px, 0, 0)",this._currentDrag.content.style[t.CSS.TRANSITION]="none"}}),c.prototype.end=function(e,i){var n=this;if(!this._currentDrag)return void(i&&i());var r=-this._currentDrag.buttonsWidth;e.gesture.deltaX>-(this._currentDrag.buttonsWidth/2)&&("left"==e.gesture.direction&&Math.abs(e.gesture.velocityX)<.3?r=0:"right"==e.gesture.direction&&(r=0)),t.requestAnimationFrame(function(){if(0===r){n._currentDrag.content.style[t.CSS.TRANSFORM]="";var e=n._currentDrag.buttons;setTimeout(function(){e&&e.classList.add("invisible")},250)}else n._currentDrag.content.style[t.CSS.TRANSFORM]="translate3d("+r+"px, 0, 0)";n._currentDrag.content.style[t.CSS.TRANSITION]="",n._lastDrag=n._currentDrag,n._currentDrag=null,i&&i()})};var u=function(t){this.dragThresholdY=t.dragThresholdY||0,this.onReorder=t.onReorder,this.listEl=t.listEl,this.el=t.el,this.scrollEl=t.scrollEl,this.scrollView=t.scrollView};u.prototype=new l,u.prototype._moveElement=function(e){var i=e.gesture.center.pageY-this._currentDrag.elementHeight+this.scrollView.getValues().top-this.listEl.offsetTop;this.el.style[t.CSS.TRANSFORM]="translate3d(0, "+i+"px, 0)"},u.prototype.start=function(e){var i=t.DomUtil.getChildIndex(this.el,this.el.nodeName.toLowerCase()),n=this.el.scrollHeight,r=this.el.cloneNode(!0);r.classList.add(o),this.el.parentNode.insertBefore(r,this.el),this.el.classList.add(s),this._currentDrag={elementHeight:n,startIndex:i,placeholder:r,scrollHeight:scroll,list:r.parentNode},this._moveElement(e)},u.prototype.drag=t.animationFrameThrottle(function(t){if(this._currentDrag){var e=0,i=t.gesture.center.pageY;if(this.scrollView){var n=this.scrollEl;e=this.scrollView.getValues().top;var r=n.offsetTop,o=r-i+this._currentDrag.elementHeight/2,s=i+this._currentDrag.elementHeight/2-r-n.offsetHeight;t.gesture.deltaY<0&&o>0&&e>0&&this.scrollView.scrollBy(null,-o),t.gesture.deltaY>0&&s>0&&ethis.dragThresholdY&&(this._isDragging=!0),this._isDragging&&(this._moveElement(t),this._currentDrag.currentY=e+i-this._currentDrag.placeholder.parentNode.offsetTop,this._reorderItems())}}),u.prototype._reorderItems=function(){var e=this,i=(this._currentDrag.placeholder,Array.prototype.slice.call(this._currentDrag.placeholder.parentNode.children).filter(function(t){return t!==e.el})),n=i.indexOf(this._currentDrag.placeholder),r=i[Math.max(0,n-1)],o=i[Math.min(i.length,n+1)],s=this._currentDrag.currentY;return r&&so.offsetTop+o.offsetHeight/2?(t.DomUtil.swapNodes(o,this._currentDrag.placeholder),n+1):void 0},u.prototype.end=function(e,i){if(!this._currentDrag)return void(i&&i());var n=this._currentDrag.placeholder,r=t.DomUtil.getChildIndex(n,n.nodeName.toLowerCase());this.el.classList.remove(s),this.el.style[t.CSS.TRANSFORM]="",n.parentNode.insertBefore(this.el,n),n.parentNode.removeChild(n),this.onReorder&&this.onReorder(this.el,this._currentDrag.startIndex,r),this._currentDrag=null,i&&i()},t.views.ListView=t.views.View.inherit({initialize:function(e){var i=this;e=t.extend({onReorder:function(){},virtualRemoveThreshold:-200,virtualAddThreshold:200,canSwipe:function(){return!0}},e),t.extend(this,e),!this.itemHeight&&this.listEl&&(this.itemHeight=this.listEl.children[0]&&parseInt(this.listEl.children[0].style.height,10)),this.onRefresh=e.onRefresh||function(){},this.onRefreshOpening=e.onRefreshOpening||function(){},this.onRefreshHolding=e.onRefreshHolding||function(){},window.ionic.onGesture("release",function(t){i._handleEndDrag(t)},this.el),window.ionic.onGesture("drag",function(t){i._handleDrag(t)},this.el),this._initDrag()},stopRefreshing:function(){var t=this.el.querySelector(".list-refresher");t.style.height="0px"},didScroll:function(t){if(this.isVirtual){var e=this.itemHeight,i=(this.listEl.children.length,t.target.scrollHeight),n=this.el.parentNode.offsetHeight,r=(t.scrollTop,Math.max(0,t.scrollTop+this.virtualRemoveThreshold)),o=Math.min(i,Math.abs(t.scrollTop)+n+this.virtualAddThreshold),s=Math.floor((o-r)/e),a=parseInt(Math.abs(r/e),10),l=parseInt(Math.abs(o/e),10);this._virtualItemsToRemove=Array.prototype.slice.call(this.listEl.children,0,a);{Array.prototype.slice.call(this.listEl.children,a,a+s)}this.renderViewport&&this.renderViewport(r,o,a,l)}},didStopScrolling:function(){if(this.isVirtual)for(var t=0;t5){var r=this._getItem(e.target);r&&r.querySelector(".item-options")&&(this._dragOp=new c({el:this.el,canSwipe:this.canSwipe}),this._dragOp.start(e),e.preventDefault())}}else{var r=this._getItem(e.target);r&&(this._dragOp=new u({listEl:this.el,el:r,scrollEl:this.scrollEl,scrollView:this.scrollView,onReorder:function(t,e,n){i.onReorder&&i.onReorder(t,e,n)}}),this._dragOp.start(e),e.preventDefault())}n&&this._dragOp&&!this._dragOp.isSameItem(n)&&e.defaultPrevented&&n.clean&&n.clean()},_handleEndDrag:function(t){var e=this;this._didDragUpOrDown=!1,this._dragOp&&this._dragOp.end(t,function(){e._initDrag()})},_handleDrag:function(t){Math.abs(t.gesture.deltaY)>5&&(this._didDragUpOrDown=!0),this.isDragging||this._dragOp||this._startDrag(t),this._dragOp&&(t.gesture.srcEvent.preventDefault(),this._dragOp.drag(t))}})}(ionic),function(t){"use strict";t.views.Modal=t.views.View.inherit({initialize:function(e){e=t.extend({focusFirstInput:!1,unfocusOnHide:!0,focusFirstDelay:600},e),t.extend(this,e),this.el=e.el -},show:function(){var t=this;t.focusFirstInput&&window.setTimeout(function(){var e=t.el.querySelector("input, textarea");e&&e.focus&&e.focus()},t.focusFirstDelay)},hide:function(){if(this.unfocusOnHide){var t=this.el.querySelectorAll("input, textarea");window.setTimeout(function(){for(var e=0;ee?-v:e>S?v:0,0))}t.continuous&&f.transitions&&(s(r(S-1),-v,0),s(r(S+1),v,0)),f.transitions||(E.style.left=S*-v+"px"),p.style.visibility="visible",t.slidesChanged&&t.slidesChanged()}function i(){t.continuous?o(S-1):S&&o(S-1)}function n(){t.continuous?o(S+1):SS?e:S)-a-1),v*n,0);e=r(e),s(S,v*n,i||b),s(e,0,i||b),t.continuous&&s(r(e-n),-(v*n),0)}else e=r(e),l(S*-v,e*-v,i||b);S=e,_(t.callback&&t.callback(S,g[S]))}}function s(t,e,i){a(t,e,i),m[t]=e}function a(t,e,i){var n=g[t],r=n&&n.style;r&&(r.webkitTransitionDuration=r.MozTransitionDuration=r.msTransitionDuration=r.OTransitionDuration=r.transitionDuration=i+"ms",r.webkitTransform="translate("+e+"px,0)translateZ(0)",r.msTransform=r.MozTransform=r.OTransform="translateX("+e+"px)")}function l(e,i,n){if(!n)return void(E.style.left=i+"px");var r=+new Date,o=setInterval(function(){var s=+new Date-r;return s>n?(E.style.left=i+"px",D&&c(),t.transitionEnd&&t.transitionEnd.call(event,S,g[S]),void clearInterval(o)):void(E.style.left=(i-e)*(Math.floor(s/n*100)/100)+e+"px")},4)}function c(){y=setTimeout(n,D)}function u(){D=t.auto||0,clearTimeout(y)}var h=this,d=function(){},_=function(t){setTimeout(t||d,0)},f={addEventListener:!!window.addEventListener,touch:"ontouchstart"in window||window.DocumentTouch&&document instanceof DocumentTouch,transitions:function(t){var e=["transitionProperty","WebkitTransition","MozTransition","OTransition","msTransition"];for(var i in e)if(void 0!==t.style[e[i]])return!0;return!1}(document.createElement("swipe"))},p=t.el;if(p){var g,m,v,T,E=p.children[0];t=t||{};var S=parseInt(t.startSlide,10)||0,b=t.speed||300;t.continuous=void 0!==t.continuous?t.continuous:!0;var y,w,D=t.auto||0,x={},L={},M={handleEvent:function(i){switch(("mousedown"==i.type||"mouseup"==i.type||"mousemove"==i.type)&&(i.touches=[{pageX:i.pageX,pageY:i.pageY}]),i.type){case"mousedown":this.start(i);break;case"touchstart":this.start(i);break;case"touchmove":this.touchmove(i);break;case"mousemove":this.touchmove(i);break;case"touchend":_(this.end(i));break;case"mouseup":_(this.end(i));break;case"webkitTransitionEnd":case"msTransitionEnd":case"oTransitionEnd":case"otransitionend":case"transitionend":_(this.transitionEnd(i));break;case"resize":_(e)}t.stopPropagation&&i.stopPropagation()},start:function(t){var e=t.touches[0];x={x:e.pageX,y:e.pageY,time:+new Date},w=void 0,L={},f.touch?(E.addEventListener("touchmove",this,!1),E.addEventListener("touchend",this,!1)):(E.addEventListener("mousemove",this,!1),E.addEventListener("mouseup",this,!1),document.addEventListener("mouseup",this,!1))},touchmove:function(e){if(!(e.touches.length>1||e.scale&&1!==e.scale||h.slideIsDisabled)){t.disableScroll&&e.preventDefault();var i=e.touches[0];L={x:i.pageX-x.x,y:i.pageY-x.y},"undefined"==typeof w&&(w=!!(w||Math.abs(L.x)0||S==g.length-1&&L.x<0?Math.abs(L.x)/v+1:1),a(S-1,L.x+m[S-1],0),a(S,L.x+m[S],0),a(S+1,L.x+m[S+1],0)))}},end:function(){var e=+new Date-x.time,i=Number(e)<250&&Math.abs(L.x)>20||Math.abs(L.x)>v/2,n=!S&&L.x>0||S==g.length-1&&L.x<0;t.continuous&&(n=!1);var o=L.x<0;w||(i&&!n?(o?(t.continuous?(s(r(S-1),-v,0),s(r(S+2),v,0)):s(S-1,-v,0),s(S,m[S]-v,b),s(r(S+1),m[r(S+1)]-v,b),S=r(S+1)):(t.continuous?(s(r(S+1),v,0),s(r(S-2),-v,0)):s(S+1,v,0),s(S,m[S]+v,b),s(r(S-1),m[r(S-1)]+v,b),S=r(S-1)),t.callback&&t.callback(S,g[S])):t.continuous?(s(r(S-1),-v,b),s(S,0,b),s(r(S+1),v,b)):(s(S-1,-v,b),s(S,0,b),s(S+1,v,b))),f.touch?(E.removeEventListener("touchmove",M,!1),E.removeEventListener("touchend",M,!1)):(E.removeEventListener("mousemove",M,!1),E.removeEventListener("mouseup",M,!1),document.removeEventListener("mouseup",M,!1))},transitionEnd:function(e){parseInt(e.target.getAttribute("data-index"),10)==S&&(D&&c(),t.transitionEnd&&t.transitionEnd.call(e,S,g[S]))}};this.update=function(){setTimeout(e)},this.setup=function(){e()},this.enableSlide=function(t){return arguments.length&&(this.slideIsDisabled=!t),!this.slideIsDisabled},this.slide=function(t,e){u(),o(t,e)},this.prev=this.previous=function(){u(),i()},this.next=function(){u(),n()},this.stop=function(){u()},this.currentIndex=function(){return S},this.slidesCount=function(){return T},this.kill=function(){u(),E.style.width="",E.style.left="";for(var t=g.length;t--;){var e=g[t];e.style.width="",e.style.left="",f.transitions&&a(t,0,0)}f.addEventListener?(E.removeEventListener("touchstart",M,!1),E.removeEventListener("webkitTransitionEnd",M,!1),E.removeEventListener("msTransitionEnd",M,!1),E.removeEventListener("oTransitionEnd",M,!1),E.removeEventListener("otransitionend",M,!1),E.removeEventListener("transitionend",M,!1),window.removeEventListener("resize",M,!1)):window.onresize=null},this.load=function(){e(),D&&c(),f.addEventListener?(f.touch?E.addEventListener("touchstart",M,!1):E.addEventListener("mousedown",M,!1),f.transitions&&(E.addEventListener("webkitTransitionEnd",M,!1),E.addEventListener("msTransitionEnd",M,!1),E.addEventListener("oTransitionEnd",M,!1),E.addEventListener("otransitionend",M,!1),E.addEventListener("transitionend",M,!1)),window.addEventListener("resize",M,!1)):window.onresize=function(){e()}}}}})}(ionic),function(t){"use strict";t.views.Toggle=t.views.View.inherit({initialize:function(e){var i=this;this.el=e.el,this.checkbox=e.checkbox,this.track=e.track,this.handle=e.handle,this.openPercent=-1,this.onChange=e.onChange||function(){},this.triggerThreshold=e.triggerThreshold||20,this.dragStartHandler=function(t){i.dragStart(t)},this.dragHandler=function(t){i.drag(t)},this.holdHandler=function(t){i.hold(t)},this.releaseHandler=function(t){i.release(t)},this.dragStartGesture=t.onGesture("dragstart",this.dragStartHandler,this.el),this.dragGesture=t.onGesture("drag",this.dragHandler,this.el),this.dragHoldGesture=t.onGesture("hold",this.holdHandler,this.el),this.dragReleaseGesture=t.onGesture("release",this.releaseHandler,this.el)},destroy:function(){t.offGesture(this.dragStartGesture,"dragstart",this.dragStartGesture),t.offGesture(this.dragGesture,"drag",this.dragGesture),t.offGesture(this.dragHoldGesture,"hold",this.holdHandler),t.offGesture(this.dragReleaseGesture,"release",this.releaseHandler)},tap:function(){"disabled"!==this.el.getAttribute("disabled")&&this.val(!this.checkbox.checked)},dragStart:function(t){this.checkbox.disabled||(this._dragInfo={width:this.el.offsetWidth,left:this.el.offsetLeft,right:this.el.offsetLeft+this.el.offsetWidth,triggerX:this.el.offsetWidth/2,initialState:this.checkbox.checked},t.gesture.srcEvent.preventDefault(),this.hold(t))},drag:function(e){var i=this;this._dragInfo&&(e.gesture.srcEvent.preventDefault(),t.requestAnimationFrame(function(){var t=(i.track.offsetLeft+i.handle.offsetWidth/2,i.track.offsetLeft+i.track.offsetWidth-i.handle.offsetWidth/2,e.gesture.deltaX,e.gesture.touches[0].pageX-i._dragInfo.left),n=i._dragInfo.width-i.triggerThreshold;i._dragInfo.initialState?ti._dragInfo.triggerX&&i.setOpenPercent(100):tn&&i.setOpenPercent(100)}))},endDrag:function(){this._dragInfo=null},hold:function(){this.el.classList.add("dragging")},release:function(t){this.el.classList.remove("dragging"),this.endDrag(t)},setOpenPercent:function(e){if(this.openPercent<0||ethis.openPercent+3)if(this.openPercent=e,0===e)this.val(!1);else if(100===e)this.val(!0);else{var i=Math.round(e/100*this.track.offsetWidth-this.handle.offsetWidth);i=1>i?0:i,this.handle.style[t.CSS.TRANSFORM]="translate3d("+i+"px,0,0)"}},val:function(e){return(e===!0||e===!1)&&(""!==this.handle.style[t.CSS.TRANSFORM]&&(this.handle.style[t.CSS.TRANSFORM]=""),this.checkbox.checked=e,this.openPercent=e?100:0,this.onChange&&this.onChange()),this.checkbox.checked}})}(ionic),function(t){"use strict";t.controllers.ViewController=function(){this.initialize.apply(this,arguments)},t.controllers.ViewController.inherit=t.inherit,t.extend(t.controllers.ViewController.prototype,{initialize:function(){},destroy:function(){}})}(window.ionic),function(t){"use strict";t.controllers.SideMenuController=t.controllers.ViewController.inherit({initialize:function(t){var e=this;this.left=t.left,this.right=t.right,this.content=t.content,this.dragThresholdX=t.dragThresholdX||10,this._rightShowing=!1,this._leftShowing=!1,this._isDragging=!1,this.content&&(this.content.onDrag=function(t){e._handleDrag(t)},this.content.onEndDrag=function(t){e._endDrag(t)})},setContent:function(t){var e=this;this.content=t,this.content.onDrag=function(t){e._handleDrag(t)},this.content.endDrag=function(t){e._endDrag(t)}},isOpenLeft:function(){return this.getOpenAmount()>0},isOpenRight:function(){return this.getOpenAmount()<0},toggleLeft:function(t){var e=this.getOpenAmount();0===arguments.length&&(t=0>=e),this.content.enableAnimation(),this.openPercentage(t?100:0)},toggleRight:function(t){var e=this.getOpenAmount();0===arguments.length&&(t=e>=0),this.content.enableAnimation(),this.openPercentage(t?-100:0)},close:function(){this.openPercentage(0)},getOpenAmount:function(){return this.content&&this.content.getTranslateX()||0},getOpenRatio:function(){var t=this.getOpenAmount();return t>=0?t/this.left.width:t/this.right.width},isOpen:function(){return 0!==this.getOpenAmount()},getOpenPercentage:function(){return 100*this.getOpenRatio()},openPercentage:function(t){var e=t/100;if(this.left&&t>=0)this.openAmount(this.left.width*e);else if(this.right&&0>t){{this.right.width}this.openAmount(this.right.width*e)}},openAmount:function(t){var e=this.left&&this.left.width||0,i=this.right&&this.right.width||0;return(this.left&&this.left.isEnabled||!(t>0))&&(this.right&&this.right.isEnabled||!(0>t))?this._leftShowing&&t>e?void this.content.setTranslateX(e):this._rightShowing&&-i>t?void this.content.setTranslateX(-i):(this.content.setTranslateX(t),void(t>=0?(this._leftShowing=!0,this._rightShowing=!1,t>0&&(this.right&&this.right.pushDown&&this.right.pushDown(),this.left&&this.left.bringUp&&this.left.bringUp())):(this._rightShowing=!0,this._leftShowing=!1,this.right&&this.right.bringUp&&this.right.bringUp(),this.left&&this.left.pushDown&&this.left.pushDown()))):void this.content.setTranslateX(0)},snapToRest:function(t){this.content.enableAnimation(),this._isDragging=!1;var e=this.getOpenRatio();if(0===e)return void this.openPercentage(0);var i=.3,n=t.gesture.velocityX,r=t.gesture.direction;this.openPercentage(e>0&&.5>e&&"right"==r&&i>n?0:e>.5&&"left"==r&&i>n?100:0>e&&e>-.5&&"left"==r&&i>n?0:.5>e&&"right"==r&&i>n?-100:"right"==r&&e>=0&&(e>=.5||n>i)?100:"left"==r&&0>=e&&(-.5>=e||n>i)?-100:0)},_endDrag:function(t){this._isDragging&&this.snapToRest(t),this._startX=null,this._lastX=null,this._offsetX=null},_handleDrag:function(t){this._startX?this._lastX=t.gesture.touches[0].pageX:(this._startX=t.gesture.touches[0].pageX,this._lastX=this._startX),!this._isDragging&&Math.abs(this._lastX-this._startX)>this.dragThresholdX&&(this._startX=this._lastX,this._isDragging=!0,this.content.disableAnimation(),this._offsetX=this.getOpenAmount()),this._isDragging&&this.openAmount(this._offsetX+(this._lastX-this._startX))}})}(ionic)}(); \ No newline at end of file +!function(){function t(t,e,n){e!==!1?z.addEventListener(t,B[t],n):z.removeEventListener(t,B[t])}function e(t){var e=E(t.target),i=w(e);if(ionic.tap.requiresNativeClick(i)||F)return!1;var r=T(t);n("click",i,r.x,r.y),f(i)}function n(t,e,n,i){var r=document.createEvent("MouseEvents");r.initMouseEvent(t,!0,!0,window,1,0,0,n,i,!1,!1,!1,!1,0,null),r.isIonicTap=!0,e.dispatchEvent(r)}function i(t){return("submit"!=t.target.type||0!==t.detail)&&(ionic.scroll.isScrolling&&ionic.tap.containsOrIsTextInput(t.target)||!t.isIonicTap&&!ionic.tap.requiresNativeClick(t.target))?(t.stopPropagation(),ionic.tap.isLabelWithTextInput(t.target)||t.preventDefault(),!1):void 0}function r(e){if(!e.isIonicTap&&!d(e)){if(Y)return e.stopPropagation(),ionic.tap.isTextInput(e.target)||e.preventDefault(),!1;F=!1,q=T(e),t("mousemove"),ionic.activator.start(e)}}function o(n){return Y?(n.stopPropagation(),n.preventDefault(),!1):d(n)||"SELECT"===n.target.tagName?!1:(v(n)||e(n),t("mousemove",!1),ionic.activator.end(),void(F=!1))}function a(e){return v(e)?(t("mousemove",!1),ionic.activator.end(),F=!0,!1):void 0}function s(e){if(!d(e)&&(F=!1,h(),q=T(e),t("touchmove"),ionic.activator.start(e),ionic.Platform.isIOS()&&ionic.tap.isLabelWithTextInput(e.target))){var n=w(E(e.target));n!==k&&e.preventDefault()}}function c(t){d(t)||(h(),v(t)||e(t),u())}function l(e){return v(e)?(F=!0,t("touchmove",!1),ionic.activator.end(),!1):void 0}function u(){t("touchmove",!1),ionic.activator.end(),F=!1}function h(){Y=!0,clearTimeout(H),H=setTimeout(function(){Y=!1},2e3)}function d(t){return t.isTapHandled?!0:(t.isTapHandled=!0,ionic.scroll.isScrolling&&ionic.tap.containsOrIsTextInput(t.target)?(t.preventDefault(),!0):void 0)}function f(t){W=null;var e=!1;"SELECT"==t.tagName?(n("mousedown",t,0,0),t.focus&&t.focus(),e=!0):m()===t?e=!0:/input|textarea/i.test(t.tagName)?(e=!0,t.focus&&t.focus(),t.value=t.value,Y&&(W=t)):_(),e&&(m(t),ionic.trigger("ionic.focusin",{target:t},!0))}function _(){var t=m();t&&/input|textarea|select/i.test(t.tagName)&&t.blur(),m(null)}function p(t){Y&&ionic.tap.isTextInput(m())&&ionic.tap.isTextInput(W)&&W!==t.target&&(W.focus(),W=null),ionic.scroll.isScrolling=!1}function g(){m(null)}function m(t){return arguments.length&&(k=t),k||document.activeElement}function v(t){if(!t||!q||0===q.x&&0===q.y)return!1;var e=T(t);return Math.abs(q.x-e.x)>U||Math.abs(q.y-e.y)>U}function T(t){var e={x:0,y:0};if(t){var n=t.touches&&t.touches.length?t.touches:[t],i=t.changedTouches&&t.changedTouches[0]||n[0];i&&(e.x=i.clientX||i.pageX||0,e.y=i.clientY||i.pageY||0)}return e}function E(t,e){for(var n=t,i=0;6>i&&n;i++){if("LABEL"===n.tagName)return n;n=t.parentElement}return e!==!1?t:void 0}function w(t){if(t&&"LABEL"===t.tagName){if(t.control)return t.control;if(t.querySelector){var e=t.querySelector("input,textarea,select");if(e)return e}}return t}function y(){C()?(window.addEventListener("native.showkeyboard",S),window.addEventListener("native.hidekeyboard",x)):document.body.addEventListener("focusout",x),document.body.addEventListener("ionic.focusin",b),document.body.addEventListener("focusin",b),document.body.addEventListener("orientationchange",G),document.removeEventListener("touchstart",y)}function S(t){clearTimeout(j),ionic.keyboard.height=t.keyboardHeight}function b(t){t.target&&ionic.tap.isTextInput(t.target)&&P(t.target)&&(document.addEventListener("keydown",O,!1),document.body.scrollTop=0,document.body.querySelector(".scroll-content").scrollTop=0,Z=t.target,M(t))}function M(t){clearTimeout(Q),clearTimeout(j),Q=setTimeout(function(){if(!(J+350>Date.now())){J=Date.now();var e,n=Z.getBoundingClientRect(),i=0,r=setInterval(function(){e=N(),i>10&&(clearInterval(r),e=275),e&&(D(t.target,n.top,n.bottom,K,e),clearInterval(r)),i++},100)}},32)}function D(t,e,n,i,r){var o={target:t,elementTop:Math.round(e),elementBottom:Math.round(n),keyboardHeight:r};return o.hasPlugin=C(),o.contentHeight=i-r,o.keyboardTopOffset=o.elementTop-o.contentHeight,o.isElementUnderKeyboard=o.elementBottom>o.contentHeight,ionic.keyboard.isOpen=!0,Z=t,ionic.trigger("scrollChildIntoView",o,!0),ionic.requestAnimationFrame(function(){document.body.classList.add($)}),document.addEventListener("touchmove",I,!1),o}function x(){clearTimeout(Q),clearTimeout(j),j=setTimeout(L,350)}function L(){ionic.keyboard.isOpen=!1,ionic.trigger("resetScrollView",{target:Z},!0),ionic.requestAnimationFrame(function(){document.body.classList.remove($)}),document.removeEventListener("touchmove",I),document.removeEventListener("keydown",O)}function A(){window.innerHeight>K&&(K=window.innerHeight)}function O(t){ionic.scroll.isScrolling&&I(t)}function I(t){t.preventDefault()}function G(){var t=window.innerHeight;if(t===K)var e=0,n=setInterval(function(){e>10&&clearInterval(n),t=window.innerHeight,t!==K&&(ionic.keyboard.landscape=K>t?!0:!1,K=t,clearInterval(n)),e++},50);else K=t}function N(){return ionic.keyboard.height?ionic.keyboard.height:ionic.Platform.isAndroid()?ionic.Platform.isFullScreen?275:window.innerHeight1?e[1]:"_");V()}}function V(){var t=ne.width,e=ne.height,n=ionic.Platform,i=n.version(),r="device-width",o="device-height",a=ionic.viewport.orientation();delete ne.height,ne.width=r,n.isIPad()?i>7?delete ne.width:n.isWebView()?90==a?ne.height="0":7==i&&(ne.height=o):7>i&&(ne.height="0"):n.isIOS()&&(n.isWebView()&&i>7?delete ne.width:7>i&&e&&(ne.height="0")),(t!==ne.width||e!==ne.height)&&X()}function X(){var t,e=[];for(t in ne)ne[t]&&e.push(t+("_"==ne[t]?"":"="+ne[t]));ee.content=e.join(", ")}window.ionic={controllers:{},views:{},version:"1.0.0-beta.4"},function(t){function e(t){return t*t*t}function n(t){return 3*t*t*(1-t)}function i(t){return 3*t*(1-t)*(1-t)}function r(t){return(1-t)*(1-t)*(1-t)}var o=function(t,e){return t||(t=0),e||(e=0),{x:t,y:e}};t.Animator={getQuadraticBezier:function(t,a,s,c,l){var u=new o;return u.x=a.x*e(t)+s.x*n(t)+c.x*i(t)+l.x*r(t),u.y=a.y*e(t)+s.y*n(t)+c.y*i(t)+l.y*r(t),u},getCubicBezier:function(t,e,n,i,r){epsilon=1e3/60/r/4;var o=function(e){var i=1-e;return 3*i*i*e*t+3*i*e*e*n+e*e*e},a=function(t){var n=1-t;return 3*n*n*t*e+3*n*t*t*i+t*t*t},s=function(e){var i=1-e;return 3*(2*(e-1)*e+i*i)*t+3*(-e*e*e+2*i*e)*n};return function(t){var e,n,i,r,c,l,u=t;for(i=u,l=0;8>l;l++){if(r=o(i)-u,Math.abs(r)i)return a(e);if(i>n)return a(n);for(;n>e;){if(r=o(i),Math.abs(r-u)r?e=i:n=i,i=.5*(n-e)+e}return a(i)}},animate:function(t){return{leave:function(){var e=function(){t.classList.remove("leave"),t.classList.remove("leave-active"),t.removeEventListener("webkitTransitionEnd",e),t.removeEventListener("transitionEnd",e)};return t.addEventListener("webkitTransitionEnd",e),t.addEventListener("transitionEnd",e),t.classList.add("leave"),t.classList.add("leave-active"),this},enter:function(){var e=function(){t.classList.remove("enter"),t.classList.remove("enter-active"),t.removeEventListener("webkitTransitionEnd",e),t.removeEventListener("transitionEnd",e)};return t.addEventListener("webkitTransitionEnd",e),t.addEventListener("transitionEnd",e),t.classList.add("enter"),t.classList.add("enter-active"),this}}}}}(ionic),function(t,e,n){function i(){o=!0;for(var t=0;tr;r++)if(n=i[r],n.nodeName&&n.nodeName.toLowerCase()==e){if(n==t)return o;o++}return Array.prototype.slice.call(t.parentNode.children).indexOf(t)},swapNodes:function(t,e){e.parentNode.insertBefore(t,e)},centerElementByMargin:function(t){t.style.marginLeft=-t.offsetWidth/2+"px",t.style.marginTop=-t.offsetHeight/2+"px"},centerElementByMarginTwice:function(t){n.requestAnimationFrame(function(){n.DomUtil.centerElementByMargin(t),n.requestAnimationFrame(function(){n.DomUtil.centerElementByMargin(t)})})},getParentWithClass:function(t,e,n){for(n=n||10;t.parentNode&&n--;){if(t.parentNode.classList&&t.parentNode.classList.contains(e))return t.parentNode;t=t.parentNode}return null},getParentOrSelfWithClass:function(t,e,n){for(n=n||10;t&&n--;){if(t.classList&&t.classList.contains(e))return t;t=t.parentNode}return null},rectContains:function(t,e,n,i,r,o){return n>t||t>r?!1:i>e||e>o?!1:!0}},n.requestAnimationFrame=n.DomUtil.requestAnimationFrame,n.animationFrameThrottle=n.DomUtil.animationFrameThrottle}(window,document,ionic),function(t){t.CustomEvent=window.CustomEvent||function(){var t;return t=function(t,e){var n;e=e||{bubbles:!1,cancelable:!1,detail:void 0};try{n=document.createEvent("CustomEvent"),n.initCustomEvent(t,e.bubbles,e.cancelable,e.detail)}catch(i){n=document.createEvent("Event");for(var r in e)n[r]=e[r];n.initEvent(t,e.bubbles,e.cancelable)}return n},t.prototype=window.Event.prototype,t}(),t.EventController={VIRTUALIZED_EVENTS:["tap","swipe","swiperight","swipeleft","drag","hold","release"],trigger:function(e,n,i,r){var o=new t.CustomEvent(e,{detail:n,bubbles:!!i,cancelable:!!r});n&&n.target&&n.target.dispatchEvent&&n.target.dispatchEvent(o)||window.dispatchEvent(o)},on:function(e,n,i){for(var r=i||window,o=0,a=this.VIRTUALIZED_EVENTS.length;a>o;o++)if(e==this.VIRTUALIZED_EVENTS[o]){var s=new t.Gesture(i);return s.on(e,n),s}r.addEventListener(e,n)},off:function(t,e,n){n.removeEventListener(t,e)},onGesture:function(e,n,i){var r=new t.Gesture(i);return r.on(e,n),r},offGesture:function(t,e,n){t.off(e,n)},handlePopState:function(){}},t.on=function(){t.EventController.on.apply(t.EventController,arguments)},t.off=function(){t.EventController.off.apply(t.EventController,arguments)},t.trigger=t.EventController.trigger,t.onGesture=function(){return t.EventController.onGesture.apply(t.EventController.onGesture,arguments)},t.offGesture=function(){return t.EventController.offGesture.apply(t.EventController.offGesture,arguments)}}(window.ionic),function(t){function e(){if(!t.Gestures.READY){t.Gestures.event.determineEventTypes();for(var e in t.Gestures.gestures)t.Gestures.gestures.hasOwnProperty(e)&&t.Gestures.detection.register(t.Gestures.gestures[e]);t.Gestures.event.onTouch(t.Gestures.DOCUMENT,t.Gestures.EVENT_MOVE,t.Gestures.detection.detect),t.Gestures.event.onTouch(t.Gestures.DOCUMENT,t.Gestures.EVENT_END,t.Gestures.detection.detect),t.Gestures.READY=!0}}t.Gesture=function(e,n){return new t.Gestures.Instance(e,n||{})},t.Gestures={},t.Gestures.defaults={stop_browser_behavior:"disable-user-behavior"},t.Gestures.HAS_POINTEREVENTS=window.navigator.pointerEnabled||window.navigator.msPointerEnabled,t.Gestures.HAS_TOUCHEVENTS="ontouchstart"in window,t.Gestures.MOBILE_REGEX=/mobile|tablet|ip(ad|hone|od)|android|silk/i,t.Gestures.NO_MOUSEEVENTS=t.Gestures.HAS_TOUCHEVENTS&&window.navigator.userAgent.match(t.Gestures.MOBILE_REGEX),t.Gestures.EVENT_TYPES={},t.Gestures.DIRECTION_DOWN="down",t.Gestures.DIRECTION_LEFT="left",t.Gestures.DIRECTION_UP="up",t.Gestures.DIRECTION_RIGHT="right",t.Gestures.POINTER_MOUSE="mouse",t.Gestures.POINTER_TOUCH="touch",t.Gestures.POINTER_PEN="pen",t.Gestures.EVENT_START="start",t.Gestures.EVENT_MOVE="move",t.Gestures.EVENT_END="end",t.Gestures.DOCUMENT=window.document,t.Gestures.plugins={},t.Gestures.READY=!1,t.Gestures.Instance=function(n,i){var r=this;if(null!==n)return e(),this.element=n,this.enabled=!0,this.options=t.Gestures.utils.extend(t.Gestures.utils.extend({},t.Gestures.defaults),i||{}),this.options.stop_browser_behavior&&t.Gestures.utils.stopDefaultBrowserBehavior(this.element,this.options.stop_browser_behavior),t.Gestures.event.onTouch(n,t.Gestures.EVENT_START,function(e){r.enabled&&t.Gestures.detection.startDetect(r,e)}),this},t.Gestures.Instance.prototype={on:function(t,e){for(var n=t.split(" "),i=0;i0&&o==t.Gestures.EVENT_END?o=t.Gestures.EVENT_MOVE:u||(o=t.Gestures.EVENT_END),(u||null===n)&&(n=c),a.call(t.Gestures.detection,s.collectEventData(e,o,s.getTouchList(n,o),c)),t.Gestures.HAS_POINTEREVENTS&&o==t.Gestures.EVENT_END&&(u=t.Gestures.PointerEvent.updatePointer(o,c))),u||(n=null,i=!1,r=!1,t.Gestures.PointerEvent.reset())}})},determineEventTypes:function(){var e;e=t.Gestures.HAS_POINTEREVENTS?t.Gestures.PointerEvent.getEvents():t.Gestures.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],t.Gestures.EVENT_TYPES[t.Gestures.EVENT_START]=e[0],t.Gestures.EVENT_TYPES[t.Gestures.EVENT_MOVE]=e[1],t.Gestures.EVENT_TYPES[t.Gestures.EVENT_END]=e[2]},getTouchList:function(e){return t.Gestures.HAS_POINTEREVENTS?t.Gestures.PointerEvent.getTouchList():e.touches?e.touches:(e.indentifier=1,[e])},collectEventData:function(e,n,i,r){var o=t.Gestures.POINTER_TOUCH;return(r.type.match(/mouse/)||t.Gestures.PointerEvent.matchType(t.Gestures.POINTER_MOUSE,r))&&(o=t.Gestures.POINTER_MOUSE),{center:t.Gestures.utils.getCenter(i),timeStamp:(new Date).getTime(),target:r.target,touches:i,eventType:n,pointerType:o,srcEvent:r,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return t.Gestures.detection.stopDetect()}}}},t.Gestures.PointerEvent={pointers:{},getTouchList:function(){var t=this,e=[];return Object.keys(t.pointers).sort().forEach(function(n){e.push(t.pointers[n])}),e},updatePointer:function(e,n){return e==t.Gestures.EVENT_END?this.pointers={}:(n.identifier=n.pointerId,this.pointers[n.pointerId]=n),Object.keys(this.pointers).length},matchType:function(e,n){if(!n.pointerType)return!1;var i={};return i[t.Gestures.POINTER_MOUSE]=n.pointerType==n.MSPOINTER_TYPE_MOUSE||n.pointerType==t.Gestures.POINTER_MOUSE,i[t.Gestures.POINTER_TOUCH]=n.pointerType==n.MSPOINTER_TYPE_TOUCH||n.pointerType==t.Gestures.POINTER_TOUCH,i[t.Gestures.POINTER_PEN]=n.pointerType==n.MSPOINTER_TYPE_PEN||n.pointerType==t.Gestures.POINTER_PEN,i[e]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},t.Gestures.utils={extend:function(t,e,n){for(var i in e)void 0!==t[i]&&n||(t[i]=e[i]);return t},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){for(var e=[],n=[],i=0,r=t.length;r>i;i++)e.push(t[i].pageX),n.push(t[i].pageY);return{pageX:(Math.min.apply(Math,e)+Math.max.apply(Math,e))/2,pageY:(Math.min.apply(Math,n)+Math.max.apply(Math,n))/2}},getVelocity:function(t,e,n){return{x:Math.abs(e/t)||0,y:Math.abs(n/t)||0}},getAngle:function(t,e){var n=e.pageY-t.pageY,i=e.pageX-t.pageX;return 180*Math.atan2(n,i)/Math.PI},getDirection:function(e,n){var i=Math.abs(e.pageX-n.pageX),r=Math.abs(e.pageY-n.pageY);return i>=r?e.pageX-n.pageX>0?t.Gestures.DIRECTION_LEFT:t.Gestures.DIRECTION_RIGHT:e.pageY-n.pageY>0?t.Gestures.DIRECTION_UP:t.Gestures.DIRECTION_DOWN},getDistance:function(t,e){var n=e.pageX-t.pageX,i=e.pageY-t.pageY;return Math.sqrt(n*n+i*i)},getScale:function(t,e){return t.length>=2&&e.length>=2?this.getDistance(e[0],e[1])/this.getDistance(t[0],t[1]):1},getRotation:function(t,e){return t.length>=2&&e.length>=2?this.getAngle(e[1],e[0])-this.getAngle(t[1],t[0]):0},isVertical:function(e){return e==t.Gestures.DIRECTION_UP||e==t.Gestures.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){t&&t.classList&&(t.classList.add(e),t.onselectstart=function(){return!1})}},t.Gestures.detection={gestures:[],current:null,previous:null,stopped:!1,startDetect:function(e,n){this.current||(this.stopped=!1,this.current={inst:e,startEvent:t.Gestures.utils.extend({},n),lastEvent:!1,name:""},this.detect(n))},detect:function(e){if(this.current&&!this.stopped){e=this.extendEventData(e);for(var n=this.current.inst.options,i=0,r=this.gestures.length;r>i;i++){var o=this.gestures[i];if(!this.stopped&&n[o.name]!==!1&&o.handler.call(o,e,this.current.inst)===!1){this.stopDetect();break}}return this.current&&(this.current.lastEvent=e),e.eventType==t.Gestures.EVENT_END&&!e.touches.length-1&&this.stopDetect(),e}},stopDetect:function(){this.previous=t.Gestures.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(e){var n=this.current.startEvent;if(n&&(e.touches.length!=n.touches.length||e.touches===n.touches)){n.touches=[];for(var i=0,r=e.touches.length;r>i;i++)n.touches.push(t.Gestures.utils.extend({},e.touches[i]))}var o=e.timeStamp-n.timeStamp,a=e.center.pageX-n.center.pageX,s=e.center.pageY-n.center.pageY,c=t.Gestures.utils.getVelocity(o,a,s);return t.Gestures.utils.extend(e,{deltaTime:o,deltaX:a,deltaY:s,velocityX:c.x,velocityY:c.y,distance:t.Gestures.utils.getDistance(n.center,e.center),angle:t.Gestures.utils.getAngle(n.center,e.center),direction:t.Gestures.utils.getDirection(n.center,e.center),scale:t.Gestures.utils.getScale(n.touches,e.touches),rotation:t.Gestures.utils.getRotation(n.touches,e.touches),startEvent:n}),e},register:function(e){var n=e.defaults||{};return void 0===n[e.name]&&(n[e.name]=!0),t.Gestures.utils.extend(t.Gestures.defaults,n,!0),e.index=e.index||1e3,this.gestures.push(e),this.gestures.sort(function(t,e){return t.indexe.index?1:0}),this.gestures}},t.Gestures.gestures=t.Gestures.gestures||{},t.Gestures.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(e,n){switch(e.eventType){case t.Gestures.EVENT_START:clearTimeout(this.timer),t.Gestures.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==t.Gestures.detection.current.name&&n.trigger("hold",e)},n.options.hold_timeout);break;case t.Gestures.EVENT_MOVE:e.distance>n.options.hold_threshold&&clearTimeout(this.timer);break;case t.Gestures.EVENT_END:clearTimeout(this.timer)}}},t.Gestures.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(e,n){if(e.eventType==t.Gestures.EVENT_END&&"touchcancel"!=e.srcEvent.type){var i=t.Gestures.detection.previous,r=!1;if(e.deltaTime>n.options.tap_max_touchtime||e.distance>n.options.tap_max_distance)return;i&&"tap"==i.name&&e.timeStamp-i.lastEvent.timeStamp0&&e.touches.length>n.options.swipe_max_touches)return;(e.velocityX>n.options.swipe_velocity||e.velocityY>n.options.swipe_velocity)&&(n.trigger(this.name,e),n.trigger(this.name+e.direction,e))}}},t.Gestures.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,correct_for_drag_min_distance:!0,drag_max_touches:1,drag_block_horizontal:!0,drag_block_vertical:!0,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(e,n){if(t.Gestures.detection.current.name!=this.name&&this.triggered)return n.trigger(this.name+"end",e),void(this.triggered=!1);if(!(n.options.drag_max_touches>0&&e.touches.length>n.options.drag_max_touches))switch(e.eventType){case t.Gestures.EVENT_START:this.triggered=!1;break;case t.Gestures.EVENT_MOVE:if(e.distancen.options.transform_min_rotation&&n.trigger("rotate",e),i>n.options.transform_min_scale&&(n.trigger("pinch",e),n.trigger("pinch"+(e.scale<1?"in":"out"),e));break;case t.Gestures.EVENT_END:this.triggered&&n.trigger(this.name+"end",e),this.triggered=!1}}},t.Gestures.gestures.Touch={name:"touch",index:-1/0,defaults:{prevent_default:!1,prevent_mouseevents:!1},handler:function(e,n){return n.options.prevent_mouseevents&&e.pointerType==t.Gestures.POINTER_MOUSE?void e.stopDetect():(n.options.prevent_default&&e.preventDefault(),void(e.eventType==t.Gestures.EVENT_START&&n.trigger(this.name,e)))}},t.Gestures.gestures.Release={name:"release",index:1/0,handler:function(e,n){e.eventType==t.Gestures.EVENT_END&&n.trigger(this.name,e)}}}(window.ionic),function(t,e,n){function i(){n.Platform.isWebView()?e.addEventListener("deviceready",r,!1):r(),t.removeEventListener("load",i,!1)}function r(){n.Platform.isReady=!0,n.Platform.detect();for(var t=0;t0?n=n.replace(".","_"):n+="_0",this.platforms.push(t+n.split("_")[0]),this.platforms.push(t+n),this.isAndroid()&&4.4>e&&(this.grade=4>e?"c":"b")}}},isWebView:function(){return!(!t.cordova&&!t.PhoneGap&&!t.phonegap)},isIPad:function(){return/iPad/i.test(t.navigator.platform)?!0:/iPad/i.test(this.ua)},isIOS:function(){return this.is("ios")},isAndroid:function(){return this.is("android")},platform:function(){return null===o&&this.setPlatform(this.device().platform),o},setPlatform:function(e){o="undefined"!=typeof e&&null!==e&&e.length?e.toLowerCase():this.ua.indexOf("Android")>0?"android":this.ua.indexOf("iPhone")>-1||this.ua.indexOf("iPad")>-1||this.ua.indexOf("iPod")>-1?"ios":t.navigator.platform&&t.navigator.platform.toLowerCase().split(" ")[0]||""},version:function(){return null===a&&this.setVersion(this.device().version),a},setVersion:function(t){if("undefined"!=typeof t&&null!==t&&(t=t.split("."),t=parseFloat(t[0]+"."+(t.length>1?t[1]:0)),!isNaN(t)))return void(a=t);a=0;var e=this.platform(),n={android:/Android (\d+).(\d+)?/,ios:/OS (\d+)_(\d+)?/};n[e]&&(t=this.ua.match(n[e]),t.length>2&&(a=parseFloat(t[1]+"."+t[2])))},is:function(t){if(t=t.toLowerCase(),this.platforms)for(var e=0;e=0},exitApp:function(){this.ready(function(){navigator.app&&navigator.app.exitApp&&navigator.app.exitApp()})},showStatusBar:function(i){this._showStatusBar=i,this.ready(function(){n.requestAnimationFrame(function(){n.Platform._showStatusBar?(t.StatusBar&&t.StatusBar.show(),e.body.classList.remove("status-bar-hide")):(t.StatusBar&&t.StatusBar.hide(),e.body.classList.add("status-bar-hide"))})})},fullScreen:function(t,i){this.isFullScreen=t!==!1,n.DomUtil.ready(function(){n.requestAnimationFrame(function(){n.Platform.isFullScreen?e.body.classList.add("fullscreen"):e.body.classList.remove("fullscreen")}),n.Platform.showStatusBar(i===!0)})}};var o=null,a=null,s=[];t.addEventListener("load",i,!1)}(this,document,ionic),function(t,e){"use strict";e.CSS={},function(){var n,i=["webkitTransform","transform","-webkit-transform","webkit-transform","-moz-transform","moz-transform","MozTransform","mozTransform"];for(n=0;nc&&(a&&1===a.nodeType);c++){if(r&&a.classList.contains("item")){r=a;break}if(("A"==a.tagName||"BUTTON"==a.tagName||a.hasAttribute("ng-click"))&&(r=a),a.classList.contains("button")){r=a;break}a=a.parentElement}r&&(o[s]=r,"touchstart"===t.type?n._activateTimeout=setTimeout(i,80):e.requestAnimationFrame(i),s=s>19?0:s+1)}})},end:function(){clearTimeout(this._activateTimeout),setTimeout(n,200)}}}(document,ionic),function(t){var e=["0","0","0"];t.Utils={arrayMove:function(t,e,n){if(n>=t.length)for(var i=n-t.length;i--+1;)t.push(void 0);return t.splice(n,0,t.splice(e,1)[0]),t},proxy:function(t,e){var n=Array.prototype.slice.call(arguments,2); +return function(){return t.apply(e,n.concat(Array.prototype.slice.call(arguments)))}},debounce:function(t,e,n){var i,r,o,a,s;return function(){o=this,r=arguments,a=new Date;var c=function(){var l=new Date-a;e>l?i=setTimeout(c,e-l):(i=null,n||(s=t.apply(o,r)))},l=n&&!i;return i||(i=setTimeout(c,e)),l&&(s=t.apply(o,r)),s}},throttle:function(t,e,n){var i,r,o,a=null,s=0;n||(n={});var c=function(){s=n.leading===!1?0:Date.now(),a=null,o=t.apply(i,r)};return function(){var l=Date.now();s||n.leading!==!1||(s=l);var u=e-(l-s);return i=this,r=arguments,0>=u?(clearTimeout(a),a=null,s=l,o=t.apply(i,r)):a||n.trailing===!1||(a=setTimeout(c,u)),o}},inherit:function(e,n){var i,r=this;i=e&&e.hasOwnProperty("constructor")?e.constructor:function(){return r.apply(this,arguments)},t.extend(i,r,n);var o=function(){this.constructor=i};return o.prototype=r.prototype,i.prototype=new o,e&&t.extend(i.prototype,e),i.__super__=r.prototype,i},extend:function(t){for(var e=Array.prototype.slice.call(arguments,1),n=0;nwindow.innerHeight?90:0}},ionic.Platform.ready(function(){R(),window.addEventListener("orientationchange",function(){setTimeout(V,1e3)},!1)}),function(t){"use strict";t.views.View=function(){this.initialize.apply(this,arguments)},t.views.View.inherit=t.inherit,t.extend(t.views.View.prototype,{initialize:function(){}})}(window.ionic);var ie={effect:{}};!function(t){var e=Date.now||function(){return+new Date},n=60,i=1e3,r={},o=1;ie.effect.Animate={requestAnimationFrame:function(){var e=t.requestAnimationFrame||t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||t.oRequestAnimationFrame,n=!!e;if(e&&!/requestAnimationFrame\(\)\s*\{\s*\[native code\]\s*\}/i.test(e.toString())&&(n=!1),n)return function(t,n){e(t,n)};var i=60,r={},o=0,a=1,s=null,c=+new Date;return function(t){var e=a++;return r[e]=t,o++,null===s&&(s=setInterval(function(){var t=+new Date,e=r;r={},o=0;for(var n in e)e.hasOwnProperty(n)&&(e[n](t),c=t);t-c>2500&&(clearInterval(s),s=null)},1e3/i)),e}}(),stop:function(t){var e=null!=r[t];return e&&(r[t]=null),e},isRunning:function(t){return null!=r[t]},start:function(t,a,s,c,l,u){var h=e(),d=h,f=0,_=0,p=o++;if(u||(u=document.body),p%20===0){var g={};for(var m in r)g[m]=!0;r=g}var v=function(o){var g=o!==!0,m=e();if(!r[p]||a&&!a(p))return r[p]=null,void(s&&s(n-_/((m-h)/i),p,!1));if(g)for(var T=Math.round((m-d)/(i/n))-1,E=0;E1&&(f=1));var w=l?l(f):f;t(w,m,g)!==!1&&1!==f||!g?g&&(d=m,ie.effect.Animate.requestAnimationFrame(v,u)):(r[p]=null,s&&s(n-_/((m-h)/i),p,1===f||null==c))};return r[p]=!0,ie.effect.Animate.requestAnimationFrame(v,u),p}}}(this);!function(t){var e=function(){},n=function(t){return Math.pow(t-1,3)+1},i=function(t){return(t/=.5)<1?.5*Math.pow(t,3):.5*(Math.pow(t-2,3)+2)};t.views.Scroll=t.views.View.inherit({initialize:function(n){var i=this;this.__container=n.el,this.__content=n.el.firstElementChild,setTimeout(function(){i.__container&&i.__content&&(i.__container.scrollTop=0,i.__content.scrollTop=0)}),this.options={scrollingX:!1,scrollbarX:!0,scrollingY:!0,scrollbarY:!0,startX:0,startY:0,wheelDampen:6,minScrollbarSizeX:5,minScrollbarSizeY:5,scrollbarsFade:!0,scrollbarFadeDelay:300,scrollbarResizeFadeDelay:1e3,animating:!0,animationDuration:250,bouncing:!0,locking:!0,paging:!1,snapping:!1,zooming:!1,minZoom:.5,maxZoom:3,speedMultiplier:1,scrollingComplete:e,penetrationDeceleration:.03,penetrationAcceleration:.08,scrollEventInterval:10,getContentWidth:function(){return Math.max(i.__content.scrollWidth,i.__content.offsetWidth)},getContentHeight:function(){return Math.max(i.__content.scrollHeight,i.__content.offsetHeight)}};for(var r in n)this.options[r]=n[r];this.hintResize=t.debounce(function(){i.resize()},1e3,!0),this.onScroll=function(){t.scroll.isScrolling?(clearTimeout(i.scrollTimer),i.scrollTimer=setTimeout(i.setScrollStop,80)):setTimeout(i.setScrollStart,50)},this.setScrollStart=function(){t.scroll.isScrolling=Math.abs(t.scroll.lastTop-i.__scrollTop)>1,clearTimeout(i.scrollTimer),i.scrollTimer=setTimeout(i.setScrollStop,80)},this.setScrollStop=function(){t.scroll.isScrolling=!1,t.scroll.lastTop=i.__scrollTop},this.triggerScrollEvent=t.throttle(function(){i.onScroll(),t.trigger("scroll",{scrollTop:i.__scrollTop,scrollLeft:i.__scrollLeft,target:i.__container})},this.options.scrollEventInterval),this.triggerScrollEndEvent=function(){t.trigger("scrollend",{scrollTop:i.__scrollTop,scrollLeft:i.__scrollLeft,target:i.__container})},this.__scrollLeft=this.options.startX,this.__scrollTop=this.options.startY,this.__callback=this.getRenderFn(),this.__initEventHandlers(),this.__createScrollbars()},run:function(){this.resize(),this.__fadeScrollbars("out",this.options.scrollbarResizeFadeDelay)},__isSingleTouch:!1,__isTracking:!1,__didDecelerationComplete:!1,__isGesturing:!1,__isDragging:!1,__isDecelerating:!1,__isAnimating:!1,__clientLeft:0,__clientTop:0,__clientWidth:0,__clientHeight:0,__contentWidth:0,__contentHeight:0,__snapWidth:100,__snapHeight:100,__refreshHeight:null,__refreshActive:!1,__refreshActivate:null,__refreshDeactivate:null,__refreshStart:null,__zoomLevel:1,__scrollLeft:0,__scrollTop:0,__maxScrollLeft:0,__maxScrollTop:0,__scheduledLeft:0,__scheduledTop:0,__scheduledZoom:0,__lastTouchLeft:null,__lastTouchTop:null,__lastTouchMove:null,__positions:null,__minDecelerationScrollLeft:null,__minDecelerationScrollTop:null,__maxDecelerationScrollLeft:null,__maxDecelerationScrollTop:null,__decelerationVelocityX:null,__decelerationVelocityY:null,__transformProperty:null,__perspectiveProperty:null,__indicatorX:null,__indicatorY:null,__scrollbarFadeTimeout:null,__didWaitForSize:null,__sizerTimeout:null,__initEventHandlers:function(){function e(t){n.hintResize(),o(),n.scrollBy(t.wheelDeltaX/n.options.wheelDampen,-t.wheelDeltaY/n.options.wheelDampen),a()}var n=this,i=this.__container;if(i.addEventListener("scrollChildIntoView",function(e){if(n.isScrolledIntoView||((t.Platform.isIOS()||t.Platform.isFullScreen)&&(i.style.height=i.clientHeight-e.detail.keyboardHeight+"px",i.style.overflow="visible",n.resize()),n.isScrolledIntoView=!0),e.detail.isElementUnderKeyboard){var r;r=!t.Platform.isFullScreen&&e.detail.hasPlugin?350:80,t.scroll.isScrolling=!0,setTimeout(function(){var r=.5*i.clientHeight,o=e.detail.keyboardTopOffset+r;t.tap.cloneFocusedInput(i,n),n.scrollBy(0,o,!0),n.onScroll()},r)}e.stopPropagation()}),i.addEventListener("resetScrollView",function(){n.isScrolledIntoView=!1,i.style.height="",i.style.overflow="",n.resize(),t.scroll.isScrolling=!1}),n.touchStart=function(e){if(n.startCoordinates=T(e),!t.tap.ignoreScrollStart(e)){if(t.tap.containsOrIsTextInput(e.target))return void(n.__hasStarted=!1);n.__isSelectable=!0,n.__enableScrollY=!0,n.__hasStarted=!0,n.doTouchStart(e.touches,e.timeStamp),e.preventDefault()}},n.touchMove=function(e){if(!e.defaultPrevented){if(!n.__hasStarted&&t.tap.containsOrIsTextInput(e.target))return n.__hasStarted=!0,n.doTouchStart(e.touches,e.timeStamp),void e.preventDefault();if(n.startCoordinates){var r=T(e);n.__isSelectable&&t.tap.isTextInput(e.target)&&Math.abs(n.startCoordinates.x-r.x)>20&&(n.__enableScrollY=!1,n.__isSelectable=!0),n.__enableScrollY&&Math.abs(n.startCoordinates.y-r.y)>10&&(n.__isSelectable=!1,t.tap.cloneFocusedInput(i,n))}n.doTouchMove(e.touches,e.timeStamp,e.scale)}},n.touchEnd=function(e){n.doTouchEnd(e.timeStamp),n.__hasStarted=!1,n.__isSelectable=!0,n.__enableScrollY=!0,n.__isDragging||n.__isDecelerating||n.__isAnimating||t.tap.removeClonedInputs(i,n)},n.options.orgScrollingComplete=n.options.scrollingComplete,n.options.scrollingComplete=function(){t.tap.removeClonedInputs(i,n),n.options.orgScrollingComplete()},"ontouchstart"in window)i.addEventListener("touchstart",n.touchStart,!1),document.addEventListener("touchmove",n.touchMove,!1),document.addEventListener("touchend",n.touchEnd,!1),document.addEventListener("touchcancel",n.touchEnd,!1);else{var r=!1;i.addEventListener("mousedown",function(e){t.tap.ignoreScrollStart(e)||"SELECT"===e.target.tagName||(n.doTouchStart([{pageX:e.pageX,pageY:e.pageY}],e.timeStamp),e.preventDefault(),r=!0)},!1),document.addEventListener("mousemove",function(t){r&&!t.defaultPrevented&&(n.doTouchMove([{pageX:t.pageX,pageY:t.pageY}],t.timeStamp),r=!0)},!1),document.addEventListener("mouseup",function(t){r&&(n.doTouchEnd(t.timeStamp),r=!1)},!1);var o=t.debounce(function(){n.__fadeScrollbars("in")},500,!0),a=t.debounce(function(){n.__fadeScrollbars("out")},100,!1);document.addEventListener("mousewheel",e)}},__createScrollbar:function(t){var e=document.createElement("div"),n=document.createElement("div");return n.className="scroll-bar-indicator",e.className="h"==t?"scroll-bar scroll-bar-h":"scroll-bar scroll-bar-v",e.appendChild(n),e},__createScrollbars:function(){var t,e;this.options.scrollingX&&(t={el:this.__createScrollbar("h"),sizeRatio:1},t.indicator=t.el.children[0],this.options.scrollbarX&&this.__container.appendChild(t.el),this.__indicatorX=t),this.options.scrollingY&&(e={el:this.__createScrollbar("v"),sizeRatio:1},e.indicator=e.el.children[0],this.options.scrollbarY&&this.__container.appendChild(e.el),this.__indicatorY=e)},__resizeScrollbars:function(){var t=this;if(t.__indicatorX){var e=Math.max(Math.round(t.__clientWidth*t.__clientWidth/t.__contentWidth),20);e>t.__contentWidth&&(e=0),t.__indicatorX.size=e,t.__indicatorX.minScale=this.options.minScrollbarSizeX/e,t.__indicatorX.indicator.style.width=e+"px",t.__indicatorX.maxPos=t.__clientWidth-e,t.__indicatorX.sizeRatio=t.__maxScrollLeft?t.__indicatorX.maxPos/t.__maxScrollLeft:1}if(t.__indicatorY){var n=Math.max(Math.round(t.__clientHeight*t.__clientHeight/t.__contentHeight),20);n>t.__contentHeight&&(n=0),t.__indicatorY.size=n,t.__indicatorY.minScale=this.options.minScrollbarSizeY/n,t.__indicatorY.maxPos=t.__clientHeight-n,t.__indicatorY.indicator.style.height=n+"px",t.__indicatorY.sizeRatio=t.__maxScrollTop?t.__indicatorY.maxPos/t.__maxScrollTop:1}},__repositionScrollbars:function(){var t,e,n,i,r,o=this,a=0,s=0;o.__indicatorX&&(o.__indicatorY&&(a=10),i=Math.round(o.__indicatorX.sizeRatio*o.__scrollLeft)||0,e=o.__scrollLeft-(o.__maxScrollLeft-a),o.__scrollLeft<0?(widthScale=Math.max(o.__indicatorX.minScale,(o.__indicatorX.size-Math.abs(o.__scrollLeft))/o.__indicatorX.size),i=0,o.__indicatorX.indicator.style[o.__transformOriginProperty]="left center"):e>0?(widthScale=Math.max(o.__indicatorX.minScale,(o.__indicatorX.size-e)/o.__indicatorX.size),i=o.__indicatorX.maxPos-a,o.__indicatorX.indicator.style[o.__transformOriginProperty]="right center"):(i=Math.min(o.__maxScrollLeft,Math.max(0,i)),widthScale=1),o.__indicatorX.indicator.style[o.__transformProperty]="translate3d("+i+"px, 0, 0) scaleX("+widthScale+")"),o.__indicatorY&&(r=Math.round(o.__indicatorY.sizeRatio*o.__scrollTop)||0,o.__indicatorX&&(s=10),n=o.__scrollTop-(o.__maxScrollTop-s),o.__scrollTop<0?(t=Math.max(o.__indicatorY.minScale,(o.__indicatorY.size-Math.abs(o.__scrollTop))/o.__indicatorY.size),r=0,o.__indicatorY.indicator.style[o.__transformOriginProperty]="center top"):n>0?(t=Math.max(o.__indicatorY.minScale,(o.__indicatorY.size-n)/o.__indicatorY.size),r=o.__indicatorY.maxPos-s,o.__indicatorY.indicator.style[o.__transformOriginProperty]="center bottom"):(r=Math.min(o.__maxScrollTop,Math.max(0,r)),t=1),o.__indicatorY.indicator.style[o.__transformProperty]="translate3d(0,"+r+"px, 0) scaleY("+t+")")},__fadeScrollbars:function(t,e){var n=this;if(this.options.scrollbarsFade){var i="scroll-bar-fade-out";n.options.scrollbarsFade===!0&&(clearTimeout(n.__scrollbarFadeTimeout),"in"==t?(n.__indicatorX&&n.__indicatorX.indicator.classList.remove(i),n.__indicatorY&&n.__indicatorY.indicator.classList.remove(i)):n.__scrollbarFadeTimeout=setTimeout(function(){n.__indicatorX&&n.__indicatorX.indicator.classList.add(i),n.__indicatorY&&n.__indicatorY.indicator.classList.add(i)},e||n.options.scrollbarFadeDelay))}},__scrollingComplete:function(){var t=this;t.options.scrollingComplete(),t.__fadeScrollbars("out")},resize:function(){this.setDimensions(this.__container.clientWidth,this.__container.clientHeight,this.options.getContentWidth(),this.options.getContentHeight())},getRenderFn:function(){var t,e=this,n=this.__content,i=document.documentElement.style;"MozAppearance"in i?t="gecko":"WebkitAppearance"in i?t="webkit":"string"==typeof navigator.cpuClass&&(t="trident");var r,o={trident:"ms",gecko:"Moz",webkit:"Webkit",presto:"O"}[t],a=document.createElement("div"),s=o+"Perspective",c=o+"Transform",l=o+"TransformOrigin";return e.__perspectiveProperty=c,e.__transformProperty=c,e.__transformOriginProperty=l,a.style[s]!==r?function(t,i,r,o){n.style[c]="translate3d("+-t+"px,"+-i+"px,0) scale("+r+")",e.__repositionScrollbars(),o||e.triggerScrollEvent()}:a.style[c]!==r?function(t,i,r,o){n.style[c]="translate("+-t+"px,"+-i+"px) scale("+r+")",e.__repositionScrollbars(),o||e.triggerScrollEvent()}:function(t,i,r,o){n.style.marginLeft=t?-t/r+"px":"",n.style.marginTop=i?-i/r+"px":"",n.style.zoom=r||"",e.__repositionScrollbars(),o||e.triggerScrollEvent()}},setDimensions:function(t,e,n,i){var r=this;t===+t&&(r.__clientWidth=t),e===+e&&(r.__clientHeight=e),n===+n&&(r.__contentWidth=n),i===+i&&(r.__contentHeight=i),r.__computeScrollMax(),r.__resizeScrollbars(),r.scrollTo(r.__scrollLeft,r.__scrollTop,!0,null,!0)},setPosition:function(t,e){var n=this;n.__clientLeft=t||0,n.__clientTop=e||0},setSnapSize:function(t,e){var n=this;n.__snapWidth=t,n.__snapHeight=e},activatePullToRefresh:function(t,e,n,i){var r=this;r.__refreshHeight=t,r.__refreshActivate=e,r.__refreshDeactivate=n,r.__refreshStart=i},triggerPullToRefresh:function(){this.__publish(this.__scrollLeft,-this.__refreshHeight,this.__zoomLevel,!0),this.__refreshStart&&this.__refreshStart()},finishPullToRefresh:function(){var t=this;t.__refreshActive=!1,t.__refreshDeactivate&&t.__refreshDeactivate(),t.scrollTo(t.__scrollLeft,t.__scrollTop,!0)},getValues:function(){var t=this;return{left:t.__scrollLeft,top:t.__scrollTop,zoom:t.__zoomLevel}},getScrollMax:function(){var t=this;return{left:t.__maxScrollLeft,top:t.__maxScrollTop}},zoomTo:function(t,e,n,i){var r=this;if(!r.options.zooming)throw new Error("Zooming is not enabled!");r.__isDecelerating&&(ie.effect.Animate.stop(r.__isDecelerating),r.__isDecelerating=!1);var o=r.__zoomLevel;null==n&&(n=r.__clientWidth/2),null==i&&(i=r.__clientHeight/2),t=Math.max(Math.min(t,r.options.maxZoom),r.options.minZoom),r.__computeScrollMax(t);var a=(n+r.__scrollLeft)*t/o-n,s=(i+r.__scrollTop)*t/o-i;a>r.__maxScrollLeft?a=r.__maxScrollLeft:0>a&&(a=0),s>r.__maxScrollTop?s=r.__maxScrollTop:0>s&&(s=0),r.__publish(a,s,t,e)},zoomBy:function(t,e,n,i){var r=this;r.zoomTo(r.__zoomLevel*t,e,n,i)},scrollTo:function(t,e,n,i,r){var o=this;if(o.__isDecelerating&&(ie.effect.Animate.stop(o.__isDecelerating),o.__isDecelerating=!1),null!=i&&i!==o.__zoomLevel){if(!o.options.zooming)throw new Error("Zooming is not enabled!");t*=i,e*=i,o.__computeScrollMax(i)}else i=o.__zoomLevel;o.options.scrollingX?o.options.paging?t=Math.round(t/o.__clientWidth)*o.__clientWidth:o.options.snapping&&(t=Math.round(t/o.__snapWidth)*o.__snapWidth):t=o.__scrollLeft,o.options.scrollingY?o.options.paging?e=Math.round(e/o.__clientHeight)*o.__clientHeight:o.options.snapping&&(e=Math.round(e/o.__snapHeight)*o.__snapHeight):e=o.__scrollTop,t=Math.max(Math.min(o.__maxScrollLeft,t),0),e=Math.max(Math.min(o.__maxScrollTop,e),0),t===o.__scrollLeft&&e===o.__scrollTop&&(n=!1),o.__publish(t,e,i,n,r)},scrollBy:function(t,e,n){var i=this,r=i.__isAnimating?i.__scheduledLeft:i.__scrollLeft,o=i.__isAnimating?i.__scheduledTop:i.__scrollTop;i.scrollTo(r+(t||0),o+(e||0),n)},doMouseZoom:function(t,e,n,i){var r=this,o=t>0?.97:1.03;return r.zoomTo(r.__zoomLevel*o,!1,n-r.__clientLeft,i-r.__clientTop)},doTouchStart:function(t,e){if(this.hintResize(),null==t.length)throw new Error("Invalid touch list: "+t);if(e instanceof Date&&(e=e.valueOf()),"number"!=typeof e)throw new Error("Invalid timestamp value: "+e);var n=this;n.__interruptedAnimation=!0,n.__isDecelerating&&(ie.effect.Animate.stop(n.__isDecelerating),n.__isDecelerating=!1,n.__interruptedAnimation=!0),n.__isAnimating&&(ie.effect.Animate.stop(n.__isAnimating),n.__isAnimating=!1,n.__interruptedAnimation=!0);var i,r,o=1===t.length;o?(i=t[0].pageX,r=t[0].pageY):(i=Math.abs(t[0].pageX+t[1].pageX)/2,r=Math.abs(t[0].pageY+t[1].pageY)/2),n.__initialTouchLeft=i,n.__initialTouchTop=r,n.__zoomLevelStart=n.__zoomLevel,n.__lastTouchLeft=i,n.__lastTouchTop=r,n.__lastTouchMove=e,n.__lastScale=1,n.__enableScrollX=!o&&n.options.scrollingX,n.__enableScrollY=!o&&n.options.scrollingY,n.__isTracking=!0,n.__didDecelerationComplete=!1,n.__isDragging=!o,n.__isSingleTouch=o,n.__positions=[]},doTouchMove:function(t,e,n){if(null==t.length)throw new Error("Invalid touch list: "+t);if(e instanceof Date&&(e=e.valueOf()),"number"!=typeof e)throw new Error("Invalid timestamp value: "+e);var i=this;if(i.__isTracking){var r,o;2===t.length?(r=Math.abs(t[0].pageX+t[1].pageX)/2,o=Math.abs(t[0].pageY+t[1].pageY)/2):(r=t[0].pageX,o=t[0].pageY);var a=i.__positions;if(i.__isDragging){var s=r-i.__lastTouchLeft,c=o-i.__lastTouchTop,l=i.__scrollLeft,u=i.__scrollTop,h=i.__zoomLevel;if(null!=n&&i.options.zooming){var d=h;if(h=h/i.__lastScale*n,h=Math.max(Math.min(h,i.options.maxZoom),i.options.minZoom),d!==h){var f=r-i.__clientLeft,_=o-i.__clientTop;l=(f+l)*h/d-f,u=(_+u)*h/d-_,i.__computeScrollMax(h)}}if(i.__enableScrollX){l-=s*this.options.speedMultiplier;var p=i.__maxScrollLeft;(l>p||0>l)&&(i.options.bouncing?l+=s/2*this.options.speedMultiplier:l=l>p?p:0)}if(i.__enableScrollY){u-=c*this.options.speedMultiplier;var g=i.__maxScrollTop;(u>g||0>u)&&(i.options.bouncing||i.__refreshHeight&&0>u?(u+=c/2*this.options.speedMultiplier,i.__enableScrollX||null==i.__refreshHeight||(!i.__refreshActive&&u<=-i.__refreshHeight?(i.__refreshActive=!0,i.__refreshActivate&&i.__refreshActivate()):i.__refreshActive&&u>-i.__refreshHeight&&(i.__refreshActive=!1,i.__refreshDeactivate&&i.__refreshDeactivate()))):u=u>g?g:0)}a.length>60&&a.splice(0,30),a.push(l,u,e),i.__publish(l,u,h)}else{var m=i.options.locking?3:0,v=5,T=Math.abs(r-i.__initialTouchLeft),E=Math.abs(o-i.__initialTouchTop);i.__enableScrollX=i.options.scrollingX&&T>=m,i.__enableScrollY=i.options.scrollingY&&E>=m,a.push(i.__scrollLeft,i.__scrollTop,e),i.__isDragging=(i.__enableScrollX||i.__enableScrollY)&&(T>=v||E>=v),i.__isDragging&&(i.__interruptedAnimation=!1,i.__fadeScrollbars("in"))}i.__lastTouchLeft=r,i.__lastTouchTop=o,i.__lastTouchMove=e,i.__lastScale=n}},doTouchEnd:function(t){if(t instanceof Date&&(t=t.valueOf()),"number"!=typeof t)throw new Error("Invalid timestamp value: "+t);var e=this;if(e.__isTracking){if(e.__isTracking=!1,e.__isDragging)if(e.__isDragging=!1,e.__isSingleTouch&&e.options.animating&&t-e.__lastTouchMove<=100){for(var n=e.__positions,i=n.length-1,r=i,o=i;o>0&&n[o]>e.__lastTouchMove-100;o-=3)r=o;if(r!==i){var a=n[i]-n[r],s=e.__scrollLeft-n[r-2],c=e.__scrollTop-n[r-1];e.__decelerationVelocityX=s/a*(1e3/60),e.__decelerationVelocityY=c/a*(1e3/60);var l=e.options.paging||e.options.snapping?4:1;(Math.abs(e.__decelerationVelocityX)>l||Math.abs(e.__decelerationVelocityY)>l)&&(e.__refreshActive||e.__startDeceleration(t))}else e.__scrollingComplete()}else t-e.__lastTouchMove>100&&e.__scrollingComplete();e.__isDecelerating||(e.__refreshActive&&e.__refreshStart?(e.__publish(e.__scrollLeft,-e.__refreshHeight,e.__zoomLevel,!0),e.__refreshStart&&e.__refreshStart()):((e.__interruptedAnimation||e.__isDragging)&&e.__scrollingComplete(),e.scrollTo(e.__scrollLeft,e.__scrollTop,!0,e.__zoomLevel),e.__refreshActive&&(e.__refreshActive=!1,e.__refreshDeactivate&&e.__refreshDeactivate()))),e.__positions.length=0}},__publish:function(t,e,r,o,a){var s=this,c=s.__isAnimating;if(c&&(ie.effect.Animate.stop(c),s.__isAnimating=!1),o&&s.options.animating){s.__scheduledLeft=t,s.__scheduledTop=e,s.__scheduledZoom=r;var l=s.__scrollLeft,u=s.__scrollTop,h=s.__zoomLevel,d=t-l,f=e-u,_=r-h,p=function(t,e,n){n&&(s.__scrollLeft=l+d*t,s.__scrollTop=u+f*t,s.__zoomLevel=h+_*t,s.__callback&&s.__callback(s.__scrollLeft,s.__scrollTop,s.__zoomLevel,a))},g=function(t){return s.__isAnimating===t},m=function(t,e,n){e===s.__isAnimating&&(s.__isAnimating=!1),(s.__didDecelerationComplete||n)&&s.__scrollingComplete(),s.options.zooming&&s.__computeScrollMax()};s.__isAnimating=ie.effect.Animate.start(p,g,m,s.options.animationDuration,c?n:i)}else s.__scheduledLeft=s.__scrollLeft=t,s.__scheduledTop=s.__scrollTop=e,s.__scheduledZoom=s.__zoomLevel=r,s.__callback&&s.__callback(t,e,r,a),s.options.zooming&&s.__computeScrollMax()},__computeScrollMax:function(t){var e=this;null==t&&(t=e.__zoomLevel),e.__maxScrollLeft=Math.max(e.__contentWidth*t-e.__clientWidth,0),e.__maxScrollTop=Math.max(e.__contentHeight*t-e.__clientHeight,0),e.__didWaitForSize||0!=e.__maxScrollLeft||0!=e.__maxScrollTop||(e.__didWaitForSize=!0,e.__waitForSize())},__waitForSize:function(){var t=this;clearTimeout(t.__sizerTimeout);var e=function(){t.resize(),t.options.scrollingX&&0==t.__maxScrollLeft||t.options.scrollingY&&0==t.__maxScrollTop};e(),t.__sizerTimeout=setTimeout(e,1e3)},__startDeceleration:function(){var t=this;if(t.options.paging){var e=Math.max(Math.min(t.__scrollLeft,t.__maxScrollLeft),0),n=Math.max(Math.min(t.__scrollTop,t.__maxScrollTop),0),i=t.__clientWidth,r=t.__clientHeight;t.__minDecelerationScrollLeft=Math.floor(e/i)*i,t.__minDecelerationScrollTop=Math.floor(n/r)*r,t.__maxDecelerationScrollLeft=Math.ceil(e/i)*i,t.__maxDecelerationScrollTop=Math.ceil(n/r)*r}else t.__minDecelerationScrollLeft=0,t.__minDecelerationScrollTop=0,t.__maxDecelerationScrollLeft=t.__maxScrollLeft,t.__maxDecelerationScrollTop=t.__maxScrollTop;var o=function(e,n,i){t.__stepThroughDeceleration(i)};t.__minVelocityToKeepDecelerating=t.options.snapping?4:.1;var a=function(){var e=Math.abs(t.__decelerationVelocityX)>=t.__minVelocityToKeepDecelerating||Math.abs(t.__decelerationVelocityY)>=t.__minVelocityToKeepDecelerating;return e||(t.__didDecelerationComplete=!0),e},s=function(){t.__isDecelerating=!1,t.__didDecelerationComplete&&t.__scrollingComplete(),t.options.paging&&t.scrollTo(t.__scrollLeft,t.__scrollTop,t.options.snapping)};t.__isDecelerating=ie.effect.Animate.start(o,a,s)},__stepThroughDeceleration:function(t){var e=this,n=e.__scrollLeft+e.__decelerationVelocityX,i=e.__scrollTop+e.__decelerationVelocityY;if(!e.options.bouncing){var r=Math.max(Math.min(e.__maxDecelerationScrollLeft,n),e.__minDecelerationScrollLeft);r!==n&&(n=r,e.__decelerationVelocityX=0);var o=Math.max(Math.min(e.__maxDecelerationScrollTop,i),e.__minDecelerationScrollTop);o!==i&&(i=o,e.__decelerationVelocityY=0)}if(t?e.__publish(n,i,e.__zoomLevel):(e.__scrollLeft=n,e.__scrollTop=i),!e.options.paging){var a=.95;e.__decelerationVelocityX*=a,e.__decelerationVelocityY*=a}if(e.options.bouncing){var s=0,c=0,l=e.options.penetrationDeceleration,u=e.options.penetrationAcceleration;if(ne.__maxDecelerationScrollLeft&&(s=e.__maxDecelerationScrollLeft-n),ie.__maxDecelerationScrollTop&&(c=e.__maxDecelerationScrollTop-i),0!==s){var h=s*e.__decelerationVelocityX<=e.__minDecelerationScrollLeft;h&&(e.__decelerationVelocityX+=s*l);var d=Math.abs(e.__decelerationVelocityX)<=e.__minVelocityToKeepDecelerating;(!h||d)&&(e.__decelerationVelocityX=s*u)}if(0!==c){var f=c*e.__decelerationVelocityY<=e.__minDecelerationScrollTop;f&&(e.__decelerationVelocityY+=c*l);var _=Math.abs(e.__decelerationVelocityY)<=e.__minVelocityToKeepDecelerating;(!f||_)&&(e.__decelerationVelocityY=c*u)}}}}),t.scroll={isScrolling:!1,lastTop:0}}(ionic),function(t){"use strict";t.views.ActionSheet=t.views.View.inherit({initialize:function(t){this.el=t.el},show:function(){this.el.offsetWidth,this.el.classList.add("active")},hide:function(){this.el.offsetWidth,this.el.classList.remove("active")}})}(ionic),function(t){"use strict";t.views.HeaderBar=t.views.View.inherit({initialize:function(e){this.el=e.el,t.extend(this,{alignTitle:"center"},e),this.align()},align:function(e){e||(e=this.alignTitle);var n=this.el.querySelector(".title");if(n){var i=this;t.requestAnimationFrame(function(){var r,o,a,s=i.el.childNodes,c=0,l=0,u=!1;for(r=0;r10&&(n.style.left=h+"px",n.style.right=h+"px"),n.offsetWidth0&&(n.style.right=l+5+"px")):"left"==e?(n.classList.add("title-left"),c>0&&(n.style.left=c+15+"px")):"right"==e&&(n.classList.add("title-right"),l>0&&(n.style.right=l+15+"px"))})}}})}(ionic),function(t){"use strict";var e="item",n="item-content",i="item-sliding",r="item-options",o="item-placeholder",a="item-reordering",s="item-reorder",c=function(){};c.prototype={start:function(){},drag:function(){},end:function(){},isSameItem:function(){return!1}};var l=function(t){this.dragThresholdX=t.dragThresholdX||10,this.el=t.el,this.canSwipe=t.canSwipe};l.prototype=new c,l.prototype.start=function(o){var a,s,c,l;this.canSwipe()&&(a=o.target.classList.contains(n)?o.target:o.target.classList.contains(e)?o.target.querySelector("."+n):t.DomUtil.getParentWithClass(o.target,n),a&&(a.classList.remove(i),c=parseFloat(a.style[t.CSS.TRANSFORM].replace("translate3d(","").split(",")[0])||0,s=a.parentNode.querySelector("."+r),s&&(s.classList.remove("invisible"),l=s.offsetWidth,this._currentDrag={buttons:s,buttonsWidth:l,content:a,startOffsetX:c})))},l.prototype.isSameItem=function(t){return t._lastDrag&&this._currentDrag?this._currentDrag.content==t._lastDrag.content:!1},l.prototype.clean=function(){var e=this._lastDrag;e&&t.requestAnimationFrame(function(){e.content.style[t.CSS.TRANSITION]="",e.content.style[t.CSS.TRANSFORM]="",setTimeout(function(){e.buttons&&e.buttons.classList.add("invisible")},250)})},l.prototype.drag=t.animationFrameThrottle(function(e){var n;if(this._currentDrag&&(!this._isDragging&&(Math.abs(e.gesture.deltaX)>this.dragThresholdX||Math.abs(this._currentDrag.startOffsetX)>0)&&(this._isDragging=!0),this._isDragging)){n=this._currentDrag.buttonsWidth;var i=Math.min(0,this._currentDrag.startOffsetX+e.gesture.deltaX);-n>i&&(i=Math.min(-n,-n+.4*(e.gesture.deltaX+n))),this._currentDrag.content.style[t.CSS.TRANSFORM]="translate3d("+i+"px, 0, 0)",this._currentDrag.content.style[t.CSS.TRANSITION]="none"}}),l.prototype.end=function(e,n){var i=this;if(!this._currentDrag)return void(n&&n());var r=-this._currentDrag.buttonsWidth;e.gesture.deltaX>-(this._currentDrag.buttonsWidth/2)&&("left"==e.gesture.direction&&Math.abs(e.gesture.velocityX)<.3?r=0:"right"==e.gesture.direction&&(r=0)),t.requestAnimationFrame(function(){if(0===r){i._currentDrag.content.style[t.CSS.TRANSFORM]="";var e=i._currentDrag.buttons;setTimeout(function(){e&&e.classList.add("invisible")},250)}else i._currentDrag.content.style[t.CSS.TRANSFORM]="translate3d("+r+"px, 0, 0)";i._currentDrag.content.style[t.CSS.TRANSITION]="",i._lastDrag=i._currentDrag,i._currentDrag=null,n&&n()})};var u=function(t){this.dragThresholdY=t.dragThresholdY||0,this.onReorder=t.onReorder,this.listEl=t.listEl,this.el=t.el,this.scrollEl=t.scrollEl,this.scrollView=t.scrollView};u.prototype=new c,u.prototype._moveElement=function(e){var n=e.gesture.center.pageY-this._currentDrag.elementHeight+this.scrollView.getValues().top-this.listEl.offsetTop;this.el.style[t.CSS.TRANSFORM]="translate3d(0, "+n+"px, 0)"},u.prototype.start=function(e){var n=t.DomUtil.getChildIndex(this.el,this.el.nodeName.toLowerCase()),i=this.el.scrollHeight,r=this.el.cloneNode(!0);r.classList.add(o),this.el.parentNode.insertBefore(r,this.el),this.el.classList.add(a),this._currentDrag={elementHeight:i,startIndex:n,placeholder:r,scrollHeight:scroll,list:r.parentNode},this._moveElement(e)},u.prototype.drag=t.animationFrameThrottle(function(t){if(this._currentDrag){var e=0,n=t.gesture.center.pageY;if(this.scrollView){var i=this.scrollEl;e=this.scrollView.getValues().top;var r=i.offsetTop,o=r-n+this._currentDrag.elementHeight/2,a=n+this._currentDrag.elementHeight/2-r-i.offsetHeight;t.gesture.deltaY<0&&o>0&&e>0&&this.scrollView.scrollBy(null,-o),t.gesture.deltaY>0&&a>0&&ethis.dragThresholdY&&(this._isDragging=!0),this._isDragging&&(this._moveElement(t),this._currentDrag.currentY=e+n-this._currentDrag.placeholder.parentNode.offsetTop,this._reorderItems())}}),u.prototype._reorderItems=function(){var e=this,n=(this._currentDrag.placeholder,Array.prototype.slice.call(this._currentDrag.placeholder.parentNode.children).filter(function(t){return t!==e.el})),i=n.indexOf(this._currentDrag.placeholder),r=n[Math.max(0,i-1)],o=n[Math.min(n.length,i+1)],a=this._currentDrag.currentY;return r&&ao.offsetTop+o.offsetHeight/2?(t.DomUtil.swapNodes(o,this._currentDrag.placeholder),i+1):void 0},u.prototype.end=function(e,n){if(!this._currentDrag)return void(n&&n());var i=this._currentDrag.placeholder,r=t.DomUtil.getChildIndex(i,i.nodeName.toLowerCase());this.el.classList.remove(a),this.el.style[t.CSS.TRANSFORM]="",i.parentNode.insertBefore(this.el,i),i.parentNode.removeChild(i),this.onReorder&&this.onReorder(this.el,this._currentDrag.startIndex,r),this._currentDrag=null,n&&n()},t.views.ListView=t.views.View.inherit({initialize:function(e){var n=this;e=t.extend({onReorder:function(){},virtualRemoveThreshold:-200,virtualAddThreshold:200,canSwipe:function(){return!0}},e),t.extend(this,e),!this.itemHeight&&this.listEl&&(this.itemHeight=this.listEl.children[0]&&parseInt(this.listEl.children[0].style.height,10)),this.onRefresh=e.onRefresh||function(){},this.onRefreshOpening=e.onRefreshOpening||function(){},this.onRefreshHolding=e.onRefreshHolding||function(){},window.ionic.onGesture("release",function(t){n._handleEndDrag(t)},this.el),window.ionic.onGesture("drag",function(t){n._handleDrag(t)},this.el),this._initDrag()},stopRefreshing:function(){var t=this.el.querySelector(".list-refresher");t.style.height="0px"},didScroll:function(t){if(this.isVirtual){var e=this.itemHeight,n=(this.listEl.children.length,t.target.scrollHeight),i=this.el.parentNode.offsetHeight,r=(t.scrollTop,Math.max(0,t.scrollTop+this.virtualRemoveThreshold)),o=Math.min(n,Math.abs(t.scrollTop)+i+this.virtualAddThreshold),a=Math.floor((o-r)/e),s=parseInt(Math.abs(r/e),10),c=parseInt(Math.abs(o/e),10);this._virtualItemsToRemove=Array.prototype.slice.call(this.listEl.children,0,s);{Array.prototype.slice.call(this.listEl.children,s,s+a)}this.renderViewport&&this.renderViewport(r,o,s,c)}},didStopScrolling:function(){if(this.isVirtual)for(var t=0;t5){var r=this._getItem(e.target);r&&r.querySelector(".item-options")&&(this._dragOp=new l({el:this.el,canSwipe:this.canSwipe}),this._dragOp.start(e),e.preventDefault())}}else{var r=this._getItem(e.target);r&&(this._dragOp=new u({listEl:this.el,el:r,scrollEl:this.scrollEl,scrollView:this.scrollView,onReorder:function(t,e,i){n.onReorder&&n.onReorder(t,e,i)}}),this._dragOp.start(e),e.preventDefault())}i&&this._dragOp&&!this._dragOp.isSameItem(i)&&e.defaultPrevented&&i.clean&&i.clean()},_handleEndDrag:function(t){var e=this;this._didDragUpOrDown=!1,this._dragOp&&this._dragOp.end(t,function(){e._initDrag()})},_handleDrag:function(t){Math.abs(t.gesture.deltaY)>5&&(this._didDragUpOrDown=!0),this.isDragging||this._dragOp||this._startDrag(t),this._dragOp&&(t.gesture.srcEvent.preventDefault(),this._dragOp.drag(t))}})}(ionic),function(t){"use strict";t.views.Modal=t.views.View.inherit({initialize:function(e){e=t.extend({focusFirstInput:!1,unfocusOnHide:!0,focusFirstDelay:600},e),t.extend(this,e),this.el=e.el},show:function(){var t=this;t.focusFirstInput&&window.setTimeout(function(){var e=t.el.querySelector("input, textarea");e&&e.focus&&e.focus()},t.focusFirstDelay)},hide:function(){if(this.unfocusOnHide){var t=this.el.querySelectorAll("input, textarea");window.setTimeout(function(){for(var e=0;ee?-v:e>w?v:0,0))}t.continuous&&_.transitions&&(a(r(w-1),-v,0),a(r(w+1),v,0)),_.transitions||(E.style.left=w*-v+"px"),p.style.visibility="visible",t.slidesChanged&&t.slidesChanged()}function n(){t.continuous?o(w-1):w&&o(w-1)}function i(){t.continuous?o(w+1):ww?e:w)-s-1),v*i,0);e=r(e),a(w,v*i,n||y),a(e,0,n||y),t.continuous&&a(r(e-i),-(v*i),0)}else e=r(e),c(w*-v,e*-v,n||y);w=e,f(t.callback&&t.callback(w,g[w]))}}function a(t,e,n){s(t,e,n),m[t]=e}function s(t,e,n){var i=g[t],r=i&&i.style;r&&(r.webkitTransitionDuration=r.MozTransitionDuration=r.msTransitionDuration=r.OTransitionDuration=r.transitionDuration=n+"ms",r.webkitTransform="translate("+e+"px,0)translateZ(0)",r.msTransform=r.MozTransform=r.OTransform="translateX("+e+"px)")}function c(e,n,i){if(!i)return void(E.style.left=n+"px");var r=+new Date,o=setInterval(function(){var a=+new Date-r;return a>i?(E.style.left=n+"px",M&&l(),t.transitionEnd&&t.transitionEnd.call(event,w,g[w]),void clearInterval(o)):void(E.style.left=(n-e)*(Math.floor(a/i*100)/100)+e+"px")},4)}function l(){S=setTimeout(i,M)}function u(){M=t.auto||0,clearTimeout(S)}var h=this,d=function(){},f=function(t){setTimeout(t||d,0)},_={addEventListener:!!window.addEventListener,touch:"ontouchstart"in window||window.DocumentTouch&&document instanceof DocumentTouch,transitions:function(t){var e=["transitionProperty","WebkitTransition","MozTransition","OTransition","msTransition"];for(var n in e)if(void 0!==t.style[e[n]])return!0;return!1}(document.createElement("swipe"))},p=t.el;if(p){var g,m,v,T,E=p.children[0];t=t||{};var w=parseInt(t.startSlide,10)||0,y=t.speed||300;t.continuous=void 0!==t.continuous?t.continuous:!0;var S,b,M=t.auto||0,D={},x={},L={handleEvent:function(n){switch(("mousedown"==n.type||"mouseup"==n.type||"mousemove"==n.type)&&(n.touches=[{pageX:n.pageX,pageY:n.pageY}]),n.type){case"mousedown":this.start(n);break;case"touchstart":this.start(n);break;case"touchmove":this.touchmove(n);break;case"mousemove":this.touchmove(n);break;case"touchend":f(this.end(n));break;case"mouseup":f(this.end(n));break;case"webkitTransitionEnd":case"msTransitionEnd":case"oTransitionEnd":case"otransitionend":case"transitionend":f(this.transitionEnd(n));break;case"resize":f(e)}t.stopPropagation&&n.stopPropagation()},start:function(t){var e=t.touches[0];D={x:e.pageX,y:e.pageY,time:+new Date},b=void 0,x={},_.touch?(E.addEventListener("touchmove",this,!1),E.addEventListener("touchend",this,!1)):(E.addEventListener("mousemove",this,!1),E.addEventListener("mouseup",this,!1),document.addEventListener("mouseup",this,!1))},touchmove:function(e){if(!(e.touches.length>1||e.scale&&1!==e.scale||h.slideIsDisabled)){t.disableScroll&&e.preventDefault();var n=e.touches[0];x={x:n.pageX-D.x,y:n.pageY-D.y},"undefined"==typeof b&&(b=!!(b||Math.abs(x.x)0||w==g.length-1&&x.x<0?Math.abs(x.x)/v+1:1),s(w-1,x.x+m[w-1],0),s(w,x.x+m[w],0),s(w+1,x.x+m[w+1],0)))}},end:function(){var e=+new Date-D.time,n=Number(e)<250&&Math.abs(x.x)>20||Math.abs(x.x)>v/2,i=!w&&x.x>0||w==g.length-1&&x.x<0;t.continuous&&(i=!1);var o=x.x<0;b||(n&&!i?(o?(t.continuous?(a(r(w-1),-v,0),a(r(w+2),v,0)):a(w-1,-v,0),a(w,m[w]-v,y),a(r(w+1),m[r(w+1)]-v,y),w=r(w+1)):(t.continuous?(a(r(w+1),v,0),a(r(w-2),-v,0)):a(w+1,v,0),a(w,m[w]+v,y),a(r(w-1),m[r(w-1)]+v,y),w=r(w-1)),t.callback&&t.callback(w,g[w])):t.continuous?(a(r(w-1),-v,y),a(w,0,y),a(r(w+1),v,y)):(a(w-1,-v,y),a(w,0,y),a(w+1,v,y))),_.touch?(E.removeEventListener("touchmove",L,!1),E.removeEventListener("touchend",L,!1)):(E.removeEventListener("mousemove",L,!1),E.removeEventListener("mouseup",L,!1),document.removeEventListener("mouseup",L,!1))},transitionEnd:function(e){parseInt(e.target.getAttribute("data-index"),10)==w&&(M&&l(),t.transitionEnd&&t.transitionEnd.call(e,w,g[w]))}};this.update=function(){setTimeout(e)},this.setup=function(){e()},this.enableSlide=function(t){return arguments.length&&(this.slideIsDisabled=!t),!this.slideIsDisabled},this.slide=function(t,e){u(),o(t,e)},this.prev=this.previous=function(){u(),n()},this.next=function(){u(),i()},this.stop=function(){u()},this.currentIndex=function(){return w},this.slidesCount=function(){return T},this.kill=function(){u(),E.style.width="",E.style.left="";for(var t=g.length;t--;){var e=g[t];e.style.width="",e.style.left="",_.transitions&&s(t,0,0)}_.addEventListener?(E.removeEventListener("touchstart",L,!1),E.removeEventListener("webkitTransitionEnd",L,!1),E.removeEventListener("msTransitionEnd",L,!1),E.removeEventListener("oTransitionEnd",L,!1),E.removeEventListener("otransitionend",L,!1),E.removeEventListener("transitionend",L,!1),window.removeEventListener("resize",L,!1)):window.onresize=null},this.load=function(){e(),M&&l(),_.addEventListener?(_.touch?E.addEventListener("touchstart",L,!1):E.addEventListener("mousedown",L,!1),_.transitions&&(E.addEventListener("webkitTransitionEnd",L,!1),E.addEventListener("msTransitionEnd",L,!1),E.addEventListener("oTransitionEnd",L,!1),E.addEventListener("otransitionend",L,!1),E.addEventListener("transitionend",L,!1)),window.addEventListener("resize",L,!1)):window.onresize=function(){e()}}}}})}(ionic),function(t){"use strict";t.views.Toggle=t.views.View.inherit({initialize:function(e){var n=this;this.el=e.el,this.checkbox=e.checkbox,this.track=e.track,this.handle=e.handle,this.openPercent=-1,this.onChange=e.onChange||function(){},this.triggerThreshold=e.triggerThreshold||20,this.dragStartHandler=function(t){n.dragStart(t)},this.dragHandler=function(t){n.drag(t)},this.holdHandler=function(t){n.hold(t)},this.releaseHandler=function(t){n.release(t)},this.dragStartGesture=t.onGesture("dragstart",this.dragStartHandler,this.el),this.dragGesture=t.onGesture("drag",this.dragHandler,this.el),this.dragHoldGesture=t.onGesture("hold",this.holdHandler,this.el),this.dragReleaseGesture=t.onGesture("release",this.releaseHandler,this.el)},destroy:function(){t.offGesture(this.dragStartGesture,"dragstart",this.dragStartGesture),t.offGesture(this.dragGesture,"drag",this.dragGesture),t.offGesture(this.dragHoldGesture,"hold",this.holdHandler),t.offGesture(this.dragReleaseGesture,"release",this.releaseHandler)},tap:function(){"disabled"!==this.el.getAttribute("disabled")&&this.val(!this.checkbox.checked)},dragStart:function(t){this.checkbox.disabled||(this._dragInfo={width:this.el.offsetWidth,left:this.el.offsetLeft,right:this.el.offsetLeft+this.el.offsetWidth,triggerX:this.el.offsetWidth/2,initialState:this.checkbox.checked},t.gesture.srcEvent.preventDefault(),this.hold(t))},drag:function(e){var n=this;this._dragInfo&&(e.gesture.srcEvent.preventDefault(),t.requestAnimationFrame(function(){var t=(n.track.offsetLeft+n.handle.offsetWidth/2,n.track.offsetLeft+n.track.offsetWidth-n.handle.offsetWidth/2,e.gesture.deltaX,e.gesture.touches[0].pageX-n._dragInfo.left),i=n._dragInfo.width-n.triggerThreshold;n._dragInfo.initialState?tn._dragInfo.triggerX&&n.setOpenPercent(100):ti&&n.setOpenPercent(100)}))},endDrag:function(){this._dragInfo=null},hold:function(){this.el.classList.add("dragging")},release:function(t){this.el.classList.remove("dragging"),this.endDrag(t)},setOpenPercent:function(e){if(this.openPercent<0||ethis.openPercent+3)if(this.openPercent=e,0===e)this.val(!1);else if(100===e)this.val(!0);else{var n=Math.round(e/100*this.track.offsetWidth-this.handle.offsetWidth);n=1>n?0:n,this.handle.style[t.CSS.TRANSFORM]="translate3d("+n+"px,0,0)"}},val:function(e){return(e===!0||e===!1)&&(""!==this.handle.style[t.CSS.TRANSFORM]&&(this.handle.style[t.CSS.TRANSFORM]=""),this.checkbox.checked=e,this.openPercent=e?100:0,this.onChange&&this.onChange()),this.checkbox.checked}})}(ionic),function(t){"use strict";t.controllers.ViewController=function(){this.initialize.apply(this,arguments)},t.controllers.ViewController.inherit=t.inherit,t.extend(t.controllers.ViewController.prototype,{initialize:function(){},destroy:function(){}})}(window.ionic),function(t){"use strict";t.controllers.SideMenuController=t.controllers.ViewController.inherit({initialize:function(t){var e=this;this.left=t.left,this.right=t.right,this.content=t.content,this.dragThresholdX=t.dragThresholdX||10,this._rightShowing=!1,this._leftShowing=!1,this._isDragging=!1,this.content&&(this.content.onDrag=function(t){e._handleDrag(t)},this.content.onEndDrag=function(t){e._endDrag(t)})},setContent:function(t){var e=this;this.content=t,this.content.onDrag=function(t){e._handleDrag(t)},this.content.endDrag=function(t){e._endDrag(t)}},isOpenLeft:function(){return this.getOpenAmount()>0},isOpenRight:function(){return this.getOpenAmount()<0},toggleLeft:function(t){var e=this.getOpenAmount();0===arguments.length&&(t=0>=e),this.content.enableAnimation(),this.openPercentage(t?100:0)},toggleRight:function(t){var e=this.getOpenAmount();0===arguments.length&&(t=e>=0),this.content.enableAnimation(),this.openPercentage(t?-100:0)},close:function(){this.openPercentage(0)},getOpenAmount:function(){return this.content&&this.content.getTranslateX()||0},getOpenRatio:function(){var t=this.getOpenAmount();return t>=0?t/this.left.width:t/this.right.width},isOpen:function(){return 0!==this.getOpenAmount()},getOpenPercentage:function(){return 100*this.getOpenRatio()},openPercentage:function(t){var e=t/100;if(this.left&&t>=0)this.openAmount(this.left.width*e);else if(this.right&&0>t){{this.right.width}this.openAmount(this.right.width*e)}},openAmount:function(t){var e=this.left&&this.left.width||0,n=this.right&&this.right.width||0;return(this.left&&this.left.isEnabled||!(t>0))&&(this.right&&this.right.isEnabled||!(0>t))?this._leftShowing&&t>e?void this.content.setTranslateX(e):this._rightShowing&&-n>t?void this.content.setTranslateX(-n):(this.content.setTranslateX(t),void(t>=0?(this._leftShowing=!0,this._rightShowing=!1,t>0&&(this.right&&this.right.pushDown&&this.right.pushDown(),this.left&&this.left.bringUp&&this.left.bringUp())):(this._rightShowing=!0,this._leftShowing=!1,this.right&&this.right.bringUp&&this.right.bringUp(),this.left&&this.left.pushDown&&this.left.pushDown()))):void this.content.setTranslateX(0)},snapToRest:function(t){this.content.enableAnimation(),this._isDragging=!1;var e=this.getOpenRatio();if(0===e)return void this.openPercentage(0);var n=.3,i=t.gesture.velocityX,r=t.gesture.direction;this.openPercentage(e>0&&.5>e&&"right"==r&&n>i?0:e>.5&&"left"==r&&n>i?100:0>e&&e>-.5&&"left"==r&&n>i?0:.5>e&&"right"==r&&n>i?-100:"right"==r&&e>=0&&(e>=.5||i>n)?100:"left"==r&&0>=e&&(-.5>=e||i>n)?-100:0)},_endDrag:function(t){this._isDragging&&this.snapToRest(t),this._startX=null,this._lastX=null,this._offsetX=null},_handleDrag:function(t){this._startX?this._lastX=t.gesture.touches[0].pageX:(this._startX=t.gesture.touches[0].pageX,this._lastX=this._startX),!this._isDragging&&Math.abs(this._lastX-this._startX)>this.dragThresholdX&&(this._startX=this._lastX,this._isDragging=!0,this.content.disableAnimation(),this._offsetX=this.getOpenAmount()),this._isDragging&&this.openAmount(this._offsetX+(this._lastX-this._startX))}})}(ionic),function(){var t=Date.now||function(){return+new Date},e=60,n=1e3,i={},r=1;ionic.Animation={},ionic.Animation={create:function(t){return new ionic.Animation.Animation(t)},animationStarted:function(t){var e=r++;if(e%20===0){var n={};for(var o in i)n[o]=!0;i=n}return i[e]=!0,t.isRunning=!0,t._animationId=e,e},animationStopped:function(t){t.isRunning=!1}},ionic.Animation.Animation=function(t){ionic.extend(this,t),t.useSlowAnimations&&(this.delay*=3,this.duration*=3)},ionic.Animation.Animation.prototype={el:null,curve:"linear",duration:500,delay:0,repeat:-1,reverse:!1,autoReverse:!1,step:function(){},stop:function(){this.isRunning=!1,this.shouldEnd=!0},play:function(){this.isPaused=!1,this.start()},pause:function(){this.isPaused=!0},_saveState:function(t,e,n){this._pauseState={percent:t,iteration:e,reverse:n}},restart:function(){},start:function(){var t,e=this;t="string"==typeof this.curve?ionic.Animation.TimingFn[this.curve]||ionic.Animation.TimingFn.linear:this.curve,t=t(this.duration);var n={startPercent:this.reverse===!0?1:0,endPercent:this.reverse===!0?0:1,duration:this.duration,easingMethod:t,delay:this.delay,reverse:this.reverse,repeat:this.repeat,autoReverse:this.autoReverse};return this._pauseState&&(ionic.extend(n,this._pauseState),this._pauseState=null),ionic.Animation.animationStarted(this),this._run(function(t,n,i){i&&e.step(t)},function(){ionic.Animation.animationStopped(e)},n)},_run:function(i,r,o){var a=this,s=t(),c=s,l=(s+o.delay,o.startPercent),u=o.startPercent,h=o.endPercent,d=o.autoReverse,f=o.delay,_=o.duration,p=o.easingMethod,g=o.repeat,m=o.reverse,v=0,T=0,E=function(){if(l===h&&d){var e=h;m=!m,h=u,u=e,0===g&&(d=!1)}else l=u;s=t(),ionic.requestAnimationFrame(w)},w=function(o){var u=o!==!0,y=t(),S=y-s;if(a.isPaused)return void a._saveState(l,T,m);if(!a.isRunning)return void(r&&r(e-v/((y-s)/n),a._animationId,!1));if(u)for(var b=Math.round((y-c)/(n/e))-1,M=0;Mf&&_&&(l=(S-f)/_,m===!0?(l=1-l,0>l&&(l=0)):l>1&&(l=1));var D=p?p(l):l;i(D,y,u)!==!1&&l!==h||!u?u&&(c=y,ionic.requestAnimationFrame(w)):-1===g?E():g>T?(T++,E()):0===g&&d?E():r&&r(e-v/((y-s)/n),a._animationId,l===h||null==_)};ionic.requestAnimationFrame(w)}}}(window),function(t){t.Animation=t.Animation||{},t.Animation.Bezier=function(){"use strict";var t=400,e=function(t){return 1/(200*t)},n=function(n,i,r,o){var a=3*n,s=3*(r-n)-a,c=1-a-s,l=3*i,u=3*(o-i)-l,h=1-l-u,d=function(t){return((c*t+s)*t+a)*t},f=function(t){return((h*t+u)*t+l)*t},_=function(t){return(3*c*t+2*s)*t+a},p=function(t,e){var n,i,r,o,a,s;for(r=t,s=0;8>s;s++){if(o=d(r)-t,Math.abs(o)r)return n;if(r>i)return i;for(;i>n;){if(o=d(r),Math.abs(o-t)o?n=r:i=r,r=.5*(i-n)+n}return r},g=function(t,e){return f(p(t,e))};return function(n,i){return g(n,e(+i||t))}};return{linear:n(0,0,1,1),ease:n(.25,.1,.25,1),easeIn:n(.42,0,1,1),easeOut:n(0,0,.58,1),easeInOut:n(.42,0,.58,1),cubicBezier:function(t,e,i,r,o,a){return n(t,e,i,r)(o,a)}}}();!function(){"use strict";var t=.5*Math.pow(.5,1.925);return{linear:function(t){return t},easeInApprox:function(t){return Math.pow(t,1.685)},easeInQuadratic:function(t){return t*t},easeInCubic:function(t){return t*t*t},easeOutApprox:function(t){return 1-Math.pow(1-t,1.685)},easeOutQuadratic:function(t){return t-=1,1-t*t},easeOutCubic:function(t){return t-=1,1+t*t*t},easeInOutApprox:function(e){return.5>e?t*Math.pow(e,1.925):1-t*Math.pow(1-e,1.925)},easeInOutQuadratic:function(t){return.5>t?2*t*t:(t-=1,1-2*t*t)},easeInOutCubic:function(t){return.5>t?4*t*t*t:(t-=1,1+4*t*t*t)},easeInOutQuartic:function(t){return.5>t?8*t*t*t*t:(t-=1,1+8*t*t*t*t)},easeInOutQuintic:function(t){return.5>t?16*t*t*t*t*t:(t-=1,1+16*t*t*t*t*t)}}}()}(ionic),function(t){"use strict";var e={};"undefined"==typeof exports?"function"==typeof define&&"object"==typeof define.amd&&define.amd?(e.exports={},define(function(){return e.exports})):e.exports="undefined"!=typeof window?window:t:e.exports=exports,function(t){if(!e)var e=1e-6;if(!n)var n="undefined"!=typeof Float32Array?Float32Array:Array;if(!i)var i=Math.random;var r={};r.setMatrixArrayType=function(t){n=t},"undefined"!=typeof t&&(t.glMatrix=r);var o=Math.PI/180;r.toRadian=function(t){return t*o};var a={};a.create=function(){var t=new n(2);return t[0]=0,t[1]=0,t},a.clone=function(t){var e=new n(2);return e[0]=t[0],e[1]=t[1],e},a.fromValues=function(t,e){var i=new n(2);return i[0]=t,i[1]=e,i},a.copy=function(t,e){return t[0]=e[0],t[1]=e[1],t},a.set=function(t,e,n){return t[0]=e,t[1]=n,t},a.add=function(t,e,n){return t[0]=e[0]+n[0],t[1]=e[1]+n[1],t},a.subtract=function(t,e,n){return t[0]=e[0]-n[0],t[1]=e[1]-n[1],t},a.sub=a.subtract,a.multiply=function(t,e,n){return t[0]=e[0]*n[0],t[1]=e[1]*n[1],t},a.mul=a.multiply,a.divide=function(t,e,n){return t[0]=e[0]/n[0],t[1]=e[1]/n[1],t},a.div=a.divide,a.min=function(t,e,n){return t[0]=Math.min(e[0],n[0]),t[1]=Math.min(e[1],n[1]),t},a.max=function(t,e,n){return t[0]=Math.max(e[0],n[0]),t[1]=Math.max(e[1],n[1]),t},a.scale=function(t,e,n){return t[0]=e[0]*n,t[1]=e[1]*n,t},a.scaleAndAdd=function(t,e,n,i){return t[0]=e[0]+n[0]*i,t[1]=e[1]+n[1]*i,t},a.distance=function(t,e){var n=e[0]-t[0],i=e[1]-t[1];return Math.sqrt(n*n+i*i)},a.dist=a.distance,a.squaredDistance=function(t,e){var n=e[0]-t[0],i=e[1]-t[1];return n*n+i*i},a.sqrDist=a.squaredDistance,a.length=function(t){var e=t[0],n=t[1];return Math.sqrt(e*e+n*n)},a.len=a.length,a.squaredLength=function(t){var e=t[0],n=t[1];return e*e+n*n},a.sqrLen=a.squaredLength,a.negate=function(t,e){return t[0]=-e[0],t[1]=-e[1],t},a.normalize=function(t,e){var n=e[0],i=e[1],r=n*n+i*i;return r>0&&(r=1/Math.sqrt(r),t[0]=e[0]*r,t[1]=e[1]*r),t},a.dot=function(t,e){return t[0]*e[0]+t[1]*e[1]},a.cross=function(t,e,n){var i=e[0]*n[1]-e[1]*n[0];return t[0]=t[1]=0,t[2]=i,t},a.lerp=function(t,e,n,i){var r=e[0],o=e[1];return t[0]=r+i*(n[0]-r),t[1]=o+i*(n[1]-o),t},a.random=function(t,e){e=e||1;var n=2*i()*Math.PI;return t[0]=Math.cos(n)*e,t[1]=Math.sin(n)*e,t},a.transformMat2=function(t,e,n){var i=e[0],r=e[1];return t[0]=n[0]*i+n[2]*r,t[1]=n[1]*i+n[3]*r,t},a.transformMat2d=function(t,e,n){var i=e[0],r=e[1];return t[0]=n[0]*i+n[2]*r+n[4],t[1]=n[1]*i+n[3]*r+n[5],t},a.transformMat3=function(t,e,n){var i=e[0],r=e[1];return t[0]=n[0]*i+n[3]*r+n[6],t[1]=n[1]*i+n[4]*r+n[7],t},a.transformMat4=function(t,e,n){var i=e[0],r=e[1];return t[0]=n[0]*i+n[4]*r+n[12],t[1]=n[1]*i+n[5]*r+n[13],t},a.forEach=function(){var t=a.create();return function(e,n,i,r,o,a){var s,c;for(n||(n=2),i||(i=0),c=r?Math.min(r*n+i,e.length):e.length,s=i;c>s;s+=n)t[0]=e[s],t[1]=e[s+1],o(t,t,a),e[s]=t[0],e[s+1]=t[1];return e}}(),a.str=function(t){return"vec2("+t[0]+", "+t[1]+")"},"undefined"!=typeof t&&(t.vec2=a);var s={};s.create=function(){var t=new n(3);return t[0]=0,t[1]=0,t[2]=0,t},s.clone=function(t){var e=new n(3);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e},s.fromValues=function(t,e,i){var r=new n(3);return r[0]=t,r[1]=e,r[2]=i,r},s.copy=function(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t},s.set=function(t,e,n,i){return t[0]=e,t[1]=n,t[2]=i,t},s.add=function(t,e,n){return t[0]=e[0]+n[0],t[1]=e[1]+n[1],t[2]=e[2]+n[2],t},s.subtract=function(t,e,n){return t[0]=e[0]-n[0],t[1]=e[1]-n[1],t[2]=e[2]-n[2],t},s.sub=s.subtract,s.multiply=function(t,e,n){return t[0]=e[0]*n[0],t[1]=e[1]*n[1],t[2]=e[2]*n[2],t},s.mul=s.multiply,s.divide=function(t,e,n){return t[0]=e[0]/n[0],t[1]=e[1]/n[1],t[2]=e[2]/n[2],t},s.div=s.divide,s.min=function(t,e,n){return t[0]=Math.min(e[0],n[0]),t[1]=Math.min(e[1],n[1]),t[2]=Math.min(e[2],n[2]),t},s.max=function(t,e,n){return t[0]=Math.max(e[0],n[0]),t[1]=Math.max(e[1],n[1]),t[2]=Math.max(e[2],n[2]),t},s.scale=function(t,e,n){return t[0]=e[0]*n,t[1]=e[1]*n,t[2]=e[2]*n,t},s.scaleAndAdd=function(t,e,n,i){return t[0]=e[0]+n[0]*i,t[1]=e[1]+n[1]*i,t[2]=e[2]+n[2]*i,t},s.distance=function(t,e){var n=e[0]-t[0],i=e[1]-t[1],r=e[2]-t[2];return Math.sqrt(n*n+i*i+r*r)},s.dist=s.distance,s.squaredDistance=function(t,e){var n=e[0]-t[0],i=e[1]-t[1],r=e[2]-t[2];return n*n+i*i+r*r},s.sqrDist=s.squaredDistance,s.length=function(t){var e=t[0],n=t[1],i=t[2];return Math.sqrt(e*e+n*n+i*i)},s.len=s.length,s.squaredLength=function(t){var e=t[0],n=t[1],i=t[2];return e*e+n*n+i*i},s.sqrLen=s.squaredLength,s.negate=function(t,e){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t},s.normalize=function(t,e){var n=e[0],i=e[1],r=e[2],o=n*n+i*i+r*r;return o>0&&(o=1/Math.sqrt(o),t[0]=e[0]*o,t[1]=e[1]*o,t[2]=e[2]*o),t},s.dot=function(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]},s.cross=function(t,e,n){var i=e[0],r=e[1],o=e[2],a=n[0],s=n[1],c=n[2];return t[0]=r*c-o*s,t[1]=o*a-i*c,t[2]=i*s-r*a,t},s.lerp=function(t,e,n,i){var r=e[0],o=e[1],a=e[2];return t[0]=r+i*(n[0]-r),t[1]=o+i*(n[1]-o),t[2]=a+i*(n[2]-a),t},s.random=function(t,e){e=e||1;var n=2*i()*Math.PI,r=2*i()-1,o=Math.sqrt(1-r*r)*e;return t[0]=Math.cos(n)*o,t[1]=Math.sin(n)*o,t[2]=r*e,t},s.transformMat4=function(t,e,n){var i=e[0],r=e[1],o=e[2];return t[0]=n[0]*i+n[4]*r+n[8]*o+n[12],t[1]=n[1]*i+n[5]*r+n[9]*o+n[13],t[2]=n[2]*i+n[6]*r+n[10]*o+n[14],t},s.transformMat3=function(t,e,n){var i=e[0],r=e[1],o=e[2];return t[0]=i*n[0]+r*n[3]+o*n[6],t[1]=i*n[1]+r*n[4]+o*n[7],t[2]=i*n[2]+r*n[5]+o*n[8],t},s.transformQuat=function(t,e,n){var i=e[0],r=e[1],o=e[2],a=n[0],s=n[1],c=n[2],l=n[3],u=l*i+s*o-c*r,h=l*r+c*i-a*o,d=l*o+a*r-s*i,f=-a*i-s*r-c*o;return t[0]=u*l+f*-a+h*-c-d*-s,t[1]=h*l+f*-s+d*-a-u*-c,t[2]=d*l+f*-c+u*-s-h*-a,t},s.rotateX=function(t,e,n,i){var r=[],o=[];return r[0]=e[0]-n[0],r[1]=e[1]-n[1],r[2]=e[2]-n[2],o[0]=r[0],o[1]=r[1]*Math.cos(i)-r[2]*Math.sin(i),o[2]=r[1]*Math.sin(i)+r[2]*Math.cos(i),t[0]=o[0]+n[0],t[1]=o[1]+n[1],t[2]=o[2]+n[2],t},s.rotateY=function(t,e,n,i){var r=[],o=[];return r[0]=e[0]-n[0],r[1]=e[1]-n[1],r[2]=e[2]-n[2],o[0]=r[2]*Math.sin(i)+r[0]*Math.cos(i),o[1]=r[1],o[2]=r[2]*Math.cos(i)-r[0]*Math.sin(i),t[0]=o[0]+n[0],t[1]=o[1]+n[1],t[2]=o[2]+n[2],t},s.rotateZ=function(t,e,n,i){var r=[],o=[];return r[0]=e[0]-n[0],r[1]=e[1]-n[1],r[2]=e[2]-n[2],o[0]=r[0]*Math.cos(i)-r[1]*Math.sin(i),o[1]=r[0]*Math.sin(i)+r[1]*Math.cos(i),o[2]=r[2],t[0]=o[0]+n[0],t[1]=o[1]+n[1],t[2]=o[2]+n[2],t},s.forEach=function(){var t=s.create();return function(e,n,i,r,o,a){var s,c;for(n||(n=3),i||(i=0),c=r?Math.min(r*n+i,e.length):e.length,s=i;c>s;s+=n)t[0]=e[s],t[1]=e[s+1],t[2]=e[s+2],o(t,t,a),e[s]=t[0],e[s+1]=t[1],e[s+2]=t[2];return e}}(),s.str=function(t){return"vec3("+t[0]+", "+t[1]+", "+t[2]+")"},"undefined"!=typeof t&&(t.vec3=s);var c={};c.create=function(){var t=new n(4);return t[0]=0,t[1]=0,t[2]=0,t[3]=0,t},c.clone=function(t){var e=new n(4);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e},c.fromValues=function(t,e,i,r){var o=new n(4);return o[0]=t,o[1]=e,o[2]=i,o[3]=r,o},c.copy=function(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t},c.set=function(t,e,n,i,r){return t[0]=e,t[1]=n,t[2]=i,t[3]=r,t},c.add=function(t,e,n){return t[0]=e[0]+n[0],t[1]=e[1]+n[1],t[2]=e[2]+n[2],t[3]=e[3]+n[3],t},c.subtract=function(t,e,n){return t[0]=e[0]-n[0],t[1]=e[1]-n[1],t[2]=e[2]-n[2],t[3]=e[3]-n[3],t},c.sub=c.subtract,c.multiply=function(t,e,n){return t[0]=e[0]*n[0],t[1]=e[1]*n[1],t[2]=e[2]*n[2],t[3]=e[3]*n[3],t},c.mul=c.multiply,c.divide=function(t,e,n){return t[0]=e[0]/n[0],t[1]=e[1]/n[1],t[2]=e[2]/n[2],t[3]=e[3]/n[3],t},c.div=c.divide,c.min=function(t,e,n){return t[0]=Math.min(e[0],n[0]),t[1]=Math.min(e[1],n[1]),t[2]=Math.min(e[2],n[2]),t[3]=Math.min(e[3],n[3]),t},c.max=function(t,e,n){return t[0]=Math.max(e[0],n[0]),t[1]=Math.max(e[1],n[1]),t[2]=Math.max(e[2],n[2]),t[3]=Math.max(e[3],n[3]),t},c.scale=function(t,e,n){return t[0]=e[0]*n,t[1]=e[1]*n,t[2]=e[2]*n,t[3]=e[3]*n,t},c.scaleAndAdd=function(t,e,n,i){return t[0]=e[0]+n[0]*i,t[1]=e[1]+n[1]*i,t[2]=e[2]+n[2]*i,t[3]=e[3]+n[3]*i,t},c.distance=function(t,e){var n=e[0]-t[0],i=e[1]-t[1],r=e[2]-t[2],o=e[3]-t[3];return Math.sqrt(n*n+i*i+r*r+o*o)},c.dist=c.distance,c.squaredDistance=function(t,e){var n=e[0]-t[0],i=e[1]-t[1],r=e[2]-t[2],o=e[3]-t[3];return n*n+i*i+r*r+o*o},c.sqrDist=c.squaredDistance,c.length=function(t){var e=t[0],n=t[1],i=t[2],r=t[3];return Math.sqrt(e*e+n*n+i*i+r*r)},c.len=c.length,c.squaredLength=function(t){var e=t[0],n=t[1],i=t[2],r=t[3];return e*e+n*n+i*i+r*r},c.sqrLen=c.squaredLength,c.negate=function(t,e){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t[3]=-e[3],t},c.normalize=function(t,e){var n=e[0],i=e[1],r=e[2],o=e[3],a=n*n+i*i+r*r+o*o;return a>0&&(a=1/Math.sqrt(a),t[0]=e[0]*a,t[1]=e[1]*a,t[2]=e[2]*a,t[3]=e[3]*a),t},c.dot=function(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]+t[3]*e[3]},c.lerp=function(t,e,n,i){var r=e[0],o=e[1],a=e[2],s=e[3];return t[0]=r+i*(n[0]-r),t[1]=o+i*(n[1]-o),t[2]=a+i*(n[2]-a),t[3]=s+i*(n[3]-s),t},c.random=function(t,e){return e=e||1,t[0]=i(),t[1]=i(),t[2]=i(),t[3]=i(),c.normalize(t,t),c.scale(t,t,e),t},c.transformMat4=function(t,e,n){var i=e[0],r=e[1],o=e[2],a=e[3];return t[0]=n[0]*i+n[4]*r+n[8]*o+n[12]*a,t[1]=n[1]*i+n[5]*r+n[9]*o+n[13]*a,t[2]=n[2]*i+n[6]*r+n[10]*o+n[14]*a,t[3]=n[3]*i+n[7]*r+n[11]*o+n[15]*a,t},c.transformQuat=function(t,e,n){var i=e[0],r=e[1],o=e[2],a=n[0],s=n[1],c=n[2],l=n[3],u=l*i+s*o-c*r,h=l*r+c*i-a*o,d=l*o+a*r-s*i,f=-a*i-s*r-c*o;return t[0]=u*l+f*-a+h*-c-d*-s,t[1]=h*l+f*-s+d*-a-u*-c,t[2]=d*l+f*-c+u*-s-h*-a,t},c.forEach=function(){var t=c.create();return function(e,n,i,r,o,a){var s,c;for(n||(n=4),i||(i=0),c=r?Math.min(r*n+i,e.length):e.length,s=i;c>s;s+=n)t[0]=e[s],t[1]=e[s+1],t[2]=e[s+2],t[3]=e[s+3],o(t,t,a),e[s]=t[0],e[s+1]=t[1],e[s+2]=t[2],e[s+3]=t[3];return e}}(),c.str=function(t){return"vec4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},"undefined"!=typeof t&&(t.vec4=c);var l={};l.create=function(){var t=new n(4);return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t},l.clone=function(t){var e=new n(4);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e},l.copy=function(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t},l.identity=function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t},l.transpose=function(t,e){if(t===e){var n=e[1];t[1]=e[2],t[2]=n}else t[0]=e[0],t[1]=e[2],t[2]=e[1],t[3]=e[3];return t},l.invert=function(t,e){var n=e[0],i=e[1],r=e[2],o=e[3],a=n*o-r*i;return a?(a=1/a,t[0]=o*a,t[1]=-i*a,t[2]=-r*a,t[3]=n*a,t):null},l.adjoint=function(t,e){var n=e[0];return t[0]=e[3],t[1]=-e[1],t[2]=-e[2],t[3]=n,t},l.determinant=function(t){return t[0]*t[3]-t[2]*t[1]},l.multiply=function(t,e,n){var i=e[0],r=e[1],o=e[2],a=e[3],s=n[0],c=n[1],l=n[2],u=n[3];return t[0]=i*s+o*c,t[1]=r*s+a*c,t[2]=i*l+o*u,t[3]=r*l+a*u,t},l.mul=l.multiply,l.rotate=function(t,e,n){var i=e[0],r=e[1],o=e[2],a=e[3],s=Math.sin(n),c=Math.cos(n);return t[0]=i*c+o*s,t[1]=r*c+a*s,t[2]=i*-s+o*c,t[3]=r*-s+a*c,t},l.scale=function(t,e,n){var i=e[0],r=e[1],o=e[2],a=e[3],s=n[0],c=n[1];return t[0]=i*s,t[1]=r*s,t[2]=o*c,t[3]=a*c,t},l.str=function(t){return"mat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},l.frob=function(t){return Math.sqrt(Math.pow(t[0],2)+Math.pow(t[1],2)+Math.pow(t[2],2)+Math.pow(t[3],2))},l.LDU=function(t,e,n,i){return t[2]=i[2]/i[0],n[0]=i[0],n[1]=i[1],n[3]=i[3]-t[2]*n[1],[t,e,n]},"undefined"!=typeof t&&(t.mat2=l);var u={};u.create=function(){var t=new n(6);return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t},u.clone=function(t){var e=new n(6);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e[4]=t[4],e[5]=t[5],e},u.copy=function(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t},u.identity=function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t},u.invert=function(t,e){var n=e[0],i=e[1],r=e[2],o=e[3],a=e[4],s=e[5],c=n*o-i*r;return c?(c=1/c,t[0]=o*c,t[1]=-i*c,t[2]=-r*c,t[3]=n*c,t[4]=(r*s-o*a)*c,t[5]=(i*a-n*s)*c,t):null},u.determinant=function(t){return t[0]*t[3]-t[1]*t[2]},u.multiply=function(t,e,n){var i=e[0],r=e[1],o=e[2],a=e[3],s=e[4],c=e[5],l=n[0],u=n[1],h=n[2],d=n[3],f=n[4],_=n[5];return t[0]=i*l+o*u,t[1]=r*l+a*u,t[2]=i*h+o*d,t[3]=r*h+a*d,t[4]=i*f+o*_+s,t[5]=r*f+a*_+c,t},u.mul=u.multiply,u.rotate=function(t,e,n){var i=e[0],r=e[1],o=e[2],a=e[3],s=e[4],c=e[5],l=Math.sin(n),u=Math.cos(n);return t[0]=i*u+o*l,t[1]=r*u+a*l,t[2]=i*-l+o*u,t[3]=r*-l+a*u,t[4]=s,t[5]=c,t},u.scale=function(t,e,n){var i=e[0],r=e[1],o=e[2],a=e[3],s=e[4],c=e[5],l=n[0],u=n[1];return t[0]=i*l,t[1]=r*l,t[2]=o*u,t[3]=a*u,t[4]=s,t[5]=c,t},u.translate=function(t,e,n){var i=e[0],r=e[1],o=e[2],a=e[3],s=e[4],c=e[5],l=n[0],u=n[1];return t[0]=i,t[1]=r,t[2]=o,t[3]=a,t[4]=i*l+o*u+s,t[5]=r*l+a*u+c,t},u.str=function(t){return"mat2d("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+")"},u.frob=function(t){return Math.sqrt(Math.pow(t[0],2)+Math.pow(t[1],2)+Math.pow(t[2],2)+Math.pow(t[3],2)+Math.pow(t[4],2)+Math.pow(t[5],2)+1)},"undefined"!=typeof t&&(t.mat2d=u);var h={};h.create=function(){var t=new n(9);return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},h.fromMat4=function(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[4],t[4]=e[5],t[5]=e[6],t[6]=e[8],t[7]=e[9],t[8]=e[10],t},h.clone=function(t){var e=new n(9);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e[4]=t[4],e[5]=t[5],e[6]=t[6],e[7]=t[7],e[8]=t[8],e},h.copy=function(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t},h.identity=function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},h.transpose=function(t,e){if(t===e){var n=e[1],i=e[2],r=e[5];t[1]=e[3],t[2]=e[6],t[3]=n,t[5]=e[7],t[6]=i,t[7]=r +}else t[0]=e[0],t[1]=e[3],t[2]=e[6],t[3]=e[1],t[4]=e[4],t[5]=e[7],t[6]=e[2],t[7]=e[5],t[8]=e[8];return t},h.invert=function(t,e){var n=e[0],i=e[1],r=e[2],o=e[3],a=e[4],s=e[5],c=e[6],l=e[7],u=e[8],h=u*a-s*l,d=-u*o+s*c,f=l*o-a*c,_=n*h+i*d+r*f;return _?(_=1/_,t[0]=h*_,t[1]=(-u*i+r*l)*_,t[2]=(s*i-r*a)*_,t[3]=d*_,t[4]=(u*n-r*c)*_,t[5]=(-s*n+r*o)*_,t[6]=f*_,t[7]=(-l*n+i*c)*_,t[8]=(a*n-i*o)*_,t):null},h.adjoint=function(t,e){var n=e[0],i=e[1],r=e[2],o=e[3],a=e[4],s=e[5],c=e[6],l=e[7],u=e[8];return t[0]=a*u-s*l,t[1]=r*l-i*u,t[2]=i*s-r*a,t[3]=s*c-o*u,t[4]=n*u-r*c,t[5]=r*o-n*s,t[6]=o*l-a*c,t[7]=i*c-n*l,t[8]=n*a-i*o,t},h.determinant=function(t){var e=t[0],n=t[1],i=t[2],r=t[3],o=t[4],a=t[5],s=t[6],c=t[7],l=t[8];return e*(l*o-a*c)+n*(-l*r+a*s)+i*(c*r-o*s)},h.multiply=function(t,e,n){var i=e[0],r=e[1],o=e[2],a=e[3],s=e[4],c=e[5],l=e[6],u=e[7],h=e[8],d=n[0],f=n[1],_=n[2],p=n[3],g=n[4],m=n[5],v=n[6],T=n[7],E=n[8];return t[0]=d*i+f*a+_*l,t[1]=d*r+f*s+_*u,t[2]=d*o+f*c+_*h,t[3]=p*i+g*a+m*l,t[4]=p*r+g*s+m*u,t[5]=p*o+g*c+m*h,t[6]=v*i+T*a+E*l,t[7]=v*r+T*s+E*u,t[8]=v*o+T*c+E*h,t},h.mul=h.multiply,h.translate=function(t,e,n){var i=e[0],r=e[1],o=e[2],a=e[3],s=e[4],c=e[5],l=e[6],u=e[7],h=e[8],d=n[0],f=n[1];return t[0]=i,t[1]=r,t[2]=o,t[3]=a,t[4]=s,t[5]=c,t[6]=d*i+f*a+l,t[7]=d*r+f*s+u,t[8]=d*o+f*c+h,t},h.rotate=function(t,e,n){var i=e[0],r=e[1],o=e[2],a=e[3],s=e[4],c=e[5],l=e[6],u=e[7],h=e[8],d=Math.sin(n),f=Math.cos(n);return t[0]=f*i+d*a,t[1]=f*r+d*s,t[2]=f*o+d*c,t[3]=f*a-d*i,t[4]=f*s-d*r,t[5]=f*c-d*o,t[6]=l,t[7]=u,t[8]=h,t},h.scale=function(t,e,n){var i=n[0],r=n[1];return t[0]=i*e[0],t[1]=i*e[1],t[2]=i*e[2],t[3]=r*e[3],t[4]=r*e[4],t[5]=r*e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t},h.fromMat2d=function(t,e){return t[0]=e[0],t[1]=e[1],t[2]=0,t[3]=e[2],t[4]=e[3],t[5]=0,t[6]=e[4],t[7]=e[5],t[8]=1,t},h.fromQuat=function(t,e){var n=e[0],i=e[1],r=e[2],o=e[3],a=n+n,s=i+i,c=r+r,l=n*a,u=i*a,h=i*s,d=r*a,f=r*s,_=r*c,p=o*a,g=o*s,m=o*c;return t[0]=1-h-_,t[3]=u-m,t[6]=d+g,t[1]=u+m,t[4]=1-l-_,t[7]=f-p,t[2]=d-g,t[5]=f+p,t[8]=1-l-h,t},h.normalFromMat4=function(t,e){var n=e[0],i=e[1],r=e[2],o=e[3],a=e[4],s=e[5],c=e[6],l=e[7],u=e[8],h=e[9],d=e[10],f=e[11],_=e[12],p=e[13],g=e[14],m=e[15],v=n*s-i*a,T=n*c-r*a,E=n*l-o*a,w=i*c-r*s,y=i*l-o*s,S=r*l-o*c,b=u*p-h*_,M=u*g-d*_,D=u*m-f*_,x=h*g-d*p,L=h*m-f*p,A=d*m-f*g,O=v*A-T*L+E*x+w*D-y*M+S*b;return O?(O=1/O,t[0]=(s*A-c*L+l*x)*O,t[1]=(c*D-a*A-l*M)*O,t[2]=(a*L-s*D+l*b)*O,t[3]=(r*L-i*A-o*x)*O,t[4]=(n*A-r*D+o*M)*O,t[5]=(i*D-n*L-o*b)*O,t[6]=(p*S-g*y+m*w)*O,t[7]=(g*E-_*S-m*T)*O,t[8]=(_*y-p*E+m*v)*O,t):null},h.str=function(t){return"mat3("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+")"},h.frob=function(t){return Math.sqrt(Math.pow(t[0],2)+Math.pow(t[1],2)+Math.pow(t[2],2)+Math.pow(t[3],2)+Math.pow(t[4],2)+Math.pow(t[5],2)+Math.pow(t[6],2)+Math.pow(t[7],2)+Math.pow(t[8],2))},"undefined"!=typeof t&&(t.mat3=h);var d={};d.create=function(){var t=new n(16);return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},d.clone=function(t){var e=new n(16);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e[4]=t[4],e[5]=t[5],e[6]=t[6],e[7]=t[7],e[8]=t[8],e[9]=t[9],e[10]=t[10],e[11]=t[11],e[12]=t[12],e[13]=t[13],e[14]=t[14],e[15]=t[15],e},d.copy=function(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t[9]=e[9],t[10]=e[10],t[11]=e[11],t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15],t},d.identity=function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},d.transpose=function(t,e){if(t===e){var n=e[1],i=e[2],r=e[3],o=e[6],a=e[7],s=e[11];t[1]=e[4],t[2]=e[8],t[3]=e[12],t[4]=n,t[6]=e[9],t[7]=e[13],t[8]=i,t[9]=o,t[11]=e[14],t[12]=r,t[13]=a,t[14]=s}else t[0]=e[0],t[1]=e[4],t[2]=e[8],t[3]=e[12],t[4]=e[1],t[5]=e[5],t[6]=e[9],t[7]=e[13],t[8]=e[2],t[9]=e[6],t[10]=e[10],t[11]=e[14],t[12]=e[3],t[13]=e[7],t[14]=e[11],t[15]=e[15];return t},d.invert=function(t,e){var n=e[0],i=e[1],r=e[2],o=e[3],a=e[4],s=e[5],c=e[6],l=e[7],u=e[8],h=e[9],d=e[10],f=e[11],_=e[12],p=e[13],g=e[14],m=e[15],v=n*s-i*a,T=n*c-r*a,E=n*l-o*a,w=i*c-r*s,y=i*l-o*s,S=r*l-o*c,b=u*p-h*_,M=u*g-d*_,D=u*m-f*_,x=h*g-d*p,L=h*m-f*p,A=d*m-f*g,O=v*A-T*L+E*x+w*D-y*M+S*b;return O?(O=1/O,t[0]=(s*A-c*L+l*x)*O,t[1]=(r*L-i*A-o*x)*O,t[2]=(p*S-g*y+m*w)*O,t[3]=(d*y-h*S-f*w)*O,t[4]=(c*D-a*A-l*M)*O,t[5]=(n*A-r*D+o*M)*O,t[6]=(g*E-_*S-m*T)*O,t[7]=(u*S-d*E+f*T)*O,t[8]=(a*L-s*D+l*b)*O,t[9]=(i*D-n*L-o*b)*O,t[10]=(_*y-p*E+m*v)*O,t[11]=(h*E-u*y-f*v)*O,t[12]=(s*M-a*x-c*b)*O,t[13]=(n*x-i*M+r*b)*O,t[14]=(p*T-_*w-g*v)*O,t[15]=(u*w-h*T+d*v)*O,t):null},d.adjoint=function(t,e){var n=e[0],i=e[1],r=e[2],o=e[3],a=e[4],s=e[5],c=e[6],l=e[7],u=e[8],h=e[9],d=e[10],f=e[11],_=e[12],p=e[13],g=e[14],m=e[15];return t[0]=s*(d*m-f*g)-h*(c*m-l*g)+p*(c*f-l*d),t[1]=-(i*(d*m-f*g)-h*(r*m-o*g)+p*(r*f-o*d)),t[2]=i*(c*m-l*g)-s*(r*m-o*g)+p*(r*l-o*c),t[3]=-(i*(c*f-l*d)-s*(r*f-o*d)+h*(r*l-o*c)),t[4]=-(a*(d*m-f*g)-u*(c*m-l*g)+_*(c*f-l*d)),t[5]=n*(d*m-f*g)-u*(r*m-o*g)+_*(r*f-o*d),t[6]=-(n*(c*m-l*g)-a*(r*m-o*g)+_*(r*l-o*c)),t[7]=n*(c*f-l*d)-a*(r*f-o*d)+u*(r*l-o*c),t[8]=a*(h*m-f*p)-u*(s*m-l*p)+_*(s*f-l*h),t[9]=-(n*(h*m-f*p)-u*(i*m-o*p)+_*(i*f-o*h)),t[10]=n*(s*m-l*p)-a*(i*m-o*p)+_*(i*l-o*s),t[11]=-(n*(s*f-l*h)-a*(i*f-o*h)+u*(i*l-o*s)),t[12]=-(a*(h*g-d*p)-u*(s*g-c*p)+_*(s*d-c*h)),t[13]=n*(h*g-d*p)-u*(i*g-r*p)+_*(i*d-r*h),t[14]=-(n*(s*g-c*p)-a*(i*g-r*p)+_*(i*c-r*s)),t[15]=n*(s*d-c*h)-a*(i*d-r*h)+u*(i*c-r*s),t},d.determinant=function(t){var e=t[0],n=t[1],i=t[2],r=t[3],o=t[4],a=t[5],s=t[6],c=t[7],l=t[8],u=t[9],h=t[10],d=t[11],f=t[12],_=t[13],p=t[14],g=t[15],m=e*a-n*o,v=e*s-i*o,T=e*c-r*o,E=n*s-i*a,w=n*c-r*a,y=i*c-r*s,S=l*_-u*f,b=l*p-h*f,M=l*g-d*f,D=u*p-h*_,x=u*g-d*_,L=h*g-d*p;return m*L-v*x+T*D+E*M-w*b+y*S},d.multiply=function(t,e,n){var i=e[0],r=e[1],o=e[2],a=e[3],s=e[4],c=e[5],l=e[6],u=e[7],h=e[8],d=e[9],f=e[10],_=e[11],p=e[12],g=e[13],m=e[14],v=e[15],T=n[0],E=n[1],w=n[2],y=n[3];return t[0]=T*i+E*s+w*h+y*p,t[1]=T*r+E*c+w*d+y*g,t[2]=T*o+E*l+w*f+y*m,t[3]=T*a+E*u+w*_+y*v,T=n[4],E=n[5],w=n[6],y=n[7],t[4]=T*i+E*s+w*h+y*p,t[5]=T*r+E*c+w*d+y*g,t[6]=T*o+E*l+w*f+y*m,t[7]=T*a+E*u+w*_+y*v,T=n[8],E=n[9],w=n[10],y=n[11],t[8]=T*i+E*s+w*h+y*p,t[9]=T*r+E*c+w*d+y*g,t[10]=T*o+E*l+w*f+y*m,t[11]=T*a+E*u+w*_+y*v,T=n[12],E=n[13],w=n[14],y=n[15],t[12]=T*i+E*s+w*h+y*p,t[13]=T*r+E*c+w*d+y*g,t[14]=T*o+E*l+w*f+y*m,t[15]=T*a+E*u+w*_+y*v,t},d.mul=d.multiply,d.translate=function(t,e,n){var i,r,o,a,s,c,l,u,h,d,f,_,p=n[0],g=n[1],m=n[2];return e===t?(t[12]=e[0]*p+e[4]*g+e[8]*m+e[12],t[13]=e[1]*p+e[5]*g+e[9]*m+e[13],t[14]=e[2]*p+e[6]*g+e[10]*m+e[14],t[15]=e[3]*p+e[7]*g+e[11]*m+e[15]):(i=e[0],r=e[1],o=e[2],a=e[3],s=e[4],c=e[5],l=e[6],u=e[7],h=e[8],d=e[9],f=e[10],_=e[11],t[0]=i,t[1]=r,t[2]=o,t[3]=a,t[4]=s,t[5]=c,t[6]=l,t[7]=u,t[8]=h,t[9]=d,t[10]=f,t[11]=_,t[12]=i*p+s*g+h*m+e[12],t[13]=r*p+c*g+d*m+e[13],t[14]=o*p+l*g+f*m+e[14],t[15]=a*p+u*g+_*m+e[15]),t},d.scale=function(t,e,n){var i=n[0],r=n[1],o=n[2];return t[0]=e[0]*i,t[1]=e[1]*i,t[2]=e[2]*i,t[3]=e[3]*i,t[4]=e[4]*r,t[5]=e[5]*r,t[6]=e[6]*r,t[7]=e[7]*r,t[8]=e[8]*o,t[9]=e[9]*o,t[10]=e[10]*o,t[11]=e[11]*o,t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15],t},d.rotate=function(t,n,i,r){var o,a,s,c,l,u,h,d,f,_,p,g,m,v,T,E,w,y,S,b,M,D,x,L,A=r[0],O=r[1],I=r[2],G=Math.sqrt(A*A+O*O+I*I);return Math.abs(G)a?(s.cross(t,e,r),s.length(t)<1e-6&&s.cross(t,n,r),s.normalize(t,t),f.setAxisAngle(i,t,Math.PI),i):a>.999999?(i[0]=0,i[1]=0,i[2]=0,i[3]=1,i):(s.cross(t,r,o),i[0]=t[0],i[1]=t[1],i[2]=t[2],i[3]=1+a,f.normalize(i,i))}}(),f.setAxes=function(){var t=h.create();return function(e,n,i,r){return t[0]=i[0],t[3]=i[1],t[6]=i[2],t[1]=r[0],t[4]=r[1],t[7]=r[2],t[2]=-n[0],t[5]=-n[1],t[8]=-n[2],f.normalize(e,f.fromMat3(e,t))}}(),f.clone=c.clone,f.fromValues=c.fromValues,f.copy=c.copy,f.set=c.set,f.identity=function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t},f.setAxisAngle=function(t,e,n){n=.5*n;var i=Math.sin(n);return t[0]=i*e[0],t[1]=i*e[1],t[2]=i*e[2],t[3]=Math.cos(n),t},f.add=c.add,f.multiply=function(t,e,n){var i=e[0],r=e[1],o=e[2],a=e[3],s=n[0],c=n[1],l=n[2],u=n[3];return t[0]=i*u+a*s+r*l-o*c,t[1]=r*u+a*c+o*s-i*l,t[2]=o*u+a*l+i*c-r*s,t[3]=a*u-i*s-r*c-o*l,t},f.mul=f.multiply,f.scale=c.scale,f.rotateX=function(t,e,n){n*=.5;var i=e[0],r=e[1],o=e[2],a=e[3],s=Math.sin(n),c=Math.cos(n);return t[0]=i*c+a*s,t[1]=r*c+o*s,t[2]=o*c-r*s,t[3]=a*c-i*s,t},f.rotateY=function(t,e,n){n*=.5;var i=e[0],r=e[1],o=e[2],a=e[3],s=Math.sin(n),c=Math.cos(n);return t[0]=i*c-o*s,t[1]=r*c+a*s,t[2]=o*c+i*s,t[3]=a*c-r*s,t},f.rotateZ=function(t,e,n){n*=.5;var i=e[0],r=e[1],o=e[2],a=e[3],s=Math.sin(n),c=Math.cos(n);return t[0]=i*c+r*s,t[1]=r*c-i*s,t[2]=o*c+a*s,t[3]=a*c-o*s,t},f.calculateW=function(t,e){var n=e[0],i=e[1],r=e[2];return t[0]=n,t[1]=i,t[2]=r,t[3]=-Math.sqrt(Math.abs(1-n*n-i*i-r*r)),t},f.dot=c.dot,f.lerp=c.lerp,f.slerp=function(t,e,n,i){var r,o,a,s,c,l=e[0],u=e[1],h=e[2],d=e[3],f=n[0],_=n[1],p=n[2],g=n[3];return o=l*f+u*_+h*p+d*g,0>o&&(o=-o,f=-f,_=-_,p=-p,g=-g),1-o>1e-6?(r=Math.acos(o),a=Math.sin(r),s=Math.sin((1-i)*r)/a,c=Math.sin(i*r)/a):(s=1-i,c=i),t[0]=s*l+c*f,t[1]=s*u+c*_,t[2]=s*h+c*p,t[3]=s*d+c*g,t},f.invert=function(t,e){var n=e[0],i=e[1],r=e[2],o=e[3],a=n*n+i*i+r*r+o*o,s=a?1/a:0;return t[0]=-n*s,t[1]=-i*s,t[2]=-r*s,t[3]=o*s,t},f.conjugate=function(t,e){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t[3]=e[3],t},f.length=c.length,f.len=f.length,f.squaredLength=c.squaredLength,f.sqrLen=f.squaredLength,f.normalize=c.normalize,f.fromMat3=function(t,e){var n,i=e[0]+e[4]+e[8];if(i>0)n=Math.sqrt(i+1),t[3]=.5*n,n=.5/n,t[0]=(e[7]-e[5])*n,t[1]=(e[2]-e[6])*n,t[2]=(e[3]-e[1])*n;else{var r=0;e[4]>e[0]&&(r=1),e[8]>e[3*r+r]&&(r=2);var o=(r+1)%3,a=(r+2)%3;n=Math.sqrt(e[3*r+r]-e[3*o+o]-e[3*a+a]+1),t[r]=.5*n,n=.5/n,t[3]=(e[3*a+o]-e[3*o+a])*n,t[o]=(e[3*o+r]+e[3*r+o])*n,t[a]=(e[3*a+r]+e[3*r+a])*n}return t},f.str=function(t){return"quat("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},"undefined"!=typeof t&&(t.quat=f)}(e.exports)}(this),function(){ionic.Animation=ionic.Animation||{},ionic.Animation.TimingFn={linear:function(t){return function(e){return ionic.Animation.Bezier.linear(e,t)}},ease:function(t){return function(e){return ionic.Animation.Bezier.ease(e,t)}},"ease-in":function(t){return function(e){return ionic.Animation.Bezier.easeIn(e,t)}},"ease-out":function(t){return function(e){return ionic.Animation.Bezier.easeOut(e,t)}},"ease-in-out":function(t){return function(e){return ionic.Animation.Bezier.easeInOut(e,t)}}}}(window)}(); \ No newline at end of file diff --git a/release/version.json b/release/version.json index c2912676d37..e91230fc468 100644 --- a/release/version.json +++ b/release/version.json @@ -1,6 +1,6 @@ { - "version": "1.0.0-beta.3", + "version": "1.0.0-beta.4", "codename": "americium", - "date": "2014-04-30", - "time": "15:49:37" + "date": "2014-05-07", + "time": "17:57:45" }