Security/ Package Name changes
[portal.git] / ecomp-portal-FE-common / client / bower_components_external / b2b / js / b2b-angular / b2b-library.min.js
1 /*! b2b-angular-library - v1.0.5 - Last updated: 2017-05-24. Copyright (c) 2016 AT&T Services, Inc. */ 
2 angular.module("b2b.att.tpls", ['b2bTemplate/audioPlayer/audioPlayer.html', 'b2bTemplate/audioRecorder/audioRecorder.html', 'b2bTemplate/backToTop/backToTop.html', 'b2bTemplate/boardstrip/b2bAddBoard.html', 'b2bTemplate/boardstrip/b2bBoard.html', 'b2bTemplate/boardstrip/b2bBoardstrip.html', 'b2bTemplate/calendar/datepicker-popup.html', 'b2bTemplate/calendar/datepicker.html', 'b2bTemplate/coachmark/coachmark.html', 'b2bTemplate/dropdowns/b2bDropdownDesktop.html', 'b2bTemplate/dropdowns/b2bDropdownGroupDesktop.html', 'b2bTemplate/dropdowns/b2bDropdownListDesktop.html', 'b2bTemplate/fileUpload/fileUpload.html', 'b2bTemplate/flyout/flyout.html', 'b2bTemplate/flyout/flyoutContent.html', 'b2bTemplate/footer/footer_column_switch_tpl.html', 'b2bTemplate/horizontalTable/horizontalTable.html', 'b2bTemplate/hourPicker/b2bHourpicker.html', 'b2bTemplate/hourPicker/b2bHourpickerPanel.html', 'b2bTemplate/hourPicker/b2bHourpickerValue.html', 'b2bTemplate/leftNavigation/leftNavigation.html', 'b2bTemplate/listbox/listbox.html', 'b2bTemplate/modalsAndAlerts/b2b-backdrop.html', 'b2bTemplate/modalsAndAlerts/b2b-window.html', 'b2bTemplate/monthSelector/monthSelector-popup.html', 'b2bTemplate/monthSelector/monthSelector.html', 'b2bTemplate/monthSelector/monthSelectorLink.html', 'b2bTemplate/pagination/b2b-pagination.html', 'b2bTemplate/paneSelector/paneSelector.html', 'b2bTemplate/paneSelector/paneSelectorPane.html', 'b2bTemplate/profileCard/profileCard-addUser.html', 'b2bTemplate/profileCard/profileCard.html', 'b2bTemplate/searchField/searchField.html', 'b2bTemplate/seekBar/seekBar.html', 'b2bTemplate/slider/slider.html', 'b2bTemplate/spinButton/spinButton.html', 'b2bTemplate/statusTracker/statusTracker.html', 'b2bTemplate/stepTracker/stepTracker.html', 'b2bTemplate/switches/switches-spanish.html', 'b2bTemplate/switches/switches.html', 'b2bTemplate/tableMessages/tableMessage.html', 'b2bTemplate/tables/b2bTable.html', 'b2bTemplate/tables/b2bTableBody.html', 'b2bTemplate/tables/b2bTableHeaderSortable.html', 'b2bTemplate/tables/b2bTableHeaderUnsortable.html', 'b2bTemplate/tableScrollbar/tableScrollbar.html', 'b2bTemplate/tabs/b2bTab.html', 'b2bTemplate/tabs/b2bTabset.html', 'b2bTemplate/treeNav/groupedTree.html', 'b2bTemplate/treeNav/treeMember.html', 'b2bTemplate/treeNav/ungroupedTree.html', 'b2bTemplate/treeNodeCheckbox/groupedTree.html', 'b2bTemplate/treeNodeCheckbox/treeMember.html', 'b2bTemplate/treeNodeCheckbox/ungroupedTree.html']);angular.module("b2b.att", ["b2b.att.tpls", 'b2b.att.addressInputTemplate','b2b.att.arrows','b2b.att.audioPlayer','b2b.att.audioRecorder','b2b.att.backToTop','b2b.att.badgesForAlerts','b2b.att.boardstrip','b2b.att.bootstrapGridTemplate','b2b.att.breadcrumbs','b2b.att.buttonGroups','b2b.att.buttons','b2b.att.calendar','b2b.att.checkboxes','b2b.att.coachmark','b2b.att.configurationSection','b2b.att.directoryListingTemplate','b2b.att.dropdowns','b2b.att.fileUpload','b2b.att.filters','b2b.att.flyout','b2b.att.footer','b2b.att.header','b2b.att.headingsAndCopy','b2b.att.horizontalTable','b2b.att.hourPicker','b2b.att.inputTemplate','b2b.att.leftNavigation','b2b.att.links','b2b.att.listbox','b2b.att.loaderAnimation','b2b.att.messageWrapper','b2b.att.modalsAndAlerts','b2b.att.monthSelector','b2b.att.multiLevelNavigation','b2b.att.multipurposeExpander','b2b.att.notesMessagesAndErrors','b2b.att.notificationCardTemplate','b2b.att.orderConfirmationTemplate','b2b.att.pagination','b2b.att.paneSelector','b2b.att.phoneNumberInput','b2b.att.profileBlockTemplate','b2b.att.profileCard','b2b.att.radios','b2b.att.searchField','b2b.att.seekBar','b2b.att.separators','b2b.att.slider','b2b.att.spinButton','b2b.att.staticRouteTemplate','b2b.att.statusTracker','b2b.att.stepTracker','b2b.att.switches','b2b.att.tableDragAndDrop','b2b.att.tableMessages','b2b.att.tables','b2b.att.tableScrollbar','b2b.att.tabs','b2b.att.tagBadges','b2b.att.textArea','b2b.att.timeInputField','b2b.att.tooltipsForForms','b2b.att.treeNav','b2b.att.treeNodeCheckbox','b2b.att.utilities']);/**
3  * @ngdoc directive
4  * @name Template.att:Address Input
5  *
6  * @description
7  *  <file src="src/addressInputTemplate/docs/readme.md" />
8  *
9  * @usage
10
11  *
12  * @example
13  *  <section id="code">   
14  <example module="b2b.att">
15  <file src="src/addressInputTemplate/docs/demo.html" />
16  <file src="src/addressInputTemplate/docs/demo.js" />
17  </example>
18  </section>
19  *
20  */
21 angular.module('b2b.att.addressInputTemplate', ['ngMessages']);
22 /**
23  * @ngdoc directive
24  * @name Buttons, links & UI controls.att:arrows
25  *
26  * @description
27  *  <file src="src/arrows/docs/readme.md" />
28  *
29  * @usage
30  *   Please refer demo.html tab in Example section below.
31  *
32  * @example
33  *  <section id="code">
34         <example module="b2b.att">
35             <file src="src/arrows/docs/demo.html" />
36             <file src="src/arrows/docs/demo.js" />
37        </example>
38     </section>
39  *
40  */
41 angular.module('b2b.att.arrows', []);
42 /**
43  * @ngdoc directive
44  * @name Videos, audio & animation.att:Audio Player
45  * @scope
46  * @param {string} audioSrcUrl - MP3 audio source URL or Blob URL
47  * @description
48  *  <file src="src/audioPlayer/docs/readme.md" />
49  *
50  * @usage
51  * 
52  <div b2b-audio audio-src-url='audioSrcUrl'></div>
53  *
54  * @example
55  *  <section id="code">
56         <example module="b2b.att">
57             <file src="src/audioPlayer/docs/demo.html" />
58             <file src="src/audioPlayer/docs/demo.js" />
59        </example>
60     </section>
61  *
62  */
63  
64 angular.module('b2b.att.audioPlayer', ['b2b.att.utilities', 'b2b.att.seekBar'])
65         .constant('AudioPlayerConfig', {
66                 'defaultVolume': 50,
67                 'timeShiftInSeconds': 5
68         })
69         .filter('trustedAudioUrl', ['$sce', function ($sce) {
70                 return function (audioFileFullPath) {
71                         return audioFileFullPath ? $sce.trustAsResourceUrl(audioFileFullPath) : 'undefined';
72                 };
73         }])
74         .directive('b2bAudio', ['$log', '$timeout', 'AudioPlayerConfig', '$compile', 'events', function ($log, $timeout, AudioPlayerConfig, $compile, events) {
75                 return {
76                         restrict: 'EA',
77                         replace: true,
78                         scope: {
79                                 audioSrcUrl: '='
80                         },
81                         templateUrl: 'b2bTemplate/audioPlayer/audioPlayer.html',
82                         controller: function ($scope) {
83
84                                 $scope.audio = {};
85
86                                 if (!angular.isDefined($scope.audioSrcUrl)) {
87                                         $log.warn('b2b-audio : audio-src-url undefined');
88                                         $scope.audioSrcUrl = undefined;
89                                         $scope.audio.mp3 = undefined;
90                                 }
91
92                         },
93                         link: function (scope, element) {
94                                 var audioElement = angular.element(element[0].querySelector('audio'))[0];
95                                 scope.audio.audioElement = audioElement;
96                                 
97                                 function setAttributes(element, attributes) {
98                                         Object.keys(attributes).forEach(function (name) {
99                                                 element.setAttribute(name, attributes[name]);
100                                         });
101                                 }
102
103                                 $timeout(function () {
104                                         // TODO: Replace with DDA Tooltip
105                                         var seekBarKnob = element[0].querySelector('.b2b-seek-bar-knob');
106                                         var tooltipObject = {
107                                                 'tooltip': '{{timeFormatter(audio.currentTime)}}',
108                                                 'tooltip-placement': 'above',
109                                                 'tooltip-style': 'blue',
110                                                 'tooltip-trigger': 'mousedown',
111                                                 'tooltip-append-to-body': 'false',
112                                                 'tooltip-offset': '-10',
113                                                 'refer-by': 'seek-bar-tooltip'
114                                         };
115                                         setAttributes(seekBarKnob, tooltipObject);
116                                         $compile(seekBarKnob)(scope);
117                                 });
118
119                                 if (angular.isDefined(scope.audioSrcUrl)) {
120                                         scope.audio.mp3 = scope.audioSrcUrl;
121                                 }
122
123                                 scope.audio.currentTime = 0;
124                                 scope.audio.currentVolume = AudioPlayerConfig.defaultVolume;
125                                 scope.audio.timeShiftInSeconds = AudioPlayerConfig.timeShiftInSeconds;
126                                 scope.isPlayInProgress = false;
127                                 scope.isReady = false;
128                                 scope.isAudioDragging = false;
129
130                                 $timeout(function () {
131                                         audioElement.load();
132                                         audioElement.volume = scope.audio.currentVolume / 100;
133                                 });
134
135                                 scope.$watch('audioSrcUrl', function (newVal, oldVal) {
136                                         if (newVal !== oldVal) {
137                                                 if (!newVal) {
138                                                         $log.warn('b2b-audio : audio-src-url undefined. Please provide a valid URL');
139                                                 }
140                                                 
141                                                 scope.audio.mp3 = newVal;
142                                                 $timeout(function () {
143                                                         audioElement.load();
144                                                 });
145                                         }
146                                 });
147
148                                 scope.playAudio = function () {
149                                         if (scope.isReady) {
150                                                 audioElement.play();
151                                         }
152                                 };
153
154                                 audioElement.onplay = function () {
155                                         scope.isPlayInProgress = true;
156                                         scope.$digest();
157                                 };
158
159                                 scope.pauseAudio = function () {
160                                         audioElement.pause();
161                                 };
162
163                                 audioElement.onpause = function () {
164                                         scope.isPlayInProgress = false;
165                                         scope.$digest();
166                                 };
167
168                                 scope.toggleAudio = function () {
169                                         if (audioElement.paused) {
170                                                 scope.playAudio();
171                                         } else {
172                                                 scope.pauseAudio();
173                                         }
174                                 };
175
176                                 scope.volumeUp = function (delta) {
177                                         if (!delta) {
178                                                 delta = 0.1;
179                                         } else {
180                                                 delta = delta / 100;
181                                         }
182                                         audioElement.muted = false;
183                                         if (audioElement.volume < 1) {
184                                                 audioElement.volume = Math.min((Math.round((audioElement.volume + delta) * 100) / 100), 1);
185                                         }
186                                         scope.audio.currentVolume = audioElement.volume * 100;
187                                         return audioElement.volume;
188                                 };
189
190                                 scope.volumeDown = function (delta) {
191                                         if (!delta) {
192                                                 delta = 0.1;
193                                         } else {
194                                                 delta = delta / 100;
195                                         }
196                                         audioElement.muted = false;
197                                         if (audioElement.volume > 0) {
198                                                 audioElement.volume = Math.max((Math.round((audioElement.volume - delta) * 100) / 100), 0);
199                                         }
200                                         scope.audio.currentVolume = audioElement.volume * 100;
201                                         return audioElement.volume;
202                                 };
203
204                                 var volumeHandler = function (e) {
205                                         events.preventDefault(e);
206                                         if ((e.wheelDelta && e.wheelDelta > 0) || (e.detail && e.detail < 0)) {
207                                                 scope.volumeUp();
208                                         } else {
209                                                 scope.volumeDown();
210                                         }
211                                         scope.$digest();
212                                 };
213
214                                 
215
216                                 scope.$watch('audio.currentVolume', function (newVal, oldVal) {
217                                         if (newVal !== oldVal) {
218                                                 audioElement.volume = newVal / 100;
219                                         }
220                                 });
221
222                                 scope.setCurrentTime = function (timeInSec) {
223                                         audioElement.currentTime = timeInSec;
224                                 };
225
226                                 scope.setAudioPosition = function (val) {
227                                         if (scope.isReady) {
228                                                 scope.setCurrentTime(val);
229                                                 scope.isAudioDragging = false;
230                                         }
231                                 };
232
233                                 function getTimestampArray(timestamp) {
234                                         var d = Math.abs(timestamp) / 1000; // delta
235                                         var r = {}; // result
236                                         var s = { // structure
237                                                 day: 86400,
238                                                 hour: 3600,
239                                                 minute: 60,
240                                                 second: 1
241                                         };
242
243                                         Object.keys(s).forEach(function (key) {
244                                                 r[key] = Math.floor(d / s[key]);
245                                                 d -= r[key] * s[key];
246                                         });
247
248                                         return r;
249                                 };
250
251                                 scope.timeFormatter = function (timeInSec) {
252                                         var formattedTime = '00:00';
253
254                                         if (!timeInSec || timeInSec < 1) {
255                                                 return formattedTime;
256                                         }
257
258                                         if (typeof timeInSec === 'string') {
259                                                 return timeInSec;
260                                         }
261
262                                         var dateArray = getTimestampArray(timeInSec * 1000);
263                                         Object.keys(dateArray).forEach(function (key) {
264                                                 if (dateArray[key] === 0) {
265                                                         dateArray[key] = '00';
266                                                 } else if (dateArray[key] < 10) {
267                                                         dateArray[key] = '0' + dateArray[key];
268                                                 }
269                                         });
270
271                                         formattedTime = dateArray['minute'] + ':' + dateArray['second'];
272
273                                         if (dateArray['hour'] !== '00') {
274                                                 formattedTime = dateArray['hour'] + ':' + formattedTime;
275                                         }
276
277                                         if (dateArray['day'] !== '00') {
278                                                 formattedTime = dateArray['day'] + ':' + formattedTime;
279                                         }
280
281                                         return formattedTime;
282                                 };
283
284                                 audioElement.onloadedmetadata = function () {
285                                         scope.audio.duration = audioElement.duration;
286                                         scope.$digest();
287                                 };
288
289                                 audioElement.ontimeupdate = function () {
290                                         if (!scope.isAudioDragging) {
291                                                 scope.audio.currentTime = audioElement.currentTime;
292                                                 scope.$digest();
293                                         }
294                                 };
295
296                                 audioElement.onended = function () {
297                                         scope.setCurrentTime(0);
298                                         scope.audio.currentTime = 0;
299                                         if (!audioElement.paused) {
300                                                 scope.pauseAudio();
301                                         }
302                                         scope.$digest();
303                                 };
304
305                                 audioElement.oncanplay = function () {
306                                         scope.isReady = true;
307                                         scope.isPlayInProgress = !audioElement.paused;
308                                         scope.$digest();
309                                 };
310
311                                 var onloadstart = function () {
312                                         scope.isReady = false;
313                                         scope.isPlayInProgress = !audioElement.paused;
314                                         scope.audio.currentTime = 0;
315                                         scope.audio.duration = 0;
316                                         scope.$digest();
317                                 };
318                                 audioElement.addEventListener("loadstart", onloadstart);
319                         }
320                 };
321         }]);
322 /**
323  * @ngdoc directive
324  * @name Videos, audio & animation.att:Audio Recorder
325  * @scope
326  * @param {function} callback - A callback to handle the WAV blob
327  * @param {object} config - A config object with properties startRecordingMessage & whileRecordingMessage
328  * @description
329  *  <file src="src/audioRecorder/docs/readme.md" />
330  *
331  *
332  * @example
333  *  <section id="code">
334         <example module="b2b.att">
335             <file src="src/audioRecorder/docs/demo.html" />
336             <file src="src/audioRecorder/docs/demo.js" />
337        </example>
338     </section>
339  *
340  */
341 angular.module('b2b.att.audioRecorder', ['b2b.att.utilities'])
342     .constant('AudioRecorderConfig', {
343         'startRecordingMessage': 'Click on REC icon to being recording',
344         'whileRecordingMessage': 'Recording...'
345     })
346     .directive('b2bAudioRecorder', ['$interval', 'AudioRecorderConfig', 'b2bUserAgent', 'b2bRecorder', function($interval, AudioRecorderConfig, b2bUserAgent, b2bRecorder) {
347         return {
348             restrict: 'EA',
349             replace: true,
350             scope: {
351                 callback: '&'
352             },
353             templateUrl: 'b2bTemplate/audioRecorder/audioRecorder.html',
354             controller: function($scope) {
355
356                 function hasGetUserMedia() {
357                     return !!(navigator.getUserMedia || navigator.webkitGetUserMedia ||
358                         navigator.mozGetUserMedia || navigator.msGetUserMedia);
359                 }
360
361                 if (!hasGetUserMedia()) {
362                     throw new Error('Your broswer does not support MediaRecorder API');
363                 }
364
365                 if (!(b2bUserAgent.isFF() || b2bUserAgent.isChrome())) {
366                                         throw new Error('b2bAudioRecorder does not support this browser!');
367                                 }
368
369             },
370             link: function(scope, element) {
371                 scope.elapsedTime = 0;
372                 scope.isRecording = false;
373                 scope.config = {};
374                 scope.config.startRecordingMessage = AudioRecorderConfig.startRecordingMessage;
375                 scope.config.whileRecordingMessage = AudioRecorderConfig.whileRecordingMessage;
376                 
377
378                 var timer = undefined; // Interval promise
379                 navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
380                 var stream;
381                 var audio = angular.element(element[0].querySelector('audio'))[0];
382                 var recorder = undefined;
383
384                 function startRecording() {
385                     scope.isRecording = true;
386                     navigator.mediaDevices.getUserMedia({
387                         audio: true
388                     }).then(function(stream) {
389                         //create the MediaStreamAudioSourceNode
390                         context = new AudioContext();
391                         source = context.createMediaStreamSource(stream);
392                         recorder = new b2bRecorder(source);
393                         recorder.record();
394
395                         timer = $interval(function() {
396                             scope.elapsedTime += 1;
397                         }, 1000, 0);
398                     }).catch(function(err) {
399                         angular.noop();
400                     });
401
402                 };
403
404                 function stopRecording() {
405                     scope.isRecording = false;
406                     recorder.stop();
407                     var audio = {};
408                     recorder.exportWAV(function(s) {
409                         audio.src = window.URL.createObjectURL(s);
410                         context.close().then(function() {
411                                 if (timer) {
412                                         $interval.cancel(timer);
413                                     }
414                                     scope.elapsedTime = 0;
415                                     
416                                     recorder.clear();
417                                     recorder = undefined;
418                             });
419                             if (angular.isFunction(scope.callback)){
420                                                         scope.callback({'data': audio});        
421                                                 }
422                     });
423                     
424                     
425                 }
426
427                 scope.toggleRecording = function() {
428                     if (scope.isRecording) {
429                         stopRecording();
430                     } else {
431                         startRecording();
432                     }
433                 };
434
435
436
437                 //TODO: Move this into utilities
438                 function getTimestampArray(timestamp) {
439                     var d = Math.abs(timestamp) / 1000; // delta
440                     var r = {}; // result
441                     var s = { // structure
442                         day: 86400,
443                         hour: 3600,
444                         minute: 60,
445                         second: 1
446                     };
447
448                     Object.keys(s).forEach(function(key) {
449                         r[key] = Math.floor(d / s[key]);
450                         d -= r[key] * s[key];
451                     });
452
453                     return r;
454                 };
455                 scope.timeFormatter = function(timeInSec) {
456                     var formattedTime = '00:00';
457
458                     if (!timeInSec || timeInSec < 1) {
459                         return formattedTime;
460                     }
461
462                     if (typeof timeInSec === 'string') {
463                         return timeInSec;
464                     }
465
466                     var dateArray = getTimestampArray(timeInSec * 1000);
467                     Object.keys(dateArray).forEach(function(key) {
468                         if (dateArray[key] === 0) {
469                             dateArray[key] = '00';
470                         } else if (dateArray[key] < 10) {
471                             dateArray[key] = '0' + dateArray[key];
472                         }
473                     });
474
475                     formattedTime = dateArray['minute'] + ':' + dateArray['second'];
476
477                     if (dateArray['hour'] !== '00') {
478                         formattedTime = dateArray['hour'] + ':' + formattedTime;
479                     }
480
481                     if (dateArray['day'] !== '00') {
482                         formattedTime = dateArray['day'] + ':' + formattedTime;
483                     }
484
485                     return formattedTime;
486                 };
487
488                 scope.$on('$destroy', function() {
489                     if (timer) {
490                         $interval.cancel(timer);
491                     }
492                 });
493             }
494         };
495     }]);
496
497 /**
498  * @ngdoc directive
499  * @name Navigation.att:Back To Top
500  * @scope
501  * @description
502  *  <file src="src/backToTop/docs/readme.md" />
503  * @param {integer} scrollSpeed - Scroll speed in seconds, default is 1
504 *
505  * @usage
506  * 
507         <div ng-controller="backToTopController">
508                 <div b2b-backtotop></div>
509         </div>
510  * 
511  * @example
512  *  <section id="code">
513         <example module="b2b.att">
514             <file src="src/backToTop/docs/demo.html" />
515             <file src="src/backToTop/docs/demo.js" />
516        </example>
517     </section>
518  *
519  */
520  
521 angular.module('b2b.att.backToTop', ['b2b.att.utilities','b2b.att.position'])
522         .directive('b2bBacktotopButton', [function () {
523                 return {
524                         restrict: 'EA',
525                         replace: true,
526                         templateUrl: 'b2bTemplate/backToTop/backToTop.html',
527                         link: function (scope, elem, attr) {
528                                 elem.bind('click', function(evt) {
529                                         var scrollSpeed = parseInt(attr.scrollSpeed) || 1;
530                     TweenLite.to(window, scrollSpeed, {scrollTo:{x: 0, y: 0}});
531                 });
532                         }
533                 };
534         }]);
535 /**
536  * @ngdoc directive
537  * @name Messages, modals & alerts.att:badgesForAlerts
538  *
539  * @description
540  *  <file src="src/badgesForAlerts/docs/readme.md" />
541  * @example
542  *  <section id="code">
543         <example module="b2b.att">
544             <file src="src/badgesForAlerts/docs/demo.html" />
545             <file src="src/badgesForAlerts/docs/demo.js" />
546        </example>
547         </section>
548  *
549  */
550 angular.module('b2b.att.badgesForAlerts', []);
551 /**
552  * @ngdoc directive
553  * @name Misc.att:boardstrip
554  *
555  * @description
556  *  <file src="src/boardstrip/docs/readme.md" />
557  *
558  * @usage
559  * See demo section
560  * @example
561     <section id="code">
562         <b>HTML + AngularJS</b>
563         <example module="b2b.att">
564             <file src="src/boardstrip/docs/demo.html" />
565             <file src="src/boardstrip/docs/demo.js" />
566         </example>
567     </section>
568  */
569 angular.module('b2b.att.boardstrip', ['b2b.att.utilities'])
570         .constant('BoardStripConfig', {
571                 'maxVisibleBoards': 4,
572                 'boardsToScroll': 1,
573                 /* These parameters are non-configurable and remain unaltered, until there is a change in corresponding CSS */
574                 'boardLength': 140,
575                 'boardMargin': 15
576         })
577         .directive('b2bBoard', [function () {
578                 return {
579                         restrict: 'AE',
580                         replace: true,
581                         transclude: true,
582                         require: '^b2bBoardStrip',
583                         scope: {
584                                 boardIndex: '=',
585                                 boardLabel: '='
586                         },
587                         templateUrl: 'b2bTemplate/boardstrip/b2bBoard.html',
588                         link: function (scope, element, attrs, ctrls) {
589
590                                 var parentCtrl = ctrls;
591
592                                 scope.getCurrentIndex = function () {
593                                         return parentCtrl.getCurrentIndex();
594                                 };
595                                 scope.selectBoard = function (boardIndex) {
596                                         if (!isNaN(boardIndex)) {
597                                                 parentCtrl.setCurrentIndex(boardIndex);
598                                         }
599                                 };
600                         }
601                 };
602         }])
603         .directive('b2bBoardStrip', ['BoardStripConfig', '$timeout', function (BoardStripConfig, $timeout) {
604                 return {
605                         restrict: 'AE',
606                         replace: true,
607                         transclude: true,
608                         require: ['?ngModel', 'b2bBoardStrip'],
609                         scope: {
610                                 boardsMasterArray: '=',
611                                 onAddBoard: '&?'
612                         },
613                         templateUrl: 'b2bTemplate/boardstrip/b2bBoardstrip.html',
614                         controller: function ($scope) {
615                                 if (!angular.isDefined($scope.boardsMasterArray)) {
616                                         $scope.boardsMasterArray = [];
617                                 }
618
619                                 this.rectifyMaxVisibleBoards = function () {
620                                         if (this.maxVisibleIndex >= $scope.boardsMasterArray.length) {
621                                                 this.maxVisibleIndex = $scope.boardsMasterArray.length - 1;
622                                         }
623
624                                         if (this.maxVisibleIndex < 0) {
625                                                 this.maxVisibleIndex = 0;
626                                         }
627                                 };
628
629                                 this.resetBoardStrip = function () {
630                                         $scope.currentIndex = 0;
631
632                                         this.maxVisibleIndex = BoardStripConfig.maxVisibleBoards - 1;
633                                         this.minVisibleIndex = 0;
634
635                                         this.rectifyMaxVisibleBoards();
636                                 };
637
638                                 this.getCurrentIndex = function () {
639                                         return $scope.currentIndex;
640                                 };
641                                 this.setCurrentIndex = function (indx) {
642                                         $scope.currentIndex = indx;
643                                 };
644
645                                 this.getBoardsMasterArrayLength = function () {
646                                         return $scope.boardsMasterArray.length;
647                                 };
648
649                                 $scope.addBoardPressedFlag = false;
650                                 this.getAddBoardPressedFlag = function () {
651                                         return $scope.addBoardPressedFlag;
652                                 };
653                                 this.setAddBoardPressedFlag = function (booleanValue) {
654                                         $scope.addBoardPressedFlag = booleanValue;
655                                 };
656
657                         },
658                         link: function (scope, element, attrs, ctrls) {
659
660                                 var ngModelCtrl = ctrls[0];
661                                 var ctrl = ctrls[1];
662
663                                 var oldTimeout;
664                                 var animationTimeout = 1000;
665
666                                 var getBoardViewportWidth = function (numberOfVisibleBoards) {
667                                         return numberOfVisibleBoards * (BoardStripConfig.boardLength + BoardStripConfig.boardMargin);
668                                 };
669                                 if (element[0].querySelector(".board-viewport")) {
670                                         angular.element(element[0].querySelector(".board-viewport")).css({
671                                                 "width": getBoardViewportWidth(BoardStripConfig.maxVisibleBoards) + "px"
672                                         });
673                                 }
674
675                                 var getBoardstripContainerWidth = function (totalNumberOfBoards) {
676                                         return totalNumberOfBoards * (BoardStripConfig.boardLength + BoardStripConfig.boardMargin);
677                                 };
678                                 if (element[0].querySelector(".boardstrip-container")) {
679                                         angular.element(element[0].querySelector(".boardstrip-container")).css({
680                                                 "width": getBoardstripContainerWidth(ctrl.getBoardsMasterArrayLength()) + "px"
681                                         });
682                                         angular.element(element[0].querySelector(".boardstrip-container")).css({
683                                                 "left": "0px"
684                                         });
685                                 }
686
687                                 var calculateAndGetBoardstripContainerAdjustment = function () {
688
689                                         var calculatedAdjustmentValue;
690
691                                         if (ctrl.getBoardsMasterArrayLength() <= BoardStripConfig.maxVisibleBoards) {
692                                                 calculatedAdjustmentValue = 0;
693                                         } else {
694                                                 calculatedAdjustmentValue = (ctrl.minVisibleIndex * (BoardStripConfig.boardLength + BoardStripConfig.boardMargin)) * -1;
695                                         }
696
697                                         return calculatedAdjustmentValue;
698                                 };
699
700                                 var animateBoardstripContainerAdjustment = function (elementToFocusAfterAnimation) {
701                                         var oldContainerAdjustment = angular.element(element[0].querySelector(".boardstrip-container"))[0].style.left;
702                                         var containerAdjustment = calculateAndGetBoardstripContainerAdjustment();
703                                         if (oldContainerAdjustment !== containerAdjustment + 'px') {
704                                                 angular.element(element[0].querySelector(".boardstrip-container")).css({
705                                                         "left": containerAdjustment + "px"
706                                                 });
707
708                                                 $timeout.cancel(oldTimeout);
709                                                 oldTimeout = $timeout(function () {
710                                                         elementToFocusAfterAnimation.focus();
711                                                 }, animationTimeout);
712                                         } else {
713                                                 elementToFocusAfterAnimation.focus();
714                                         }
715                                 };
716
717                                 var updateBoardsTabIndex = function (boardArray, minViewIndex, maxViewIndex) {
718                                         for (var i = 0; i < boardArray.length; i++) {
719                                                 angular.element(boardArray[i]).attr('tabindex', '-1');
720                                         }
721                                         for (var j = minViewIndex; j <= maxViewIndex; j++) {
722                                                 angular.element(boardArray[j]).attr('tabindex', '0');
723                                         }
724                                 };
725
726                                 $timeout(function () {
727                                         var currentBoardArray = element[0].querySelectorAll('[b2b-board]');
728                                         updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
729                                 });
730
731                                 scope.$watchCollection('boardsMasterArray', function (newVal, oldVal) {
732                                         if (newVal !== oldVal) {
733                                                 /* When a board is removed */
734                                                 if (newVal.length < oldVal.length) {
735                                                         ctrl.resetBoardStrip();
736                                                         $timeout(function () {
737
738                                                                 var currentBoardArray = element[0].querySelectorAll('[b2b-board]');
739                                                                 if (currentBoardArray.length !== 0) {
740                                                                         animateBoardstripContainerAdjustment(currentBoardArray[0]);
741                                                                 } else {
742                                                                         element[0].querySelector('div.boardstrip-item--add').focus();
743                                                                 }
744
745                                                                 angular.element(element[0].querySelector(".boardstrip-container")).css({
746                                                                         "width": getBoardstripContainerWidth(ctrl.getBoardsMasterArrayLength()) + "px"
747                                                                 });
748                                                                 /* Update tabindecies to ensure keyboard navigation behaves correctly */
749                                                                 updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
750                                                         });
751                                                 }
752                                                 /* When a board is added */
753                                                 else {
754                                                         if (ctrl.getAddBoardPressedFlag()) {
755                                                                 ctrl.maxVisibleIndex = ctrl.getBoardsMasterArrayLength() - 1;
756                                                                 ctrl.minVisibleIndex = Math.max(ctrl.maxVisibleIndex - BoardStripConfig.maxVisibleBoards + 1, 0);
757
758                                                                 ctrl.setCurrentIndex(ctrl.maxVisibleIndex);
759
760                                                                 $timeout(function () {
761                                                                         angular.element(element[0].querySelector(".boardstrip-container")).css({
762                                                                                 "width": getBoardstripContainerWidth(ctrl.getBoardsMasterArrayLength()) + "px"
763                                                                         });
764
765                                                                         var currentBoardArray = element[0].querySelectorAll('[b2b-board]');
766                                                                         animateBoardstripContainerAdjustment(currentBoardArray[currentBoardArray.length - 1]);
767                                                                         /* Update tabindecies to ensure keyboard navigation behaves correctly */
768                                                                         updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
769                                                                 });
770                                                         } else {
771                                                                 if (ctrl.minVisibleIndex === 0 && ctrl.getBoardsMasterArrayLength() < BoardStripConfig.maxVisibleBoards + 1) {
772                                                                         ctrl.maxVisibleIndex = ctrl.getBoardsMasterArrayLength() - 1;
773                                                                         ctrl.rectifyMaxVisibleBoards();
774                                                                 }
775
776                                                                 $timeout(function () {
777                                                                         angular.element(element[0].querySelector(".boardstrip-container")).css({
778                                                                                 "width": getBoardstripContainerWidth(ctrl.getBoardsMasterArrayLength()) + "px"
779                                                                         });
780
781                                                                         var currentBoardArray = element[0].querySelectorAll('[b2b-board]');
782                                                                         /* Update tabindecies to ensure keyboard navigation behaves correctly */
783                                                                         updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
784                                                                 });
785                                                         }
786
787                                                         ctrl.setAddBoardPressedFlag(false);
788                                                 }
789                                         }
790                                 });
791
792                                 scope.nextBoard = function () {
793                                         ctrl.maxVisibleIndex += BoardStripConfig.boardsToScroll;
794                                         ctrl.rectifyMaxVisibleBoards();
795                                         ctrl.minVisibleIndex = ctrl.maxVisibleIndex - (BoardStripConfig.maxVisibleBoards - 1);
796
797                                         $timeout.cancel(oldTimeout);
798                                         angular.element(element[0].querySelector(".boardstrip-container")).css({
799                                                 "left": calculateAndGetBoardstripContainerAdjustment() + "px"
800                                         });
801
802                                         $timeout(function () {
803                                                 var currentBoardArray = element[0].querySelectorAll('[b2b-board]');
804
805                                                 /* Remove tabindex from non-visible boards */
806                                                 updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
807
808                                                 if (!(scope.isNextBoard())) {
809                                                         try {
810                                                                 currentBoardArray[currentBoardArray.length - 1].focus();
811                                                         } catch (e) { /* IE8 may throw exception */ }
812                                                 }
813                                         }, animationTimeout);
814                                 };
815                                 scope.prevBoard = function () {
816
817                                         ctrl.minVisibleIndex -= BoardStripConfig.boardsToScroll;
818                                         if (ctrl.minVisibleIndex < 0) {
819                                                 ctrl.minVisibleIndex = 0;
820                                         }
821
822                                         ctrl.maxVisibleIndex = ctrl.minVisibleIndex + BoardStripConfig.maxVisibleBoards - 1;
823                                         ctrl.rectifyMaxVisibleBoards();
824
825                                         $timeout.cancel(oldTimeout);
826                                         angular.element(element[0].querySelector(".boardstrip-container")).css({
827                                                 "left": calculateAndGetBoardstripContainerAdjustment() + "px"
828                                         });
829
830                                         $timeout(function () {
831                                                 var currentBoardArray = element[0].querySelectorAll('[b2b-board]');
832
833                                                 /* Remove tabindex from non-visible boards */
834                                                 updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
835
836                                                 if (ctrl.minVisibleIndex === 0) {
837                                                         try {
838                                                                 element[0].querySelector('div.boardstrip-item--add').focus();
839                                                         } catch (e) { /* IE8 may throw exception */ }
840                                                 }
841                                         });
842                                 };
843
844                                 scope.isPrevBoard = function () {
845                                         return (ctrl.minVisibleIndex > 0);
846                                 };
847                                 scope.isNextBoard = function () {
848                                         return (ctrl.getBoardsMasterArrayLength() - 1 > ctrl.maxVisibleIndex);
849                                 };
850
851                                 ngModelCtrl.$render = function () {
852                                         if (ngModelCtrl.$viewValue || ngModelCtrl.$viewValue === 0) {
853                                                 var newCurrentIndex = ngModelCtrl.$viewValue;
854
855                                                 if (!(newCurrentIndex = parseInt(newCurrentIndex, 10))) {
856                                                         newCurrentIndex = 0;
857                                                 }
858
859                                                 if (newCurrentIndex <= 0) {
860                                                         ctrl.resetBoardStrip();
861                                                         newCurrentIndex = 0;
862
863                                                         var currentBoardArray = element[0].querySelectorAll('[b2b-board]');
864                                                         if (currentBoardArray.length !== 0) {
865                                                                 animateBoardstripContainerAdjustment(currentBoardArray[0]);
866                                                         } else {
867                                                                 element[0].querySelector('div.boardstrip-item--add').focus();
868                                                         }
869                                                         /* Update tabindecies to ensure keyboard navigation behaves correctly */
870                                                         updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
871                                                 } else if (newCurrentIndex >= ctrl.getBoardsMasterArrayLength()) {
872                                                         ctrl.maxVisibleIndex = ctrl.getBoardsMasterArrayLength() - 1;
873                                                         ctrl.rectifyMaxVisibleBoards();
874                                                         ctrl.minVisibleIndex = Math.max(ctrl.maxVisibleIndex - BoardStripConfig.maxVisibleBoards + 1, 0);
875
876                                                         newCurrentIndex = ctrl.maxVisibleIndex;
877
878                                                         $timeout(function () {
879                                                                 var currentBoardArray = element[0].querySelectorAll('[b2b-board]');
880                                                                 animateBoardstripContainerAdjustment(currentBoardArray[newCurrentIndex]);
881                                                                 /* Update tabindecies to ensure keyboard navigation behaves correctly */
882                                                                 updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
883                                                         });
884                                                 } else {
885
886                                                         if (!(newCurrentIndex >= ctrl.minVisibleIndex && newCurrentIndex <= ctrl.maxVisibleIndex)) {
887                                                                 ctrl.minVisibleIndex = newCurrentIndex;
888                                                                 ctrl.maxVisibleIndex = ctrl.minVisibleIndex + BoardStripConfig.maxVisibleBoards - 1;
889                                                                 ctrl.rectifyMaxVisibleBoards();
890
891                                                                 if (ctrl.getBoardsMasterArrayLength() < BoardStripConfig.maxVisibleBoards) {
892                                                                         ctrl.minVisibleIndex = 0;
893                                                                 } else {
894                                                                         ctrl.minVisibleIndex = Math.max(ctrl.maxVisibleIndex - BoardStripConfig.maxVisibleBoards + 1, 0);
895                                                                 }
896
897                                                                 $timeout(function () {
898                                                                         var currentBoardArray = element[0].querySelectorAll('[b2b-board]');
899                                                                         animateBoardstripContainerAdjustment(currentBoardArray[newCurrentIndex]);
900                                                                         /* Update tabindecies to ensure keyboard navigation behaves correctly */
901                                                                         updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
902                                                                 });
903                                                         }
904                                                 }
905                                                 scope.currentIndex = newCurrentIndex;
906                                                 ngModelCtrl.$setViewValue(newCurrentIndex);
907                                         } else {
908                                                 ctrl.resetBoardStrip();
909                                                 ngModelCtrl.$setViewValue(0);
910                                         }
911                                 };
912
913                                 scope.$watch('currentIndex', function (newVal, oldVal) {
914                                         if (newVal !== oldVal && ngModelCtrl && ngModelCtrl.$viewValue !== newVal) {
915                                                 ngModelCtrl.$setViewValue(newVal);
916                                         }
917                                 });
918                         }
919                 };
920         }])
921         .directive('b2bAddBoard', ['BoardStripConfig', '$parse', function (BoardStripConfig, $parse) {
922                 return {
923                         restrict: 'AE',
924                         replace: true,
925                         require: '^b2bBoardStrip',
926                         scope: {
927                                 onAddBoard: '&?'
928                         },
929                         templateUrl: 'b2bTemplate/boardstrip/b2bAddBoard.html',
930                         link: function (scope, element, attrs, ctrl) {
931                                 scope.addBoard = function () {
932                                         if (attrs['onAddBoard']) {
933                                                 scope.onAddBoard = $parse(scope.onAddBoard);
934                                                 scope.onAddBoard();
935                                                 ctrl.setAddBoardPressedFlag(true);
936                                         }
937                                 };
938                         }
939                 };
940         }])
941         .directive('b2bBoardNavigation', ['keymap', 'events', function (keymap, events) {
942                 return {
943                         restrict: 'AE',
944                         link: function (scope, elem) {
945
946                                 var prevElem = keymap.KEY.LEFT;
947                                 var nextElem = keymap.KEY.RIGHT;
948
949                                 elem.bind('keydown', function (ev) {
950
951                                         if (!(ev.keyCode)) {
952                                                 ev.keyCode = ev.which;
953                                         }
954
955                                         switch (ev.keyCode) {
956                                         case nextElem:
957                                                 events.preventDefault(ev);
958                                                 events.stopPropagation(ev);
959
960                                                 if (elem[0].nextElementSibling && parseInt(angular.element(elem[0].nextElementSibling).attr('tabindex')) >= 0) {
961                                                         angular.element(elem[0])[0].nextElementSibling.focus();
962                                                 } else {
963                                                         /* IE8 fix */
964                                                         var el = angular.element(elem[0])[0];
965                                                         do {
966                                                                 if (el.nextSibling) {
967                                                                         el = el.nextSibling;
968                                                                 } else {
969                                                                         break;
970                                                                 }
971                                                         } while (el && el.tagName !== 'LI');
972
973                                                         if (el.tagName && el.tagName === 'LI' && parseInt(angular.element(el).attr('tabindex')) >= 0) {
974                                                                 el.focus();
975                                                         }
976                                                 }
977
978                                                 break;
979                                         case prevElem:
980                                                 events.preventDefault(ev);
981                                                 events.stopPropagation(ev);
982
983                                                 if (elem[0].previousElementSibling && parseInt(angular.element(elem[0].previousElementSibling).attr('tabindex')) >= 0) {
984                                                         angular.element(elem[0])[0].previousElementSibling.focus();
985                                                 } else {
986                                                         /* IE8 fix */
987                                                         var el1 = angular.element(elem[0])[0];
988                                                         do {
989                                                                 if (el1.previousSibling) {
990                                                                         el1 = el1.previousSibling;
991                                                                 } else {
992                                                                         break;
993                                                                 }
994                                                         } while (el1 && el1.tagName !== 'LI');
995
996                                                         if (el1.tagName && el1.tagName === 'LI' && parseInt(angular.element(el1).attr('tabindex')) >= 0) {
997                                                                 el1.focus();
998                                                         }
999                                                 }
1000                                                 break;
1001                                         default:
1002                                                 break;
1003                                         }
1004                                 });
1005                         }
1006                 };
1007         }]);
1008 /** 
1009  * @ngdoc directive 
1010  * @name Template.att:Bootstrap Grid Template
1011  * 
1012  * @description 
1013  *  <file src="src/bootstrapGridTemplate/docs/readme.md" /> 
1014  * 
1015  * @example 
1016  *  <section id="code">
1017         <example module="b2b.att"> 
1018             <file src="src/bootstrapGridTemplate/docs/demo.html" /> 
1019             <file src="src/bootstrapGridTemplate/docs/demo.js" /> 
1020        </example> 
1021     </section>    
1022  * 
1023  */
1024 angular.module('b2b.att.bootstrapGridTemplate', [])
1025   
1026 /**
1027  * @ngdoc directive
1028  * @name Navigation.att:breadcrumbs
1029  *
1030  * @description
1031  *  <file src="src/breadcrumbs/docs/readme.md" />
1032  * @usage
1033     <ul class="breadcrumb">
1034         <li ng-repeat="link in breadCrumbsLink"><a tabindex="{{(idx==$index)?-1:0}}" href='javascript:void(0)' ng-click="clickActive($index)" ng-class="{'active':idx==$index, '': idx!=$index}">{{link.title}}</a></li>
1035     </ul>
1036  * @example
1037  <example module="b2b.att">
1038  <file src="src/breadcrumbs/docs/demo.html" />
1039  <file src="src/breadcrumbs/docs/demo.js" />
1040  </example>
1041  */
1042 angular.module('b2b.att.breadcrumbs',[])
1043 /**
1044  * @ngdoc directive
1045  * @name Buttons, links & UI controls.att:buttonGroups
1046  *
1047  * @description
1048  *  <file src="src/buttonGroups/docs/readme.md" />
1049  *
1050  * @usage
1051 <h2>Radio Aproach</h2>
1052 <div class="btn-group" b2b-key prev="37,38" next="39,40" circular-traversal role="radiogroup">
1053     <button type="button" class="btn btn-secondary" b2b-key-item ng-focus="radioModel='Button 1'" ng-model="radioModel" b2b-btn-radio="'Button 1'" tabindex="{{(!radioModel || 'Button 1'===radioModel)?0:-1}}">Button 1</button>
1054     <button type="button" class="btn btn-secondary" b2b-key-item ng-focus="radioModel='Button 2'" ng-model="radioModel" b2b-btn-radio="'Button 2'" tabindex="{{(!radioModel || 'Button 2'===radioModel)?0:-1}}">Button 2</button>
1055     <button type="button" class="btn btn-secondary" b2b-key-item ng-focus="radioModel='Button 3'" ng-model="radioModel" b2b-btn-radio="'Button 3'" tabindex="{{(!radioModel || 'Button 3'===radioModel)?0:-1}}">Button 3</button>
1056 </div>
1057
1058 <h2>Checkbox Aproach</h2>
1059 <span b2b-button-group class="btn-group btn-fullwidth" role="group" max-select="3" ng-model="checkModel1">
1060     <button type="button" class="btn btn-secondary" ng-model="checkModel1.Button1" b2b-btn-checkbox>Button1</button>
1061     <button type="button" class="btn btn-secondary" ng-model="checkModel1.Button2" b2b-btn-checkbox>Button2</button>
1062     <button type="button" class="btn btn-secondary" ng-model="checkModel1.Button3" b2b-btn-checkbox>Button3</button>
1063     <button type="button" class="btn btn-secondary" ng-model="checkModel1.Button4" b2b-btn-checkbox>Button4</button>
1064     <button type="button" class="btn btn-secondary" ng-model="checkModel1.Button5" b2b-btn-checkbox>Button5</button>
1065 </span>
1066  *
1067  * @example
1068  *  <section id="code">
1069         <example module="b2b.att">
1070             <file src="src/buttonGroups/docs/demo.html" />
1071             <file src="src/buttonGroups/docs/demo.js" />
1072        </example>
1073         </section>
1074  *
1075  */
1076 angular.module('b2b.att.buttonGroups', ['b2b.att.utilities'])
1077     .constant('buttonConfig', {
1078         activeClass: 'active',
1079         toggleEvent: 'click'
1080     })
1081     .directive('b2bBtnRadio', ['buttonConfig', function (buttonConfig) {
1082         var activeClass = buttonConfig.activeClass || 'active';
1083         var toggleEvent = buttonConfig.toggleEvent || 'click';
1084
1085         return {
1086             require: 'ngModel',
1087             link: function (scope, element, attrs, ngModelCtrl) {
1088                 var notMobile = !/Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
1089
1090                 if (notMobile) {
1091                     element.bind('focus', function () {
1092                         scope.$apply(function () {
1093                             ngModelCtrl.$setViewValue(scope.$eval(attrs.b2bBtnRadio));
1094                             ngModelCtrl.$render();
1095                         });
1096                     });
1097                 }
1098
1099                 element.attr('role', 'radio');
1100
1101                 //model -> UI
1102                 ngModelCtrl.$render = function () {
1103                     element.toggleClass(activeClass, angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.b2bBtnRadio)));
1104                     if (angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.b2bBtnRadio))) {
1105                         element.attr("aria-checked", true);
1106                     } else {
1107                         element.attr("aria-checked", false);
1108                     }
1109                 };
1110
1111                 //ui->model
1112                 element.bind(toggleEvent, function () {
1113                     if (!element.hasClass(activeClass)) {
1114                         scope.$apply(function () {
1115                             ngModelCtrl.$setViewValue(scope.$eval(attrs.b2bBtnRadio));
1116                             ngModelCtrl.$render();
1117                         });
1118                     }
1119                 });
1120             }
1121         };
1122     }])
1123     .directive('b2bBtnCheckbox', ['buttonConfig', function (buttonConfig) {
1124         var activeClass = buttonConfig.activeClass || 'active';
1125         var toggleEvent = buttonConfig.toggleEvent || 'click';
1126
1127         return {
1128             require: ['ngModel', '^^b2bButtonGroup'],
1129             link: function (scope, element, attrs, ctrls) {
1130
1131                 var ngModelCtrl = ctrls[0];
1132                 var parentCtrl = ctrls[1];
1133
1134                 element.attr('role', 'checkbox');
1135                 element.attr('aria-describedby', parentCtrl.getStateDescriptionElemId());
1136
1137                 function getTrueValue() {
1138                     var trueValue = scope.$eval(attrs.b2bBtnCheckboxTrue);
1139                     return angular.isDefined(trueValue) ? trueValue : true;
1140                 }
1141
1142                 function getFalseValue() {
1143                     var falseValue = scope.$eval(attrs.b2bBtnCheckboxFalse);
1144                     return angular.isDefined(falseValue) ? falseValue : false;
1145                 }
1146
1147                 //model -> UI
1148                 ngModelCtrl.$render = function () {
1149                     element.toggleClass(activeClass, angular.equals(ngModelCtrl.$modelValue, getTrueValue()));
1150                     if ((angular.equals(ngModelCtrl.$modelValue, getTrueValue()))) {
1151                         element.attr("aria-checked", true);
1152                     } else {
1153                         element.attr("aria-checked", false);
1154                     }
1155                 };
1156
1157                 //ui->model
1158                 element.bind(toggleEvent, function () {
1159                     scope.$apply(function () {
1160                         ngModelCtrl.$setViewValue(element.hasClass(activeClass) ? getFalseValue() : getTrueValue());
1161                         ngModelCtrl.$render();
1162                     });
1163                 });
1164             }
1165         };
1166     }])
1167     .directive('b2bButtonGroup', ['$timeout', '$compile', function ($timeout, $compile) {
1168         return {
1169             restrict: 'A',
1170             scope: {
1171                 maxSelect: "=",
1172                 ngModelButtonState: '=ngModel'
1173             },
1174             controller: ['$scope', '$element', function ($scope, $element) {
1175                 $scope.nSel = 0;
1176
1177                 var stateDescriptionElem = angular.element('<span id="b2b_button_group_' + $scope.$id + '" class="hide" aria-hidden="true">{{nSel}} of {{maxSelect}} options selected.</span>');
1178                 $compile(stateDescriptionElem)($scope);
1179                 $element.after(stateDescriptionElem);
1180
1181                 this.getStateDescriptionElemId = function () {
1182                     return stateDescriptionElem.attr('id');
1183                 };
1184             }],
1185             link: function (scope, element) {
1186
1187
1188                 var executeFxn = function () {
1189                     scope.nSel = 0;
1190                     angular.forEach(scope.ngModelButtonState, function (value, key) {
1191                         if (value === true) {
1192                             scope.nSel += 1;
1193                         }
1194                     });
1195
1196                     if (scope.nSel >= scope.maxSelect) {
1197                         angular.forEach(element.children(), function (chd) {
1198                             if (chd.className.indexOf('active') < 0) {
1199                                 chd.disabled = true;
1200                                 chd.setAttribute('aria-disabled', true);
1201                             }
1202                         });
1203                     } else {
1204                         angular.forEach(element.children(), function (chd) {
1205                             chd.disabled = false;
1206                             chd.setAttribute('aria-disabled', false);
1207                         });
1208                     }
1209                     scope.$digest();
1210                 };
1211
1212                 $timeout(function () {
1213                     executeFxn();
1214                 });
1215                 element.bind('click', executeFxn);
1216             }
1217         };
1218     }]);
1219 /**
1220  * @ngdoc directive
1221  * @name Buttons, links & UI controls.att:buttons
1222  * @element input
1223  * @function
1224  *
1225  * @description
1226  *  <file src="src/buttons/docs/readme.md" />
1227  * @usage
1228  *
1229 Button shape
1230 <button class="btn" type="button">Button</button> button.btn (button shape only)
1231 <button aria-label="Custom aria label" class="btn" type="button">Button</button> button.btn (button shape only) with custom aria label
1232 <button aria-label="Click on button/Press enter" class="btn" type="button" onclick="javascript:alert('It works!');">Click on button/Press enter</button> button.btn with click functionality
1233 <a b2b-keyup-click="32" href="javascript:void(0)" class="btn" role="button">Button</a> a.btn (button shape only)
1234 <button class="btn btn-primary">Button</button> .btn-primary
1235 <a b2b-keyup-click="32" href="javascript:void(0)" class="btn btn-primary" role="button">Button</a> a.btn-primary
1236
1237 5 Button colors
1238 <button class="btn btn-secondary">Button</button> .btn-secondary
1239 <a b2b-keyup-click="32" href="javascript:void(0)" class="btn btn-secondary" role="button">Button</a> a.btn-secondary
1240 <button class="btn btn-alt">Button</button> .btn-alt
1241 <a b2b-keyup-click="32" href="javascript:void(0)" class="btn btn-alt" role="button">Button</a> a.btn-alt
1242 <button class="btn btn-specialty">Button</button> .btn-specialty
1243 <a b2b-keyup-click="32" href="javascript:void(0)" class="btn btn-specialty" role="button">Button</a> a.btn-specialty
1244 <button class="btn btn-specialty" disabled="">Button</button> disabled="disabled"
1245 <a b2b-keyup-click="32" aria-disabled="true" href="javascript:void(0)" class="btn btn-primary disabled" role="button">Button</a> a.disabled
1246
1247 3 button heights
1248 <button class="btn btn-secondary">Button</button> .btn is default and 46px height
1249 <button class="btn btn-secondary btn-medium">Button</button> .btn-medium is 42px
1250 <button class="btn btn-secondary btn-small">Button</button> .btn-small is 36px
1251
1252 .row-nowrap 2 up buttons
1253 <div class="row-nowrap">
1254     <button class="btn btn-secondary btn-fullwidth" type="button">Cancel</button>
1255     <button class="btn btn-primary btn-fullwidth" type="button">Continue</button>
1256 </div>
1257
1258 .row 2 up buttons (desktop) stacked (mobile) (different order)
1259 <div class="row cta-button-group">
1260     <button class="span btn btn-secondary btn-fullwidth hidden-phone" type="button">Cancel</button>
1261     <button class="span btn btn-primary btn-fullwidth" type="button">Continue</button>
1262     <button class="span btn btn-secondary btn-fullwidth visible-phone" type="button">Cancel</button>
1263 </div>
1264
1265  * @example
1266  *  <section id="code">
1267                <b>HTML + AngularJS</b>
1268  *              <example module="b2b.att">
1269  *              <file src="src/buttons/docs/demo.html" />
1270                  <file src="src/buttons/docs/demo.js" />
1271  *              </example>
1272             </section>
1273  *
1274  */
1275 angular.module('b2b.att.buttons', ['b2b.att.utilities']);
1276 /**
1277  * @ngdoc directive
1278  * @name Forms.att:calendar
1279  *
1280  * @description
1281  *  <file src="src/calendar/docs/readme.md" />
1282  * @usage
1283  *  <input type="text" ng-model="dt" b2b-datepicker>
1284  *
1285  * @example
1286    <section id="code">
1287     <b>HTML + AngularJS</b>
1288     <example module="b2b.att">
1289      <file src="src/calendar/docs/demo.html" />
1290      <file src="src/calendar/docs/demo.js" />
1291     </example>
1292    </section>
1293  */
1294 angular.module('b2b.att.calendar', ['b2b.att.position', 'b2b.att.utilities'])
1295
1296 .constant('b2bDatepickerConfig', {
1297     dateFormat: 'MM/dd/yyyy',
1298     dayFormat: 'd',
1299     monthFormat: 'MMMM',
1300     yearFormat: 'yyyy',
1301     dayHeaderFormat: 'EEEE',
1302     dayTitleFormat: 'MMMM yyyy',
1303     disableWeekend: false,
1304     disableSunday: false,
1305     disableDates: null,
1306     onSelectClose: null,
1307     startingDay: 0,
1308     minDate: null,
1309     maxDate: null,
1310     dueDate: null,
1311     fromDate: null,
1312     legendIcon: null,
1313     legendMessage: null,
1314     calendarDisabled: false,
1315     collapseWait: 0,
1316     orientation: 'right',
1317     inline: false,
1318     helperText: 'The date you selected is $date. In case of mobile double tap to open calendar. Select a date to close the calendar.',
1319     datepickerEvalAttributes: ['dateFormat', 'dayFormat', 'monthFormat', 'yearFormat', 'dayHeaderFormat', 'dayTitleFormat', 'disableWeekend', 'disableSunday', 'startingDay', 'collapseWait', 'orientation'],
1320     datepickerWatchAttributes: ['min', 'max', 'due', 'from', 'legendIcon', 'legendMessage', 'ngDisabled'],
1321     datepickerFunctionAttributes: ['disableDates', 'onSelectClose']
1322 })
1323
1324 .factory('b2bDatepickerService', ['b2bDatepickerConfig', 'dateFilter', function (b2bDatepickerConfig, dateFilter) {
1325     var setAttributes = function (attr, elem) {
1326         if (angular.isDefined(attr) && attr !== null && angular.isDefined(elem) && elem !== null) {
1327             var attributes = b2bDatepickerConfig.datepickerEvalAttributes.concat(b2bDatepickerConfig.datepickerWatchAttributes, b2bDatepickerConfig.datepickerFunctionAttributes);
1328             for (var key in attr) {
1329                 var val = attr[key];
1330                 if (attributes.indexOf(key) !== -1 && angular.isDefined(val)) {
1331                     elem.attr(key.toSnakeCase(), key);
1332                 }
1333             }
1334         }
1335     };
1336
1337     var bindScope = function (attr, scope) {
1338         if (angular.isDefined(attr) && attr !== null && angular.isDefined(scope) && scope !== null) {
1339             var evalFunction = function (key, val) {
1340                 scope[key] = scope.$parent.$eval(val);
1341             };
1342
1343             var watchFunction = function (key, val) {
1344                 scope.$parent.$watch(val, function (value) {
1345                     scope[key] = value;
1346                 });
1347                 scope.$watch(key, function (value) {
1348                     scope.$parent[val] = value;
1349                 });
1350             };
1351
1352             var evalAttributes = b2bDatepickerConfig.datepickerEvalAttributes;
1353             var watchAttributes = b2bDatepickerConfig.datepickerWatchAttributes;
1354             for (var key in attr) {
1355                 var val = attr[key];
1356                 if (evalAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {
1357                     evalFunction(key, val);
1358                 } else if (watchAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {
1359                     watchFunction(key, val);
1360                 }
1361             }
1362         }
1363     };
1364
1365     return {
1366         setAttributes: setAttributes,
1367         bindScope: bindScope
1368     };
1369 }])
1370
1371 .controller('b2bDatepickerController', ['$scope', '$attrs', 'dateFilter', '$element', '$position', 'b2bDatepickerConfig', function ($scope, $attrs, dateFilter, $element, $position, dtConfig) {
1372     var format = {
1373             date: getValue($attrs.dateFormat, dtConfig.dateFormat),
1374             day: getValue($attrs.dayFormat, dtConfig.dayFormat),
1375             month: getValue($attrs.monthFormat, dtConfig.monthFormat),
1376             year: getValue($attrs.yearFormat, dtConfig.yearFormat),
1377             dayHeader: getValue($attrs.dayHeaderFormat, dtConfig.dayHeaderFormat),
1378             dayTitle: getValue($attrs.dayTitleFormat, dtConfig.dayTitleFormat),
1379             disableWeekend: getValue($attrs.disableWeekend, dtConfig.disableWeekend),
1380             disableSunday: getValue($attrs.disableSunday, dtConfig.disableSunday)
1381         },
1382         startingDay = getValue($attrs.startingDay, dtConfig.startingDay);
1383
1384     if($attrs.disableDates !== undefined) {
1385         format.disableDates = $attrs.disableDates;
1386     } else {
1387        format.disableDates =  dtConfig.disableDates;     
1388     }
1389     $scope.minDate = dtConfig.minDate ? $scope.resetTime(dtConfig.minDate) : null;
1390     $scope.maxDate = dtConfig.maxDate ? $scope.resetTime(dtConfig.maxDate) : null;
1391     $scope.dueDate = dtConfig.dueDate ? $scope.resetTime(dtConfig.dueDate) : null;
1392     $scope.fromDate = dtConfig.fromDate ? $scope.resetTime(dtConfig.fromDate) : null;
1393     $scope.legendIcon = dtConfig.legendIcon ? dtConfig.legendIcon : null;
1394     $scope.legendMessage = dtConfig.legendMessage ? dtConfig.legendMessage : null;
1395     $scope.ngDisabled = dtConfig.calendarDisabled ? dtConfig.calendarDisabled : null;
1396     $scope.collapseWait = getValue($attrs.collapseWait, dtConfig.collapseWait);
1397     $scope.orientation = getValue($attrs.orientation, dtConfig.orientation);
1398     $scope.onSelectClose = getValue($attrs.onSelectClose, dtConfig.onSelectClose);
1399
1400     $scope.inline = $attrs.inline === 'true' ? true : dtConfig.inline;
1401
1402     function getValue(value, defaultValue) {
1403         return angular.isDefined(value) ? $scope.$parent.$eval(value) : defaultValue;
1404     }
1405
1406     function getDaysInMonth(year, month) {
1407         return new Date(year, month, 0).getDate();
1408     }
1409
1410     function getDates(startDate, n) {
1411         var dates = new Array(n);
1412         var current = startDate,
1413             i = 0;
1414         while (i < n) {
1415             dates[i++] = new Date(current);
1416             current.setDate(current.getDate() + 1);
1417         }
1418         return dates;
1419     }
1420
1421     this.updatePosition = function (b2bDatepickerPopupTemplate) {
1422         $scope.position = $position.offset($element);
1423         $scope.position.top = $scope.position.top + $element.prop('offsetHeight');
1424         $scope.position.left = $scope.position.left - (((b2bDatepickerPopupTemplate && b2bDatepickerPopupTemplate.prop('offsetWidth')) || 290) - $element.prop('offsetWidth'));
1425     };
1426
1427     this.isDateInRange = function(date) {
1428         if ((compare(date, $scope.minDate) >= 0) && (compare(date, $scope.maxDate) <= 0)) {
1429             return true;
1430         } else  {
1431             return false;
1432         }
1433         return false;
1434     }
1435
1436     this.isDisbaledDate = function(date) {
1437         if ($attrs.from && !angular.isDate($scope.fromDate)) {
1438             return true;
1439         }
1440         if (format.disableWeekend === true && (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday")) {
1441             return true;
1442         }
1443         if (format.disableSunday === true && (dateFilter(date, format.dayHeader) === "Sunday")) {
1444             return true;
1445         }
1446     
1447         return (($scope.minDate && compare(date, $scope.minDate) < 0) || ($scope.maxDate && compare(date, $scope.maxDate) > 0) || ($scope.datesCallBack({
1448             date: date
1449         })));
1450
1451     }
1452     function isSelected(dt) {
1453         if (dt && angular.isDate($scope.currentDate) && compare(dt, $scope.currentDate) === 0) {
1454             return true;
1455         }
1456         return false;
1457     }
1458
1459     function isFromDate(dt) {
1460         if (dt && angular.isDate($scope.fromDate) && compare(dt, $scope.fromDate) === 0) {
1461             return true;
1462         }
1463         return false;
1464     }
1465
1466     function isDateRange(dt) {
1467         if (dt && $scope.fromDate && angular.isDate($scope.currentDate) && (compare(dt, $scope.fromDate) >= 0) && (compare(dt, $scope.currentDate) <= 0)) {
1468             return true;
1469         } else if (dt && $scope.fromDate && compare(dt, $scope.fromDate) === 0) {
1470             return true;
1471         }
1472         return false;
1473     }
1474
1475     function isOld(date, currentMonthDate) {
1476         if (date && currentMonthDate && (new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0).getTime() < new Date(currentMonthDate.getFullYear(), currentMonthDate.getMonth(), 1, 0, 0, 0).getTime())) {
1477             return true;
1478         } else {
1479             return false;
1480         }
1481     }
1482
1483     function isNew(date, currentMonthDate) {
1484         if (date && currentMonthDate && (new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0).getTime() > new Date(currentMonthDate.getFullYear(), currentMonthDate.getMonth(), 1, 0, 0, 0).getTime())) {
1485             return true;
1486         } else {
1487             return false;
1488         }
1489     }
1490
1491     function isPastDue(dt) {
1492         if ($scope.dueDate) {
1493             return (dt > $scope.dueDate);
1494         }
1495         return false;
1496     }
1497
1498     function isDueDate(dt) {
1499         if ($scope.dueDate) {
1500             return (dt.getTime() === $scope.dueDate.getTime());
1501         }
1502         return false;
1503     }
1504
1505     var isDisabled = function (date, currentMonthDate) {
1506         if ($attrs.from && !angular.isDate($scope.fromDate)) {
1507             return true;
1508         }
1509         if (format.disableWeekend === true && (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday")) {
1510             return true;
1511         }
1512         if (format.disableSunday === true && (dateFilter(date, format.dayHeader) === "Sunday")) {
1513             return true;
1514         }
1515         if (isOld(date, currentMonthDate) || isNew(date, currentMonthDate)) {
1516             return true;
1517         }
1518         return (($scope.minDate && compare(date, $scope.minDate) < 0) || ($scope.maxDate && compare(date, $scope.maxDate) > 0) || ($scope.datesCallBack({
1519             date: date
1520         })));
1521     };
1522
1523     var compare = function (date1, date2) {
1524         return (new Date(date1.getFullYear(), date1.getMonth(), date1.getDate()) - new Date(date2.getFullYear(), date2.getMonth(), date2.getDate()));
1525     };
1526
1527     function isMinDateAvailable(startDate, endDate) {
1528         if (($scope.minDate && $scope.minDate.getTime() >= startDate.getTime()) && ($scope.minDate.getTime() <= endDate.getTime())) {
1529             $scope.disablePrev = true;
1530             $scope.visibilityPrev = "hidden";
1531         } else {
1532             $scope.disablePrev = false;
1533             $scope.visibilityPrev = "visible";
1534         }
1535     }
1536
1537     function isMaxDateAvailable(startDate, endDate) {
1538         if (($scope.maxDate && $scope.maxDate.getTime() >= startDate.getTime()) && ($scope.maxDate.getTime() <= endDate.getTime())) {
1539             $scope.disableNext = true;
1540             $scope.visibilityNext = "hidden";
1541         } else {
1542             $scope.disableNext = false;
1543             $scope.visibilityNext = "visible";
1544         }
1545     }
1546
1547     function getLabel(label) {
1548         if (label) {
1549             var labelObj = {
1550                 pre: label.substr(0, 1).toUpperCase(),
1551                 post: label
1552             };
1553             return labelObj;
1554         }
1555         return;
1556     }
1557
1558     function makeDate(date, dayFormat, dayHeaderFormat, isSelected, isFromDate, isDateRange, isOld, isNew, isDisabled, dueDate, pastDue) {
1559         return {
1560             date: date,
1561             label: dateFilter(date, dayFormat),
1562             header: dateFilter(date, dayHeaderFormat),
1563             selected: !!isSelected,
1564             fromDate: !!isFromDate,
1565             dateRange: !!isDateRange,
1566             oldMonth: !!isOld,
1567             nextMonth: !!isNew,
1568             disabled: !!isDisabled,
1569             dueDate: !!dueDate,
1570             pastDue: !!pastDue,
1571             focusable: !((isDisabled && !(isSelected || isDateRange)) || (isOld || isNew))
1572         };
1573     }
1574
1575     this.modes = [
1576         {
1577             name: 'day',
1578             getVisibleDates: function (date) {
1579                 var year = date.getFullYear(),
1580                     month = date.getMonth(),
1581                     firstDayOfMonth = new Date(year, month, 1),
1582                     lastDayOfMonth = new Date(year, month + 1, 0);
1583                 var difference = startingDay - firstDayOfMonth.getDay(),
1584                     numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : -difference,
1585                     firstDate = new Date(firstDayOfMonth),
1586                     numDates = 0;
1587
1588                 if (numDisplayedFromPreviousMonth > 0) {
1589                     firstDate.setDate(-numDisplayedFromPreviousMonth + 1);
1590                     numDates += numDisplayedFromPreviousMonth; // Previous
1591                 }
1592                 numDates += getDaysInMonth(year, month + 1); // Current
1593                 numDates += (7 - numDates % 7) % 7; // Next
1594
1595                 var days = getDates(firstDate, numDates),
1596                     labels = new Array(7);
1597                 for (var i = 0; i < numDates; i++) {
1598                     var dt = new Date(days[i]);
1599                     days[i] = makeDate(dt,
1600                         format.day,
1601                         format.dayHeader,
1602                         isSelected(dt),
1603                         isFromDate(dt),
1604                         isDateRange(dt),
1605                         isOld(dt, date),
1606                         isNew(dt, date),
1607                         isDisabled(dt, date),
1608                         isDueDate(dt),
1609                         isPastDue(dt));
1610                 }
1611                 for (var j = 0; j < 7; j++) {
1612                     labels[j] = getLabel(dateFilter(days[j].date, format.dayHeader));
1613                 }
1614                 isMinDateAvailable(firstDayOfMonth, lastDayOfMonth);
1615                 isMaxDateAvailable(firstDayOfMonth, lastDayOfMonth);
1616                 return {
1617                     objects: days,
1618                     title: dateFilter(date, format.dayTitle),
1619                     labels: labels
1620                 };
1621             },
1622             split: 7,
1623             step: {
1624                 months: 1
1625             }
1626         }
1627     ];
1628 }])
1629
1630 .directive('b2bDatepicker', ['$parse', '$log', '$timeout', '$document', '$documentBind', '$isElement', '$templateCache', '$compile', 'trapFocusInElement', '$position', '$window', '$filter', 'b2bDatepickerConfig', function ($parse, $log, $timeout, $document, $documentBind, $isElement, $templateCache, $compile, trapFocusInElement, $position, $window, $filter, b2bDatepickerConfig) {
1631     return {
1632         restrict: 'EA',
1633         scope: { 
1634             model: '=ngModel',
1635             datesCallBack: '&disableDates',
1636             onSelectClose: '&',
1637             disabledInput: '=?ngDisabled'
1638         },
1639         require: ['b2bDatepicker', 'ngModel', '?^b2bDatepickerGroup'],
1640         controller: 'b2bDatepickerController',
1641         link: function (scope, element, attrs, ctrls) {
1642             var datepickerCtrl = ctrls[0],
1643                 ngModel = ctrls[1],
1644                 b2bDatepickerGroupCtrl = ctrls[2];
1645             var b2bDatepickerPopupTemplate;
1646             var isCalendarOpened = false;
1647             if(scope.disabledInput === undefined || scope.disabledInput === '') {
1648                 scope.disabledInput = false;
1649             } 
1650             if(attrs.inline == 'true'){     
1651                 element.after($compile($templateCache.get('b2bTemplate/calendar/datepicker-popup.html'))(scope));
1652                 var temp = element.after();
1653                 element.remove();
1654                 element = temp; 
1655             } else {
1656                 var buttonTabIndex =  scope.disabledInput===true ? -1 : 0; 
1657
1658                 element.after($compile('<button class="btn-calendar-icon" ng-disabled='+scope.disabledInput+' ><i class="icon-primary-calendar b2b-calendar-icon" aria-haspopup="true" aria-expanded="false" ng-class=\"{\'disabled\': '+scope.disabledInput+'}\" ></i></button>')(scope));
1659                 element.attr('placeholder', 'MM/dd/yyyy');
1660                 element.attr('b2b-format-date', b2bDatepickerConfig.dateFormat); 
1661             }
1662             scope.$watch('model', function(val) {
1663
1664                 if(val !== undefined && val !== '') {
1665                     var date_regex = /^(0[1-9]|1[0-2])\/(0[1-9]|1\d|2\d|3[01])\/(19|20)\d{2}$/ ;
1666
1667                     if(!date_regex.test(element[0].value)) {
1668                         ngModel.$setValidity('datePattern', false);
1669                     } else {    
1670                         ngModel.$setValidity('datePattern', true);
1671                     }
1672                     
1673                 } else {
1674                     ngModel.$setValidity('datePattern', true);
1675                 }
1676                 
1677             });
1678
1679             if (!ngModel) {
1680                 $log.error("ng-model is required.");
1681                 return; // do nothing if no ng-model
1682             }
1683
1684             if(scope.model !== undefined && scope.model !== '') {
1685                 element[0].value = $filter('date')(scope.model, "MM/dd/yyyy");
1686             }
1687
1688             // Configuration parameters
1689             var mode = 0,
1690                 selected;
1691             scope.isOpen = false;
1692             var isValidDate = false;
1693
1694             scope.headers = [];
1695             scope.footers = [];
1696
1697             if (b2bDatepickerGroupCtrl) {
1698                 b2bDatepickerGroupCtrl.registerDatepickerScope(scope);
1699             }
1700
1701              var calendarButton = angular.element(element[0].nextElementSibling);
1702
1703             calendarButton.bind('click',function(){
1704                 openCalendarPopup = false;
1705                 if (!scope.ngDisabled) {
1706                     scope.isOpen = !scope.isOpen;
1707                     toggleCalendar(scope.isOpen);
1708                     scope.$apply();
1709                     datepickerCtrl.updatePosition(b2bDatepickerPopupTemplate);
1710                     $timeout(function () { 
1711                        // angular.element(element[0].querySelector('.datepicker-input')).scrollTop=0;
1712                     },10);
1713                 }
1714             })
1715             var openCalendarPopup = false;
1716
1717             element.bind('blur', function() {
1718                 if(scope.model !== undefined && scope.model !== '') {
1719                     var dateEntered = scope.model;
1720
1721                       var date_regex = /^(0[1-9]|1[0-2])\/(0[1-9]|1\d|2\d|3[01])\/(19|20)\d{2}$/ ;
1722
1723                     if(date_regex.test(dateEntered)) {       
1724                         var parts = dateEntered.split('/');
1725                         var enteredDate = new Date(parts[2],parts[0]-1,parts[1]);                           
1726
1727                         if(datepickerCtrl.isDateInRange(enteredDate)) {
1728                             isValidDate -= 1;
1729                             ngModel.$setValidity('outOfRange', true);
1730                             $timeout(function(){
1731                                 ngModel.$setValidity('outOfRange', true);
1732                             },10);
1733                             isValidDate = true;
1734                             if(!datepickerCtrl.isDisbaledDate(enteredDate)) {  
1735                                $timeout(function(){
1736                                     ngModel.$setValidity('disabledDate', true);
1737                                },10);   
1738                                 scope.select(enteredDate); 
1739                                 openCalendarPopup = true;
1740                             } else {
1741                                 $timeout(function(){
1742                                     ngModel.$setValidity('disabledDate', false);
1743                                 },10);
1744                                 isValidDate = false;
1745                                 openCalendarPopup = false;
1746                             }
1747   
1748                         } else {
1749                             isValidDate += 1;
1750                             $timeout(function(){
1751                                 ngModel.$setValidity('outOfRange', false);
1752                             },10);
1753                             isValidDate = false;
1754                             openCalendarPopup = false;
1755                         }
1756
1757                     }
1758                 }
1759             });   
1760
1761             var toggleCalendar = function (flag) {
1762                 if (!scope.inline) {
1763                     if (flag) {
1764                         b2bDatepickerPopupTemplate = angular.element($templateCache.get('b2bTemplate/calendar/datepicker-popup.html'));
1765                         b2bDatepickerPopupTemplate = $compile(b2bDatepickerPopupTemplate)(scope);
1766                         $document.find('body').append(b2bDatepickerPopupTemplate);
1767                         b2bDatepickerPopupTemplate.bind('keydown', keyPress);
1768                         $timeout(function () {
1769                             scope.getFocus = true;
1770                             trapFocusInElement(flag, b2bDatepickerPopupTemplate);
1771                             scope.$apply();
1772                             $timeout(function () {
1773                                 scope.getFocus = false; 
1774                                 scope.$apply();
1775                             }, 100);
1776                             handleTabEvent();
1777                         });
1778                         angular.element(document.querySelector('.b2b-calendar-icon')).attr('aria-expanded','true');
1779                     } else {
1780                         if(!openCalendarPopup) {
1781                             b2bDatepickerPopupTemplate.unbind('keydown', keyPress);
1782                             b2bDatepickerPopupTemplate.remove();
1783                         }
1784                         element[0].focus();
1785                         scope.getFocus = false;
1786                         angular.element(document.querySelector('.b2b-calendar-icon')).attr('aria-expanded','false');
1787                         trapFocusInElement(flag, b2bDatepickerPopupTemplate);
1788                     }
1789                 }
1790             };
1791
1792             var handleTabEvent = function(){
1793                 b2bDatepickerPopupTemplate.find('td').on('keydown', function (e) {
1794                     if (e.keyCode == '9') {
1795                         if(e.shiftKey){
1796                             if(b2bDatepickerPopupTemplate.find('tr')[0].querySelector('th.next')){
1797                                 b2bDatepickerPopupTemplate.find('tr')[0].querySelector('th.next').focus();
1798                             }else{
1799                                 b2bDatepickerPopupTemplate.find('tr')[0].querySelector('th.datepicker-switch').focus()
1800                             }        
1801                         }else{
1802                             if(b2bDatepickerPopupTemplate.find('tr')[0].querySelector('th.prev')){
1803                                 b2bDatepickerPopupTemplate.find('tr')[0].querySelector('th.prev').focus();
1804                             }else{
1805                                 b2bDatepickerPopupTemplate.find('tr')[0].querySelector('th.datepicker-switch').focus()
1806                             }
1807                         }
1808                         
1809                         e.preventDefault();
1810                         e.stopPropagation();
1811                     }
1812                 });
1813             }
1814
1815             var outsideClick = function (e) {
1816                 var isElement = $isElement(angular.element(e.target), element, $document);
1817                 var isb2bDatepickerPopupTemplate = $isElement(angular.element(e.target), b2bDatepickerPopupTemplate, $document);
1818                 if (!(isElement || isb2bDatepickerPopupTemplate)) {
1819                     scope.isOpen = false;
1820                     toggleCalendar(scope.isOpen);
1821                     scope.$apply();
1822                 }
1823             };
1824
1825             var keyPress = function (ev) {
1826                 if (!ev.keyCode) {
1827                     if (ev.which) {
1828                         ev.keyCode = ev.which;
1829                     } else if (ev.charCode) {
1830                         ev.keyCode = ev.charCode;
1831                     }
1832                 }
1833                 if (ev.keyCode) {
1834                     if (ev.keyCode === 27) {
1835                         scope.isOpen = false;
1836                         toggleCalendar(scope.isOpen);
1837                         ev.preventDefault();
1838                         ev.stopPropagation();
1839                     } else if (ev.keyCode === 33) {
1840                         !scope.disablePrev && scope.move(-1);
1841                         $timeout(function () {
1842                             scope.getFocus = true;
1843                             scope.$apply();
1844                             $timeout(function () {
1845                                 scope.getFocus = false;
1846                                 scope.$apply();
1847                             }, 100);
1848                         });
1849                         ev.preventDefault();
1850                         ev.stopPropagation();
1851                     } else if (ev.keyCode === 34) {
1852                         !scope.disableNext && scope.move(1);
1853                         $timeout(function () {
1854                             scope.getFocus = true;
1855                             scope.$apply();
1856                             $timeout(function () {
1857                                 scope.getFocus = false;
1858                                 scope.$apply();
1859                             }, 100);
1860                         });
1861                         ev.preventDefault();
1862                         ev.stopPropagation();
1863                     }
1864                     scope.$apply();
1865                 }
1866             };
1867
1868             $documentBind.click('isOpen', outsideClick, scope);
1869
1870             var modalContainer = angular.element(document.querySelector('.modalwrapper'));
1871             var modalBodyContainer = angular.element(document.querySelector('.modal-body'));
1872             if (modalContainer) {
1873                 modalContainer.bind('scroll', function () {
1874                     if (b2bDatepickerPopupTemplate) {
1875                         datepickerCtrl.updatePosition(b2bDatepickerPopupTemplate);
1876                         scope.$apply();
1877                     }
1878                 });
1879             }
1880             if (modalBodyContainer) {
1881                 modalBodyContainer.bind('scroll', function () {
1882                     if (b2bDatepickerPopupTemplate) {
1883                         datepickerCtrl.updatePosition(b2bDatepickerPopupTemplate);
1884                         var datepickerTextfield = $position.offset(element.find('input'));
1885                         var modalBodyPosition = $position.offset(modalBodyContainer);
1886
1887                         if (((datepickerTextfield.top + datepickerTextfield.height) < modalBodyPosition.top || datepickerTextfield.top > (modalBodyPosition.top + modalBodyPosition.height)) && scope.isOpen) {
1888                             scope.isOpen = false;
1889                             toggleCalendar(scope.isOpen);
1890                         }
1891                         scope.$apply();
1892                     }
1893                 });
1894             }
1895             var window = angular.element($window);
1896             window.bind('resize', function () {
1897                 if (b2bDatepickerPopupTemplate) {
1898                     datepickerCtrl.updatePosition(b2bDatepickerPopupTemplate);
1899                     scope.$apply();
1900                 }
1901             });
1902
1903             scope.$on('$destroy', function () {
1904                 if (scope.isOpen) {
1905                     scope.isOpen = false;
1906                     toggleCalendar(scope.isOpen);
1907                 }
1908             });
1909
1910             scope.resetTime = function (date) {
1911                 if (typeof date === 'string') {
1912                     date = date + 'T12:00:00';
1913                 }
1914                 var dt;
1915                 if (!isNaN(new Date(date))) {
1916                     dt = new Date(date);
1917                 } else {
1918                     return null;
1919                 }
1920                 return new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());
1921             };
1922
1923             if (attrs.min) {
1924                 scope.$parent.$watch($parse(attrs.min), function (value) {
1925                     scope.minDate = value ? scope.resetTime(value) : null;
1926                     refill();
1927                 });
1928             }
1929             if (attrs.max) {
1930                 scope.$parent.$watch($parse(attrs.max), function (value) {
1931                     scope.maxDate = value ? scope.resetTime(value) : null;
1932                     refill();
1933                 });
1934             }
1935             if (attrs.due) {
1936                 scope.$parent.$watch($parse(attrs.due), function (value) {
1937                     scope.dueDate = value ? scope.resetTime(value) : null;
1938                     refill();
1939                 });
1940             }
1941             if (attrs.from) {
1942                 scope.$parent.$watch($parse(attrs.from), function (value) {
1943                     scope.fromDate = value ? scope.resetTime(value) : null;
1944                     refill();
1945                 });
1946             }
1947
1948             if (attrs.legendIcon) {
1949                 scope.$parent.$watch(attrs.legendIcon, function (value) {
1950                     scope.legendIcon = value ? value : null;
1951                     refill();
1952                 });
1953             }
1954             if (attrs.legendMessage) {
1955                 scope.$parent.$watch(attrs.legendMessage, function (value) {
1956                     scope.legendMessage = value ? value : null;
1957                     refill();
1958                 });
1959             }
1960             if (attrs.ngDisabled) {
1961                 scope.$parent.$watch(attrs.ngDisabled, function (value) {
1962                     scope.ngDisabled = value ? value : null;
1963                 });
1964             }
1965
1966             // Split array into smaller arrays
1967             function split(arr, size) {
1968                 var arrays = [];
1969                 while (arr.length > 0) {
1970                     arrays.push(arr.splice(0, size));
1971                 }
1972                 return arrays;
1973             }
1974
1975             function refill(date) {
1976                 if (angular.isDate(date) && !isNaN(date)) {
1977                     selected = new Date(date);
1978                 } else {
1979                     if (!selected) {
1980                         selected = new Date();
1981                     }
1982                 }
1983
1984                 if (selected) {
1985                     var currentMode = datepickerCtrl.modes[mode],
1986                         data = currentMode.getVisibleDates(selected);
1987                     scope.rows = split(data.objects, currentMode.split);
1988                     var flag = false;
1989                     var startFlag = false;
1990                     var firstSelected = false;
1991                     for (var i = 0; i < scope.rows.length; i++) {
1992                         for (var j = 0; j < scope.rows[i].length; j++) {
1993
1994                             if (scope.rows[i][j].label === "1" && !firstSelected) {
1995                                 firstSelected = true;
1996                                 var firstDay = scope.rows[i][j];
1997                             }
1998
1999                             if (scope.rows[i][j].selected === true) {
2000                                 flag = true;
2001                                 break;
2002                             }
2003                         }
2004                         if (flag) {
2005                             break;
2006                         }
2007                     }
2008                     if (!flag) {
2009                         firstDay.firstFocus = true;
2010                     }
2011
2012                     scope.labels = data.labels || [];
2013                     scope.title = data.title;
2014
2015                     datepickerCtrl.updatePosition(b2bDatepickerPopupTemplate);
2016                 }
2017             }
2018
2019             scope.select = function (date) {
2020                 var dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());
2021                 if (!scope.onSelectClose || (scope.onSelectClose && scope.onSelectClose({
2022                         date: dt
2023                     }) !== false)) {
2024                     scope.currentDate = dt;
2025                     element[0].value = $filter('date')(dt, "MM/dd/yyyy");
2026                     ngModel.$setValidity('outOfRange', true);
2027                     if (angular.isNumber(scope.collapseWait)) {
2028                         $timeout(function () {
2029                             scope.isOpen = false;
2030                             toggleCalendar(scope.isOpen);
2031                         }, scope.collapseWait);
2032                     } else {
2033                         scope.isOpen = false;
2034                         toggleCalendar(scope.isOpen);
2035                     }
2036                 }
2037             };
2038
2039             scope.move = function (direction,$event) {
2040                 var step = datepickerCtrl.modes[mode].step;
2041                 selected.setDate(1);
2042                 selected.setMonth(selected.getMonth() + direction * (step.months || 0));
2043                 selected.setFullYear(selected.getFullYear() + direction * (step.years || 0));
2044                 refill();
2045
2046                 $timeout(function () {
2047                     trapFocusInElement();
2048                     handleTabEvent();
2049                 }, 100);
2050
2051                 $event.preventDefault();
2052                 $event.stopPropagation();
2053             };
2054
2055             scope.trapFocus = function () {
2056                 $timeout(function () {
2057                     trapFocusInElement();
2058                 }, 100);
2059             };
2060
2061             scope.$watch('currentDate', function (value) {
2062                 if (angular.isDefined(value) && value !== null) {
2063                     refill(value);
2064                 } else {
2065                     refill();
2066                 }
2067                 ngModel.$setViewValue(value);
2068             });
2069
2070             ngModel.$render = function () {
2071                 scope.currentDate = ngModel.$viewValue;
2072             };
2073
2074             var stringToDate = function (value) {
2075                 if (!isNaN(new Date(value))) {
2076                     value = new Date(value);
2077                 }
2078                 return value;
2079             };
2080             ngModel.$formatters.unshift(stringToDate);
2081         }
2082     };
2083 }])
2084
2085
2086 .directive('b2bDatepickerGroup', [function () {
2087     return {
2088         restrict: 'EA',
2089         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
2090             this.$$headers = [];
2091             this.$$footers = [];
2092             this.registerDatepickerScope = function (datepickerScope) {
2093                 datepickerScope.headers = this.$$headers;
2094                 datepickerScope.footers = this.$$footers;
2095             };
2096         }],
2097         link: function (scope, elem, attr, ctrl) {}
2098     };
2099 }])
2100
2101 .directive('b2bFormatDate', ['dateFilter', function (dateFilter) {
2102     return {
2103         restrict: 'A',
2104         require: 'ngModel',
2105         link: function (scope, elem, attr, ctrl) {
2106             var b2bFormatDate = "";
2107             attr.$observe('b2bFormatDate', function (value) {
2108                 b2bFormatDate = value;
2109             });
2110             var dateToString = function (value) {
2111                 if (!isNaN(new Date(value))) {
2112                     return dateFilter(new Date(value), b2bFormatDate);
2113                 }
2114                 return value;
2115             };
2116             ctrl.$formatters.unshift(dateToString);
2117         }
2118     };
2119 }])
2120
2121 .directive('b2bDatepickerHeader', [function () {
2122     return {
2123         restrict: 'EA',
2124         require: '^b2bDatepickerGroup',
2125         transclude: true,
2126         replace: true,
2127         template: '',
2128         compile: function (elem, attr, transclude) {
2129             return function link(scope, elem, attr, ctrl) {
2130                 if (ctrl) {
2131                     ctrl.$$headers.push(transclude(scope, function () {}));
2132                 }
2133                 elem.remove();
2134             };
2135         }
2136     };
2137 }])
2138
2139 .directive('b2bDatepickerFooter', [function () {
2140     return {
2141         restrict: 'EA',
2142         require: '^b2bDatepickerGroup',
2143         transclude: true,
2144         replace: true,
2145         template: '',
2146         compile: function (elem, attr, transclude) {
2147             return function link(scope, elem, attr, ctrl) {
2148                 if (ctrl) {
2149                     ctrl.$$footers.push(transclude(scope, function () {}));
2150                 }
2151                 elem.remove();
2152             };
2153         }
2154     };
2155 }]);
2156 /**
2157  * @ngdoc directive
2158  * @name Forms.att:checkboxes
2159  *
2160  * @description
2161  *  <file src="src/checkboxes/docs/readme.md" />
2162  * @usage
2163  * See demo section
2164  * @example
2165  <example module="b2b.att">
2166  <file src="src/checkboxes/docs/demo.html" />
2167  <file src="src/checkboxes/docs/demo.js" />
2168  </example>
2169  */
2170 angular.module('b2b.att.checkboxes', ['b2b.att.utilities'])
2171 .directive('b2bSelectGroup', [function (){
2172         return {
2173             restrict: 'A',
2174             require: 'ngModel',
2175             scope: {
2176                 checkboxes: "="
2177             },
2178             link: function (scope, elem, attr, ctrl) {
2179                 elem.bind('change', function () {
2180                     var isChecked = elem.prop('checked');
2181                     angular.forEach(scope.checkboxes, function (item) {
2182                         item.isSelected = isChecked;
2183                     });
2184                     scope.$apply();
2185                 });
2186                 scope.$watch('checkboxes', function () {
2187                     var setBoxes = 0;
2188                     if(scope.checkboxes === undefined) {
2189                         return;
2190                     }
2191                     angular.forEach(scope.checkboxes, function (item) {
2192                         if (item.isSelected) {
2193                             setBoxes++; 
2194                         } 
2195                     });
2196                     elem.prop('indeterminate', false);
2197                     if ( scope.checkboxes !==undefined && setBoxes === scope.checkboxes.length && scope.checkboxes.length > 0) { 
2198                         ctrl.$setViewValue(true); 
2199                         elem.removeClass('indeterminate');
2200                     } else if (setBoxes === 0) { 
2201                        ctrl.$setViewValue(false); 
2202                        elem.removeClass('indeterminate');
2203                     } else { 
2204                         ctrl.$setViewValue(false); 
2205                         elem.addClass('indeterminate');
2206                         elem.prop('indeterminate', true); 
2207                     }
2208                     ctrl.$render();
2209                 }, true);
2210             }
2211         };
2212     }]);
2213 /**
2214  * @ngdoc directive
2215  * @name Misc.att:coachmark
2216  *
2217  * @description
2218  * <file src="src/coachmark/docs/readme.md" />
2219  *
2220  * @usage
2221  *
2222 <button b2b-coachmark start-coachmark-callback="startCoachmark()" end-coachmark-callback="endCoachmark()" action-coachmark-callback="actionCoachmark(action)" coachmark-index="coachmarkIndex" coachmarks="coachmarkElements" id="coachmark0" class="btn btn-alt">Initiate tour</button>
2223
2224  * @example
2225     <section id="code">   
2226         <b>HTML + AngularJS</b>
2227         <example module="b2b.att">
2228             <file src="src/coachmark/docs/demo.html" />
2229             <file src="src/coachmark/docs/demo.js" />
2230         </example>
2231     </section>
2232  */
2233
2234 angular.module('b2b.att.coachmark', ['b2b.att.utilities','b2b.att.position'])
2235         
2236         .directive('b2bCoachmark', ['$document', '$compile', '$position', '$timeout', 'b2bViewport', 'keymap', function($document, $compile, $position, $timeout, b2bViewport, keymap) {
2237         return {
2238             restrict: 'A',
2239                          scope: {
2240                                 coachmarks: '=',
2241                                 coachmarkIndex: '=',
2242                                 startCoachmarkCallback: '&',
2243                                 endCoachmarkCallback: '&',
2244                                 actionCoachmarkCallback: '&'
2245                         },
2246             link: function (scope, element, attrs, ctrl) {
2247                                 var coachmarkItems = scope.coachmarks;
2248                                 var body = $document.find('body').eq(0);
2249                                 var coackmarkJqContainer;
2250                                 var coackmarkContainer;
2251                                 var coachMarkElement;
2252                                 var backdropjqLiteEl;
2253                                 var coachmarkHighlight;
2254                                 var initaitedCoachmark = false;
2255                                 scope.coackmarkElPos ={
2256                                         'top':'',
2257                                         'left':''
2258                                 };
2259                                 
2260                                 scope.currentCoachmark = {};
2261                                 
2262                                 
2263                 var coachmarkBackdrop = function(){
2264                                         backdropjqLiteEl = angular.element('<div class="b2b-modal-backdrop fade in hidden-by-modal"></div>');
2265                                         body.append(backdropjqLiteEl);
2266
2267                                         backdropjqLiteEl.bind('click', function() {
2268                                                 scope.closeCoachmark();
2269                                                 scope.$apply();
2270                                         });
2271                                 };
2272                                 
2273                                 
2274                                 scope.closeButtonFocus = function(){
2275                                         if(document.getElementsByClassName('b2b-coachmark-header').length >0){
2276                                                 document.getElementsByClassName('b2b-coachmark-header')[0].scrollLeft = 0;
2277                                                 document.getElementsByClassName('b2b-coachmark-header')[0].scrollTop = 0;
2278                                         }
2279                                 }
2280
2281                                 scope.actionCoachmark = function(action){
2282                                         scope.actionCoachmarkCallback({
2283                                                 'action':action
2284                                         })
2285                                 };
2286                                 
2287                                 scope.closeCoachmark = function(){
2288                                         initaitedCoachmark = false;
2289                                         backdropjqLiteEl.remove();      
2290                                         coackmarkContainer.remove();
2291                                         coachmarkHighlight.remove();
2292                                         if(coachMarkElement !== undefined && coachMarkElement !==""){
2293                                                 coachMarkElement.removeClass('b2b-coachmark-label')
2294                                         }
2295                                         if (angular.isFunction(scope.endCoachmarkCallback)){
2296                                                 scope.endCoachmarkCallback();   
2297                                         }
2298                                         element[0].focus();
2299                                 }
2300
2301                                 var realStyle = function(_elem, _style) {
2302                                     var computedStyle;
2303                                     if ( typeof _elem.currentStyle != 'undefined' ) {
2304                                         computedStyle = _elem.currentStyle;
2305                                     } else {
2306                                         computedStyle = document.defaultView.getComputedStyle(_elem, null);
2307                                     }
2308
2309                                     return _style ? computedStyle[_style] : computedStyle;
2310                                 };
2311
2312                                 var copyComputedStyle = function(src, dest) {
2313                                     var s = realStyle(src);
2314                                     for ( var i in s ) {
2315                                         // Do not use `hasOwnProperty`, nothing will get copied
2316                                         if ( typeof i == "string" && i != "cssText" && !/\d/.test(i) && i.indexOf('webkit') !== 0 ) {
2317                                             // The try is for setter only properties
2318                                             try {
2319                                                 dest.style[i] = s[i];
2320                                                 // `fontSize` comes before `font` If `font` is empty, `fontSize` gets
2321                                                 // overwritten.  So make sure to reset this property. (hackyhackhack)
2322                                                 // Other properties may need similar treatment
2323                                                 if ( i == "font" ) {
2324                                                     dest.style.fontSize = s.fontSize;
2325                                                 }
2326                                             } catch (e) {}
2327                                         }
2328                                     }
2329                                 };
2330                                 
2331                                 function showCoachmark(targetElement) {
2332
2333                                         scope.currentCoachmark = targetElement;
2334                                         if(coachMarkElement !== undefined && coachMarkElement !==""){
2335                                                 coachMarkElement.removeClass('b2b-coachmark-label')
2336                                                 coackmarkContainer.remove();
2337                                                 coachmarkHighlight.remove();
2338                                         }
2339                                         coachMarkElement = angular.element(document.querySelector(targetElement.elementId));
2340                                         
2341                                         var     elementPosition = $position.offset(coachMarkElement);
2342                                         
2343                                         coachmarkHighlight = angular.element('<div class="b2b-coachmark-highlight"></div><div class="b2b-coachmark-highlight b2b-coachmark-highlight-mask"></div>');
2344                                         coachmarkHighlight.css({
2345                                                 'width': (elementPosition.width + 25) +'px',
2346                                                 'top': (elementPosition.top -10) + 'px',
2347                                                 'left': (elementPosition.left - 10) + 'px',
2348                                                 'height': (elementPosition.height + 20) +'px'
2349                                         });
2350                                         if(targetElement.cloneHtml){
2351                                                 var copy = coachMarkElement[0].cloneNode(true);
2352                                                 copy.id = "b2b-unique-"+targetElement.elementId.slice(1);
2353                                                 copyComputedStyle(coachMarkElement[0],copy);
2354                                                 var copychildNodes = copy.childNodes;
2355                                                 var coachmarkChildNodes = coachMarkElement[0].childNodes;
2356                                                 for(i=0;i<copychildNodes.length;i++){
2357                                                         if(copychildNodes[i].nodeType === '3'){
2358                                                                 copyComputedStyle(coachmarkChildNodes[i],copychildNodes[i])
2359                                                         }
2360                                                 }
2361                                                 coachmarkHighlight[0].appendChild(copy); // IE11 only supports appendChild, not append
2362                                         }else{
2363                                                 coachMarkElement.addClass('b2b-coachmark-label');
2364                                         }
2365                                         
2366                                         body.append(coachmarkHighlight);
2367                                         
2368                                         scope.coackmarkElPos.top = (elementPosition.top + elementPosition.height + 32) + 'px';
2369                                         scope.coackmarkElPos.left = (elementPosition.left - 158 + elementPosition.width / 2 ) + 'px';
2370                                         coackmarkJqContainer = angular.element('<div b2b-coachmark-container b2b-trap-focus-inside-element="true"></div>');
2371                                         coackmarkContainer = $compile(coackmarkJqContainer)(scope);
2372                                         body.append(coackmarkContainer);
2373                                         
2374                                         
2375                                         $timeout(function () {
2376                                                 var currentCoachmarkContainer = document.getElementsByClassName('b2b-coachmark-container')[0];
2377                                                 currentCoachmarkContainer.focus();
2378
2379                                                 newElem = angular.element(currentCoachmarkContainer);
2380                                                 newElem.bind('keydown', function (e) {
2381                                                         if(e.keyCode == keymap.KEY.TAB){
2382                                                             if(e.shiftKey) {
2383                                                                 if(e.target.className === 'b2b-coachmark-container'){
2384                                                                         e.preventDefault();
2385                                                                         e.stopPropagation();
2386                                                                     }
2387                                                             }
2388                                                         }
2389                                                 });
2390                                                 var coachmarkHeight = window.getComputedStyle(currentCoachmarkContainer).height.split('px')[0];
2391                                                 var newOffsetHeight = Math.round(elementPosition.top) - elementPosition.height;
2392                                                 
2393                                                 // We need a slight offset to show the lightboxed item
2394                                                 if(!targetElement.cloneHtml){
2395                                                         TweenLite.to(window, 2, {scrollTo:{x: (scope.coackmarkElPos.left.split('px')[0] - 100), y: newOffsetHeight-200}});
2396                                                 }
2397                                         }, 200);
2398                                 }
2399                                 
2400                                 element.bind('click', function (e) {
2401                                         initaitedCoachmark = true;
2402                     
2403                                         scope.$watch('coachmarkIndex', function () {
2404                                                 if(initaitedCoachmark === true){
2405                             if(scope.coachmarkIndex === -1){
2406                                                                 scope.closeCoachmark();
2407                                                         }else{
2408                                 findAvailableCoachmark(scope.coachmarkIndex);
2409                                 showCoachmark(scope.coachmarks[scope.coachmarkIndex]);
2410                                                         }
2411                                                 }
2412                                         });
2413                                         coachmarkBackdrop();
2414                     var findAvailableCoachmark = function(index){
2415                         if(index === -1){
2416                                 scope.coachmarkIndex = 0;
2417                         } else if(!angular.isDefined(scope.coachmarks[index]) || angular.element(document.querySelector(scope.coachmarks[index].elementId)).length === 0){
2418                             findAvailableCoachmark(index-1);
2419                         } else {
2420                             scope.coachmarkIndex = index;
2421                         }
2422                     }
2423                                         if (angular.isFunction(scope.startCoachmarkCallback)){
2424                                                 scope.startCoachmarkCallback(); 
2425                                         }
2426                     findAvailableCoachmark(scope.coachmarkIndex);
2427                     showCoachmark(scope.coachmarks[scope.coachmarkIndex]);
2428                     
2429                                         $document.bind('keydown', function (evt) {
2430                                                 if (evt.which === 27 && initaitedCoachmark) {
2431                                                         scope.closeCoachmark();
2432                                                         scope.$apply(); 
2433                                                 }
2434                                         });
2435                                 });
2436                                 //performance technique to ensure scroll event doesn't cause lag
2437                                 var throttle = function(type, name, obj) {
2438                                 obj = obj || window; 
2439                                 var running = false; 
2440                                 var func = function() { 
2441                                     if (running) { return; } 
2442                                     running = true; 
2443                                      requestAnimationFrame(function() { 
2444                                         obj.dispatchEvent(new CustomEvent(name)); 
2445                                         running = false; 
2446                                     }); 
2447                                 }; 
2448                                 obj.addEventListener(type, func); 
2449                             };
2450                          
2451                             scope.viewportWidth = b2bViewport.viewportWidth(); 
2452                             /* init - you can init any event */ 
2453                             throttle("resize", "optimizedResize"); 
2454                             window.addEventListener("optimizedResize", function() {
2455                                 if(initaitedCoachmark){
2456                         showCoachmark(scope.coachmarks[scope.coachmarkIndex]);
2457                                         scope.viewportWidth = b2bViewport.viewportWidth(); 
2458                                         scope.$digest();
2459                                 }
2460                             });
2461             }
2462         };
2463     }])
2464         .directive('b2bCoachmarkContainer', ['$document', '$position', function($document, $position) {
2465                 return {
2466                         restrict: 'A',
2467                         transclude: true,
2468             replace: true,
2469                         templateUrl: 'b2bTemplate/coachmark/coachmark.html',
2470                         link: function (scope, element, attrs, ctrl) {
2471                                                         
2472                         }
2473                 };      
2474         }]);
2475         
2476
2477 /** 
2478  * @ngdoc directive 
2479  * @name Template.att:Configuration Section 
2480  * 
2481  * @description 
2482  *  <file src="src/configurationSection/docs/readme.md" /> 
2483  * 
2484  * @example 
2485  *  <section id="code"> 
2486         <b>HTML + AngularJS</b> 
2487         <example module="b2b.att"> 
2488             <file src="src/configurationSection/docs/demo.html" /> 
2489             <file src="src/configurationSection/docs/demo.js" /> 
2490        </example> 
2491     </section>    
2492  * 
2493  */
2494 angular.module('b2b.att.configurationSection', [])
2495   
2496 /** 
2497  * @ngdoc directive 
2498  * @name Template.att:Directory Listing 
2499  * 
2500  * @description 
2501  *  <file src="src/directoryListingTemplate/docs/readme.md" /> 
2502  * 
2503  * @example 
2504  *  <section id="code"> 
2505         <b>HTML + AngularJS</b> 
2506         <example module="b2b.att"> 
2507             <file src="src/directoryListingTemplate/docs/demo.html" /> 
2508             <file src="src/directoryListingTemplate/docs/demo.js" /> 
2509        </example> 
2510     </section>    
2511  * 
2512  */
2513 angular.module('b2b.att.directoryListingTemplate', [])
2514   
2515 /**
2516  * @ngdoc directive
2517  * @name Forms.att:dropdowns
2518  *
2519  * @description
2520  *  <file src="src/dropdowns/docs/readme.md" />
2521  * @usage
2522  *
2523  * @example
2524    <section id="code">
2525     <example module="b2b.att">
2526      <file src="src/dropdowns/docs/demo.html" />
2527      <file src="src/dropdowns/docs/demo.js" />
2528     </example>
2529    </section>
2530  */
2531 angular.module('b2b.att.dropdowns', ['b2b.att.utilities', 'b2b.att.position', 'ngSanitize'])
2532
2533 .constant('b2bDropdownConfig', {
2534     prev: '37,38',
2535     next: '39,40',
2536     menuKeyword: 'menu',
2537     linkMenuKeyword: 'link-menu',
2538     largeKeyword: 'large',
2539     smallKeyword: 'small'
2540 })  
2541
2542 .directive("b2bDropdown", ['$timeout', '$compile', '$templateCache', 'b2bUserAgent', 'b2bDropdownConfig', '$position', function ($timeout, $compile, $templateCache, b2bUserAgent, b2bDropdownConfig, $position) {
2543     return {
2544         restrict: 'A',
2545         scope: true,
2546         require: 'ngModel',
2547         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
2548             scope.isInputDropdown = true;
2549             scope.placeHoldertext = attr.placeholderText;
2550             if (attr.type) {
2551                 if (attr.type.indexOf(b2bDropdownConfig.menuKeyword) > -1 || attr.type.indexOf(b2bDropdownConfig.linkMenuKeyword) > -1) {
2552                     scope.isInputDropdown = false;
2553                     if (attr.type.indexOf(b2bDropdownConfig.linkMenuKeyword) > -1) {
2554                         scope.dropdownType = b2bDropdownConfig.linkMenuKeyword;
2555                     } else if (attr.type.indexOf(b2bDropdownConfig.menuKeyword) > -1) {
2556                         scope.dropdownType = b2bDropdownConfig.menuKeyword;
2557                     }
2558                 }
2559                 if (attr.type.indexOf(b2bDropdownConfig.largeKeyword) > -1) {
2560                     scope.dropdownSize = b2bDropdownConfig.largeKeyword;
2561                 } else if (attr.type.indexOf(b2bDropdownConfig.smallKeyword) > -1) {
2562                     scope.dropdownSize = b2bDropdownConfig.smallKeyword;
2563                 }
2564             }
2565
2566             scope.labelText = attr.labelText;
2567
2568             scope.setBlur = function () {
2569                 scope.setTouched();
2570             };
2571
2572             if ((scope.isInputDropdown && b2bUserAgent.notMobile()) || (!scope.isInputDropdown)) {
2573                 var formCtrl = elem.controller('form');
2574                 scope.setNgModelController = function (name, ngModelCtrl) {
2575                     if (name && formCtrl && ngModelCtrl) {
2576                         formCtrl[name] = ngModelCtrl;
2577                     }
2578                 };
2579                 scope.setOptionalCta = function (optionalCta) {
2580                     scope.optionalCta = optionalCta;
2581                 };
2582                 var innerHtml = angular.element('<div></div>').append(elem.html());
2583                 innerHtml = ($compile(innerHtml)(scope)).html();
2584                 var template = angular.element($templateCache.get('b2bTemplate/dropdowns/b2bDropdownDesktop.html'));
2585                 template.find('ul').eq(0).append(innerHtml);
2586                 template = $compile(template)(scope);
2587                 elem.replaceWith(template);
2588             } else if (scope.isInputDropdown && b2bUserAgent.isMobile()) {
2589                 elem.css({
2590                     'opacity': '0',
2591                     'filter': 'alpha(opacity=0)'
2592                 });
2593                 elem.addClass('awd-select isWrapped');
2594                 elem.wrap('<span class="selectWrap"></span>');
2595                 var cover = angular.element('<span aria-hidden="true"><i class="icon-primary-down" aria-hidden="true"></i></span>');
2596                 elem.parent().append(cover);
2597                 elem.parent().append('<i class="icon-primary-down" aria-hidden="true"></i>');
2598                 var set = function () {
2599                     var sel = elem[0] ? elem[0] : elem;
2600                     var selectedText = "";
2601                     var selIndex = sel.selectedIndex;
2602                     if (typeof selIndex !== 'undefined') {
2603                         selectedText = sel.options[selIndex].text;
2604                     }
2605                     cover.text(selectedText).append('<i class="icon-primary-down" aria-hidden="true"></i>');
2606                 };
2607                 var update = function (value) {
2608                     $timeout(set, 100);
2609                 };
2610
2611                 if (attr.ngModel) {
2612                     scope.$watch(attr.ngModel, function (newVal, oldVal) {
2613                         update();
2614                     });
2615                 }
2616                 elem.bind('keyup', function (ev) {
2617                     if (ev.keyCode === keymap.KEY.TAB || ev.keyCode === keymap.KEY.ESC) {
2618                         return;
2619                     }
2620                     set();
2621                 });
2622             }
2623
2624         }],  
2625         link: function (scope, elem, attr, ctrl) {
2626             if ((scope.isInputDropdown && b2bUserAgent.notMobile()) || (!scope.isInputDropdown)) {
2627                 scope.updateModel = function () {
2628                     ctrl.$setViewValue(scope.currentSelected.value);
2629                     if (scope.dropdownRequired && scope.currentSelected.value === '') {
2630                         scope.setRequired(false);
2631                     } else {
2632                         scope.setRequired(true);
2633                     }
2634
2635                     if (scope.dropdownType === b2bDropdownConfig.linkMenuKeyword) {
2636                         $timeout(function () {
2637                             scope.appendCaretPositionStyle();
2638                         }, 100);
2639                     }
2640                 };
2641                 ctrl.$render = function () {
2642
2643                 $timeout(function () {
2644
2645                         if ((angular.isUndefined(ctrl.$viewValue) || ctrl.$viewValue == '') && (angular.isUndefined(scope.placeHoldertext) || scope.placeHoldertext == '')) {
2646                             scope.dropdownLists[ctrl.$viewValue] && scope.dropdownLists[ctrl.$viewValue][0].updateDropdownValue();
2647                         } else if ((angular.isUndefined(scope.placeHoldertext) || scope.placeHoldertext == '') && ctrl.$viewValue !== '' ) {
2648                             scope.dropdownLists[ctrl.$viewValue] && scope.dropdownLists[ctrl.$viewValue][0].updateDropdownValue();
2649                         } else if ((angular.isUndefined(ctrl.$viewValue) || ctrl.$viewValue == '') && scope.placeHoldertext !== '' )  {
2650                             scope.currentSelected.text = scope.placeHoldertext;
2651                             ctrl.$setViewValue(scope.placeHoldertext);
2652                         } else {
2653                             scope.dropdownLists[ctrl.$viewValue] && scope.dropdownLists[ctrl.$viewValue][0].updateDropdownValue();
2654                         }
2655
2656                     }, 100);
2657                 };
2658
2659                 scope.disabled = false;
2660                 scope.dropdownName = attr.name;
2661                 scope.dropdownId = attr.id;
2662                 scope.labelId = attr.ariaLabelledby;
2663                 scope.dropdownDescribedBy = attr.ariaDescribedby;
2664                 if (attr.required) {
2665                     scope.dropdownRequired = true;
2666                 } else {
2667                     scope.dropdownRequired = false;
2668                 }
2669                 elem.removeAttr('name');
2670                 elem.removeAttr('id');
2671                 scope.$parent.$watch(attr.ngDisabled, function (val) {
2672                     scope.disabled = val;
2673                 });
2674             }
2675         }
2676     };
2677 }])
2678
2679 .directive("b2bDropdownToggle", ['$document', '$documentBind', '$isElement', 'b2bDropdownConfig', 'keymap', 'b2bUtilitiesConfig', '$timeout', '$position', function ($document, $documentBind, $isElement, b2bDropdownConfig, keymap, b2bUtilitiesConfig, $timeout, $position) {
2680     return {
2681         restrict: 'A',
2682         require: '?^b2bKey',
2683         link: function (scope, elem, attr, ctrl) {
2684             scope.appendCaretPositionStyle = function () {
2685                 while (document.querySelector('style.b2bDropdownCaret')) {
2686                     document.querySelector('style.b2bDropdownCaret').remove();
2687                 };
2688                 var caretPosition = $position.position(elem).width - 26;
2689                 if (scope.dropdownType === b2bDropdownConfig.linkMenuKeyword) {
2690                     var template = angular.element('<style class="b2bDropdownCaret" type="text/css">.linkSelectorModule .active+.moduleWrapper:before {left: ' + caretPosition + 'px;}</style>');
2691                     $document.find('head').append(template);
2692                 }
2693             };
2694
2695             if (scope.isInputDropdown && (scope.labelText !== undefined)) {
2696                 elem.attr('aria-label', scope.labelText);
2697             }
2698
2699             scope.toggleFlag = false;
2700             scope.dropdownLists = {};
2701             scope.dropdownListValues = [];
2702             scope.dropdown = {
2703                 totalIndex: -1
2704             };
2705             scope.currentSelected = {
2706                 value: '',
2707                 text: '',
2708                 label: '',
2709                 index: -1
2710             };
2711             scope.dropdownTextList = [];
2712             var searchString = '';
2713
2714             scope.removeItem = function(value){
2715                 delete scope.dropdownLists[value];
2716                 var index = scope.dropdownListValues.indexOf(value);
2717                 scope.dropdownListValues.splice(index,1);
2718                 scope.dropdownTextList=[];
2719                 scope.dropdown.totalIndex = scope.dropdownListValues.length-1; 
2720             };
2721             var getDropdownText = function(){
2722                 var dropdownItems = elem.parent().find('ul').children();
2723                 var count = dropdownItems.length;
2724                 for(var i=0;i<count;i++){
2725                     scope.dropdownTextList.push(dropdownItems.eq(i).text());
2726                 }
2727             };
2728             var searchElement = function (searchExp) {
2729                  if(scope.dropdownTextList.length ==0){
2730                     getDropdownText ();
2731                 }
2732                 var regex = new RegExp("^" + searchExp, "i");
2733                 var position = scope.dropdownTextList.regexIndexOf(regex, scope.currentSelected.index + 1, true);
2734                 if (position > -1) {
2735                     return position;
2736                 }
2737                 return undefined;
2738             };
2739             var startTimer = function (time) {
2740                 if (searchString === '') {
2741                     $timeout(function () {
2742                         searchString = '';
2743                     }, time);
2744                 }
2745             };
2746             scope.toggleDropdown = function (toggleFlag) {
2747                 if (!scope.disabled) {
2748                     if (angular.isDefined(toggleFlag)) {
2749                         scope.toggleFlag = toggleFlag;
2750                     } else {
2751                         scope.toggleFlag = !scope.toggleFlag;
2752                     }
2753                     if (!scope.toggleFlag) {
2754                         if (scope.isInputDropdown) {
2755                             elem.parent().find('input')[0].focus();
2756                         } else {
2757                             elem.parent().find('button')[0].focus();
2758                         }
2759                     } else {
2760                         scope.dropdown.highlightedValue = scope.currentSelected.value;
2761                         if (ctrl && ctrl.enableSearch) {
2762                             if (angular.isDefined(scope.dropdownLists[scope.currentSelected.value])) {
2763                                 ctrl.resetCounter(scope.dropdownLists[scope.currentSelected.value][2]);
2764                             }
2765                         }
2766                         $timeout(function () {
2767                             if(scope.dropdownLists[scope.currentSelected.value] !== undefined){
2768                                 (scope.dropdownLists[scope.currentSelected.value][1])[0].focus();
2769                             } else {
2770                                 if (scope.isInputDropdown) {
2771                                     elem.parent().find('input')[0].focus();
2772                                 } else {
2773                                     elem.parent().find('button')[0].focus();
2774                                 }
2775                             }
2776                         }, 100);
2777                         if (scope.dropdownType === b2bDropdownConfig.linkMenuKeyword) {
2778                             scope.appendCaretPositionStyle();
2779                         }
2780                     }
2781                 }
2782             };
2783
2784             elem.bind('keydown', function (ev) {
2785                 if (!ev.keyCode) {
2786                     if (ev.which) {
2787                         ev.keyCode = ev.which;
2788                     } else if (ev.charCode) {
2789                         ev.keyCode = ev.charCode;
2790                     }
2791                 }
2792                 if (!scope.toggleFlag) {
2793                     if (ev.keyCode) {
2794                         var currentIndex = scope.currentSelected.index;
2795                         if (ev.keyCode === keymap.KEY.DOWN) {
2796                             scope.toggleDropdown(true);
2797                             ev.preventDefault();
2798                             ev.stopPropagation();
2799                         } else if (b2bDropdownConfig.prev.split(',').indexOf(ev.keyCode.toString()) > -1) {
2800                             angular.isDefined(scope.dropdownListValues[currentIndex - 1]) ? scope.dropdownLists[scope.dropdownListValues[currentIndex - 1]][0].updateDropdownValue() : angular.noop();
2801                             ev.preventDefault();
2802                             ev.stopPropagation();
2803                         } else if (b2bDropdownConfig.next.split(',').indexOf(ev.keyCode.toString()) > -1) {
2804                             angular.isDefined(scope.dropdownListValues[currentIndex + 1]) ? scope.dropdownLists[scope.dropdownListValues[currentIndex + 1]][0].updateDropdownValue() : angular.noop();
2805                             ev.preventDefault();
2806                             ev.stopPropagation();
2807                         } else if (ev.keyCode >= 48 && ev.keyCode <= 105) {
2808                             startTimer(b2bUtilitiesConfig.searchTimer);
2809                             searchString = searchString + (keymap.MAP[ev.keyCode] || '');
2810                             var position = searchElement(searchString);
2811                             angular.isDefined(scope.dropdownListValues[position]) ? scope.dropdownLists[scope.dropdownListValues[position]][0].updateDropdownValue() : angular.noop();
2812                             ev.preventDefault();
2813                             ev.stopPropagation();
2814                         }
2815                     }
2816                 } else {
2817                     if (ev.altKey === true && ev.keyCode === keymap.KEY.UP) {
2818                         scope.toggleDropdown(false);
2819                         ev.preventDefault();
2820                         ev.stopPropagation();
2821                     } else if (ev.keyCode === keymap.KEY.TAB || ev.keyCode === keymap.KEY.ESC) {
2822                         scope.toggleDropdown(false);
2823                         ev.preventDefault();
2824                         ev.stopPropagation();
2825                     }
2826                 }
2827                 scope.$apply(); // TODO: Move this into each block to avoid expensive digest cycles
2828             });
2829             var outsideClick = function (e) {
2830                 var isElement = $isElement(angular.element(e.target), elem.parent(), $document);
2831                 if (!isElement) {
2832                     scope.toggleDropdown(false);
2833                     scope.$apply();
2834                 }
2835             };
2836             $documentBind.click('toggleFlag', outsideClick, scope);
2837             $documentBind.touch('toggleFlag', outsideClick, scope);
2838         }
2839     };
2840 }])
2841
2842 .directive("b2bDropdownGroup", ['$compile', '$templateCache', 'b2bUserAgent', function ($compile, $templateCache, b2bUserAgent) {
2843     return {
2844         restrict: 'A',
2845         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
2846             if ((scope.isInputDropdown && b2bUserAgent.notMobile()) || (!scope.isInputDropdown)) {
2847                 var innerHtml = angular.element('<div></div>').append(elem.html());
2848                 innerHtml = ($compile(innerHtml)(scope)).html();
2849                 var template = angular.element($templateCache.get('b2bTemplate/dropdowns/b2bDropdownGroupDesktop.html'));
2850                 template.attr('ng-repeat', attr.optGroupRepeat);
2851                 template.attr('label', elem.attr('label'));
2852                 template.find('ul').append(innerHtml);
2853                 elem.replaceWith(template);
2854             } else if (scope.isInputDropdown && b2bUserAgent.isMobile()) {
2855                 var template = angular.element(elem.prop('outerHTML'));
2856                 template.attr('ng-repeat', attr.optGroupRepeat);
2857                 template.removeAttr('b2b-dropdown-group');
2858                 template.removeAttr('opt-group-repeat');
2859                 template = $compile(template)(scope);
2860                 elem.replaceWith(template);
2861             }
2862         }]
2863     };
2864 }])
2865
2866 .directive("b2bDropdownGroupDesktop", [function () {
2867     return {
2868         restrict: 'A',
2869         scope: true,
2870         link: function (scope, elem, attr, ctrl) {
2871             scope.groupHeader = attr.label;
2872         }
2873     };
2874 }])
2875
2876 .directive("b2bDropdownList", ['$compile', '$templateCache', 'b2bUserAgent', function ($compile, $templateCache, b2bUserAgent) {
2877     return {
2878         restrict: 'A',
2879         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {           
2880             if ((scope.isInputDropdown && b2bUserAgent.notMobile()) || (!scope.isInputDropdown)) {
2881                 var innerHtml = angular.element('<div></div>').append(elem.html());
2882                 innerHtml = ($compile(innerHtml)(scope)).html();
2883                 var template = angular.element($templateCache.get('b2bTemplate/dropdowns/b2bDropdownListDesktop.html'));
2884                 template.attr('ng-repeat', attr.optionRepeat);
2885                 template.attr('value', elem.attr('value'));
2886                 template.attr('search-key', elem.text());
2887                 if (elem.attr('aria-describedby')){
2888                     template.attr('aria-describedby', attr.ariaDescribedby);
2889                 }
2890                 if (elem.attr('imgsrc')) {
2891                     if (elem.attr('imgalt')) {
2892                         template.append('<img role="presentation" ng-src="' + elem.attr('imgsrc') + '" alt="' + elem.attr('imgalt') + '"/>');
2893                     } else {
2894                         template.append('<img role="presentation" ng-src="' + elem.attr('imgsrc') + '" alt=""/>');
2895                     }
2896                 }
2897                 template.append(innerHtml);
2898                 elem.replaceWith(template);
2899             } else if (scope.isInputDropdown && b2bUserAgent.isMobile()) {
2900                 var template = angular.element(elem.prop('outerHTML'));
2901                 template.attr('ng-repeat', attr.optionRepeat);
2902                 if (elem.attr('aria-describedby')){
2903                     template.attr('aria-describedby', attr.ariaDescribedby);
2904                 }
2905                 template.removeAttr('b2b-dropdown-list');
2906                 template.removeAttr('option-repeat');
2907                 template = $compile(template)(scope);
2908                 elem.replaceWith(template);
2909             }
2910         }]
2911     };
2912 }])
2913
2914 .directive("b2bDropdownListDesktop", ['$sce', 'keymap', 'b2bDropdownConfig', function ($sce, keymap, b2bDropdownConfig) {
2915     return {
2916         restrict: 'A',
2917         scope: true,
2918
2919         link: function (scope, elem, attr, ctrl) {
2920             var dropdownListValue = scope.dropdownListValue = attr.value;
2921             scope.dropdown.totalIndex++;
2922             var dropdownListIndex = scope.dropdown.totalIndex;
2923             scope.dropdownListValues.push(dropdownListValue);
2924             scope.dropdownLists[dropdownListValue] = [];
2925             scope.dropdownLists[dropdownListValue][0] = scope;
2926             scope.dropdownLists[dropdownListValue][1] = elem;
2927             scope.dropdownLists[dropdownListValue][2] = dropdownListIndex;
2928             scope.$parent.$parent.dropdownTextList=[];                                
2929             scope.updateDropdownValue = function () {
2930                 scope.currentSelected.value = dropdownListValue;
2931                 if (scope.isInputDropdown) {
2932                     scope.currentSelected.text = elem.text();
2933                     scope.currentSelected.label = elem.text();
2934                 } else if ((scope.dropdownType === b2bDropdownConfig.linkMenuKeyword) || (scope.dropdownType === b2bDropdownConfig.menuKeyword && scope.dropdownSize === b2bDropdownConfig.smallKeyword)) {
2935                     scope.currentSelected.text = dropdownListValue;
2936                     scope.currentSelected.label = dropdownListValue;
2937                 } else if (scope.dropdownType === b2bDropdownConfig.menuKeyword) {
2938                     scope.currentSelected.text = $sce.trustAsHtml(elem.html());
2939                     scope.currentSelected.label = elem.text();
2940                 }
2941                 scope.currentSelected.index = dropdownListIndex;
2942                 scope.updateModel();
2943             };
2944             scope.selectDropdownItem = function () {
2945                 scope.setDirty();
2946                 scope.updateDropdownValue();
2947                 scope.toggleDropdown(false);
2948             };
2949             scope.highlightDropdown = function () {
2950                 scope.dropdown.highlightedValue = dropdownListValue;
2951             };
2952             elem.bind('mouseover', function (ev) {
2953                 elem[0].focus();
2954             });
2955
2956             elem.bind('keydown', function (ev) {
2957                 if (!ev.keyCode) {
2958                     if (ev.which) {
2959                         ev.keyCode = ev.which;
2960                     } else if (ev.charCode) {
2961                         ev.keyCode = ev.charCode;
2962                     }
2963                 }
2964                 if (ev.altKey === true && ev.keyCode === keymap.KEY.UP) {
2965                     scope.toggleDropdown(false);
2966                     ev.preventDefault();
2967                     ev.stopPropagation();
2968                 } else if (ev.keyCode === keymap.KEY.TAB || ev.keyCode === keymap.KEY.ESC) {
2969                     scope.toggleDropdown(false);
2970                     ev.preventDefault();
2971                     ev.stopPropagation();
2972                 }
2973                 scope.$apply();
2974             });
2975             scope.$on('$destroy',function(){
2976                 scope.removeItem(dropdownListValue);
2977             });
2978         }
2979     };
2980 }])
2981
2982 .directive("b2bDropdownRepeat", ['$compile', 'b2bUserAgent', function ($compile, b2bUserAgent) {
2983     return {
2984         restrict: 'A',
2985         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
2986             if ((scope.isInputDropdown && b2bUserAgent.notMobile()) || (!scope.isInputDropdown)) {
2987                 var innerHtml = angular.element('<div></div>').append(elem.html());
2988                 innerHtml = ($compile(innerHtml)(scope)).html();
2989                 var template = angular.element('<div></div>');
2990                 template.attr('ng-repeat', attr.b2bDropdownRepeat);
2991                 template.append(innerHtml);
2992                 elem.replaceWith(template);
2993             } else if (scope.isInputDropdown && b2bUserAgent.isMobile()) {
2994                 angular.noop();
2995             }
2996         }]
2997     };
2998 }])
2999
3000 .directive("b2bDropdownValidation", ['$timeout', function ($timeout) {
3001     return {
3002         restrict: 'A',
3003         require: 'ngModel',
3004         link: function (scope, elem, attr, ctrl) {
3005             $timeout(function () {
3006                 scope.setNgModelController(attr.name, ctrl);
3007             }, 100);
3008             scope.setDirty = function () {
3009                 if (ctrl.$dirty === false) {
3010                     ctrl.$dirty = true;
3011                     ctrl.$pristine = false;
3012                 }
3013             };
3014             scope.setTouched = function () {
3015                 if (ctrl.$touched === false) {
3016                     ctrl.$touched = true;
3017                     ctrl.$pristine = false;
3018                 }
3019             };
3020             scope.setRequired = function (flag) {
3021                 ctrl.$setValidity('required', flag);
3022             };
3023         }
3024     };
3025 }])
3026
3027 .directive('b2bDropdownOptionalCta', [function () {
3028     return {
3029         restrict: 'EA',
3030         transclude: true,
3031         replace: true,
3032         template: '',
3033         compile: function (elem, attr, transclude) {
3034             return function link(scope, elem, attr, ctrl) {
3035                 if (scope.setOptionalCta) {
3036                     scope.setOptionalCta(transclude(scope, function () {}));
3037                 }
3038                 elem.remove();
3039             };
3040         }
3041     };
3042 }]);
3043 /**
3044  * @ngdoc directive
3045  * @name Forms.att:File Upload
3046  *
3047  * @description
3048  *  <file src="src/fileUpload/docs/readme.md" />
3049  *
3050  * @usage
3051  * 
3052 <form id="dragDropFile">                
3053     <div b2b-file-drop file-model="fileModel" on-drop="triggerFileUpload()"  align="center">
3054         <p>
3055             <br>To upload a file, drag & drop it here or 
3056                         <span b2b-file-link file-model="fileModel" on-file-select="triggerFileUpload()" >
3057                                 click here to select from your computer.
3058                         </span><br>
3059         </p>
3060     </div>
3061 </form>
3062  *
3063  * @example
3064  *  <section id="code">
3065         <example module="b2b.att">
3066             <file src="src/fileUpload/docs/demo.html" />
3067             <file src="src/fileUpload/docs/demo.js" />
3068        </example>
3069     </section>
3070  *
3071  */
3072 angular.module('b2b.att.fileUpload', ['b2b.att.utilities'])
3073     .directive('b2bFileDrop', [function() {
3074             return {
3075                 restrict: 'EA',
3076                 scope: {
3077                     fileModel: '=',
3078                     onDrop: '&'
3079                 },
3080                                 controller: ['$scope', '$attrs', function($scope, $attrs) {
3081                     this.onDrop = $scope.onDrop;
3082                 }],
3083                 link: function(scope, element) {
3084                     element.addClass('b2b-dragdrop');
3085                     element.bind(
3086                         'dragover',
3087                         function(e) {
3088                             if (e.originalEvent) {
3089                                 e.dataTransfer = e.originalEvent.dataTransfer;
3090                             }
3091                             e.dataTransfer.dropEffect = 'move';
3092                             // allows us to drop
3093                             if (e.preventDefault) {
3094                                 e.preventDefault();
3095                             }
3096                             element.addClass('b2b-dragdrop-over');
3097                             return false;
3098                         }
3099                     );
3100                     element.bind(
3101                         'dragenter',
3102                         function(e) {
3103                             // allows us to drop
3104                             if (e.preventDefault) {
3105                                 e.preventDefault();
3106                             }
3107                             element.addClass('b2b-dragdrop-over');
3108                             return false;
3109                         }
3110                     );
3111                     element.bind(
3112                         'dragleave',
3113                         function() {
3114                             element.removeClass('b2b-dragdrop-over');
3115                             return false;
3116                         }
3117                     );
3118                     element.bind(
3119                         'drop',
3120                         function(e) {
3121                             // Stops some browsers from redirecting.
3122                             if (e.preventDefault) {
3123                                 e.preventDefault();
3124                             }
3125                             if (e.stopPropagation) {
3126                                 e.stopPropagation();
3127                             }
3128                             if (e.originalEvent) {
3129                                 e.dataTransfer = e.originalEvent.dataTransfer;
3130                             }
3131                             element.removeClass('b2b-dragdrop-over');
3132                             if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
3133                                 scope.fileModel = e.dataTransfer.files[0];
3134                                 scope.$apply();
3135                                 if (angular.isFunction(scope.onDrop)) {
3136                                     scope.onDrop();
3137                                 }
3138                             }
3139                             return false;
3140                         }
3141                     );
3142                 }
3143             };
3144         }])
3145         .directive('b2bFileLink', [function() {
3146             return {
3147                 restrict: 'EA',
3148                 require: '^?b2bFileDrop',
3149                 replace: true,
3150                 transclude: true,
3151                 templateUrl: 'b2bTemplate/fileUpload/fileUpload.html',
3152                 scope: {
3153                     fileModel: '=?',
3154                     onFileSelect: '&'
3155                 },
3156                 controller: ['$scope', function($scope) {
3157                     this.setFileModel = function(fileModel) {
3158                         if ($scope.takeFileModelFromParent) {
3159                             $scope.$parent.fileModel = fileModel;
3160                             $scope.$parent.$apply();
3161                         } else {
3162                             $scope.fileModel = fileModel;
3163                             $scope.$apply();
3164                         }
3165                     };
3166                     this.callbackFunction = function() {
3167                         if (angular.isFunction($scope.onFileSelect)) {
3168                             $scope.onFileSelect();
3169                         }
3170                     };
3171                 
3172                 }],
3173                 link: function(scope, element, attr, b2bFileDropCtrl) {
3174                     scope.takeFileModelFromParent = false;
3175                     if (!(attr.fileModel) && b2bFileDropCtrl) {
3176                         scope.takeFileModelFromParent = true;
3177                     }
3178                     if (!(attr.onFileSelect) && b2bFileDropCtrl) {
3179                         scope.onFileSelect = b2bFileDropCtrl.onDrop;
3180                     }
3181                 }
3182             };
3183         }])
3184         .directive('b2bFileChange', ['$log', '$rootScope', function($log, $rootScope) {
3185             return {
3186                 restrict: 'A',
3187                 require: '^b2bFileLink',
3188                 link: function(scope, element, attr, b2bFileLinkCtrl) {
3189                     element.bind('change', changeFileModel);
3190
3191                     function changeFileModel(e) {
3192                         if (e.target.files && e.target.files.length > 0) {
3193                             b2bFileLinkCtrl.setFileModel(e.target.files[0]);
3194                             b2bFileLinkCtrl.callbackFunction();
3195                         } else {
3196                             var strFileName = e.target.value;
3197                             try {
3198                                 var objFSO = new ActiveXObject("Scripting.FileSystemObject");
3199                                 b2bFileLinkCtrl.setFileModel(objFSO.getFile(strFileName));
3200                                 b2bFileLinkCtrl.callbackFunction();
3201                             } catch (e) {
3202                                 var errMsg = "There was an issue uploading " + strFileName + ". Please try again.";
3203                                 $log.error(errMsg);
3204                                 $rootScope.$broadcast('b2b-file-link-failure', errMsg);
3205                             }
3206                         }
3207                     }
3208                 }
3209             };
3210         }]);
3211 /**
3212  * @ngdoc directive
3213  * @name Navigation.att:filters
3214  *
3215  * @description
3216  *  <file src="src/filters/docs/readme.md" />
3217  *
3218  * @usage
3219  *  <div b2b-filters></div>
3220  *
3221  * @example
3222  *      <section id="code">
3223            <b>HTML + AngularJS</b>
3224             <example module="b2b.att">
3225             <file src="src/filters/docs/demo.html" />
3226             <file src="src/filters/docs/demo.js" />
3227        </example>
3228         </section>
3229  * 
3230  */
3231 angular.module('b2b.att.filters', ['b2b.att.utilities', 'b2b.att.multipurposeExpander'])
3232     .filter('filtersSelectedItemsFilter', [function () {
3233         return function (listOfItemsArray) {
3234
3235             if (!listOfItemsArray) {
3236                 listOfItemsArray = [];
3237             }
3238
3239             var returnArray = [];
3240
3241             for (var i = 0; i < listOfItemsArray.length; i++) {
3242                 for (var j = 0; j < listOfItemsArray[i].filterTypeItems.length; j++) {
3243                     if (listOfItemsArray[i].filterTypeItems[j].selected && !listOfItemsArray[i].filterTypeItems[j].inProgress) {
3244                         returnArray.push(listOfItemsArray[i].filterTypeItems[j]);
3245                     }
3246                 }
3247             }
3248
3249             return returnArray;
3250         };
3251     }]);
3252 /**
3253  * @ngdoc directive
3254  * @name Messages, modals & alerts.att:flyout
3255  *
3256  * @description
3257  *  <file src="src/flyout/docs/readme.md" />
3258  * @example
3259  *  <section id="code">
3260         <example module="b2b.att">
3261             <file src="src/flyout/docs/demo.html" />
3262             <file src="src/flyout/docs/demo.js" />
3263        </example>
3264     </section>
3265  *
3266  */
3267 angular.module('b2b.att.flyout', ['b2b.att.utilities', 'b2b.att.position'])
3268     .directive('b2bFlyout', ['$timeout', 'b2bDOMHelper', 'keymap', 'events', function ($timeout, b2bDOMHelper, keymap, events) {
3269         return {
3270             restrict: 'EA',
3271             transclude: true,
3272             templateUrl: 'b2bTemplate/flyout/flyout.html',
3273             controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
3274                 scope.flyoutOpened = false;
3275                 var contentScope = '';
3276                 var togglerScope = '';
3277                 this.registerContentScope = function (scp) {
3278                     contentScope = scp;
3279                 };
3280                 this.registerTogglerScope = function (scp) {
3281                     togglerScope = scp;
3282                 };
3283
3284                 this.toggleFlyoutState = function () {
3285                     if (contentScope) {
3286                         contentScope.toggleFlyout();
3287                     }
3288                 };
3289                 this.getTogglerDimensions = function () {
3290                     return togglerScope.getTogglerDimensions();
3291                 }
3292                 this.setTogglerFocus = function () {
3293                     return togglerScope.setTogglerFocus();
3294                 }
3295
3296                 this.closeFlyout = function (e) {
3297                     contentScope.closeFromChild(e);
3298                 };
3299                 this.gotFocus = function () {
3300                     contentScope.gotFocus();
3301                 };
3302
3303                 this.updateAriaModel = function (val) {
3304                     scope.flyoutOpened = val;
3305                 };
3306
3307                 var firstTabableElement = undefined,
3308                     lastTabableElement = undefined;
3309
3310                 var firstTabableElementKeyhandler = function (e) {
3311                     if (!e.keyCode) {
3312                         e.keyCode = e.which;
3313                     }
3314                     if (e.keyCode === keymap.KEY.TAB && e.shiftKey && scope.flyoutOpened) { 
3315                         contentScope.gotFocus();
3316                         events.preventDefault(e);
3317                         events.stopPropagation(e);
3318                     }
3319                 };
3320
3321                 var lastTabableElementKeyhandler = function (e) {
3322                     if (!e.keyCode) {
3323                         e.keyCode = e.which;
3324                     }
3325                     if (e.keyCode === keymap.KEY.TAB && !e.shiftKey) {
3326                         contentScope.gotFocus();    
3327                         events.preventDefault(e);
3328                         events.stopPropagation(e);
3329                     }
3330                 };
3331                 this.associateTabEvent = function(){
3332                     $timeout(function () {
3333                         var element = elem[0].getElementsByClassName('b2b-flyout-container')[0];
3334                         firstTabableElement = b2bDOMHelper.firstTabableElement(element);
3335                         lastTabableElement = b2bDOMHelper.lastTabableElement(element);
3336                         if(angular.isUndefined(firstTabableElement)){
3337                             angular.element(element).css('display','block');
3338                             firstTabableElement = b2bDOMHelper.firstTabableElement(element);
3339                             lastTabableElement = b2bDOMHelper.lastTabableElement(element);
3340                             angular.element(element).css('display','none');
3341                         }
3342                         angular.element(firstTabableElement).bind('keydown', firstTabableElementKeyhandler);
3343                         angular.element(lastTabableElement).bind('keydown', lastTabableElementKeyhandler);
3344                     });
3345                 }
3346                 this.updateTabbableElements = function(){
3347                     $timeout(function () {
3348                         var element = elem[0].getElementsByClassName('b2b-flyout-container')[0];
3349                         angular.element(element).css('display','block');
3350                         firstTabableElement = b2bDOMHelper.firstTabableElement(element);
3351                         lastTabableElement = b2bDOMHelper.lastTabableElement(element);
3352                         angular.element(firstTabableElement).bind('keydown', firstTabableElementKeyhandler);
3353                         angular.element(lastTabableElement).bind('keydown', lastTabableElementKeyhandler);
3354                         angular.element(element).css('display','none');
3355                     });
3356                 }
3357                 this.unbindTabbaleEvents = function(){
3358                     if(angular.isDefined(firstTabableElement)){
3359                         angular.element(firstTabableElement).unbind('keydown', firstTabableElementKeyhandler);
3360                     }
3361
3362                     if(angular.isDefined(lastTabableElement)){
3363                         angular.element(lastTabableElement).unbind('keydown', lastTabableElementKeyhandler);
3364                     }
3365                 }
3366             }],
3367             link: function (scope, element, attrs, ctrl) {
3368
3369             }
3370         };
3371     }])
3372     .directive('b2bFlyoutToggler', [function () {
3373         return {
3374             restrict: 'A',
3375             require: '^b2bFlyout',
3376             link: function (scope, element, attrs, ctrl) {
3377                 element.bind('click', function (e) {
3378                     ctrl.toggleFlyoutState();
3379                 });
3380
3381                 scope.getTogglerDimensions = function () {
3382                     return element[0].getBoundingClientRect();
3383                 }
3384
3385                 scope.setTogglerFocus = function () {
3386                     element[0].focus();
3387                 }
3388
3389                 ctrl.registerTogglerScope(scope);
3390             }
3391         };
3392     }])
3393     .directive('b2bFlyoutContent', ['$position', '$timeout', '$documentBind', '$isElement', '$document', function ($position, $timeout, $documentBind, $isElement, $document) {
3394         return {
3395             restrict: 'EA',
3396             transclude: true,
3397             replace: true,
3398             require: '^b2bFlyout',
3399             scope: {
3400                 horizontalPlacement: '@',
3401                 verticalPlacement: '@',
3402                 flyoutStyle: '@',
3403                 flyoutTitle: '@',
3404                 contentUpdated: "=?"
3405             },
3406             templateUrl: 'b2bTemplate/flyout/flyoutContent.html',
3407             link: function (scope, element, attrs, ctrl) {
3408                 var flyoutStyleArray, eachCssProperty, cssPropertyKey, cssPropertyVal, temp;
3409                 scope.openFlyout = false;
3410                 if (!scope.horizontalPlacement) {
3411                     scope.horizontalPlacement = 'center';
3412                 }
3413                 if (!scope.verticalPlacement) {
3414                     scope.verticalPlacement = 'below';
3415                 }
3416
3417                 scope.toggleFlyout = function () {
3418
3419                     scope.openFlyout = !scope.openFlyout;
3420
3421                     if (scope.openFlyout) {
3422
3423                         if (angular.isDefined(scope.flyoutStyle) && scope.flyoutStyle != "") {
3424                             flyoutStyleArray = scope.flyoutStyle.split(";");
3425                             for (i = 0; i < flyoutStyleArray.length; i++) {
3426                                 eachCssProperty = flyoutStyleArray[i].split(":");
3427                                 if (eachCssProperty.length == 2) {
3428                                     cssPropertyKey = eachCssProperty[0].trim();
3429                                     cssPropertyVal = eachCssProperty[1].trim();
3430                                     angular.element(element[0])[0].style[cssPropertyKey] = cssPropertyVal;
3431                                 }
3432                             }
3433                         }
3434
3435                         angular.element(element[0]).css({
3436                             'opacity': 0,
3437                             'display': 'block'
3438                         });
3439
3440                         var flyoutIcons = angular.element(document.querySelectorAll(".b2b-flyout-icon"));
3441                         angular.forEach(flyoutIcons, function (elm) {
3442                             angular.element(elm)[0].blur();
3443                         });
3444
3445                         $timeout(function () {
3446                             ctrl.setTogglerFocus();
3447
3448                             var togglerDimensions = ctrl.getTogglerDimensions();
3449                             var flyoutDimensions = element[0].getBoundingClientRect();
3450
3451                             switch (scope.horizontalPlacement) {
3452                             case "left":
3453                                 angular.element(element[0]).css({
3454                                     'left': ((togglerDimensions.width / 2) - 26) + 'px'
3455                                 });
3456                                 break;
3457                             case "right":
3458                                 angular.element(element[0]).css({
3459                                     'right': ((togglerDimensions.width / 2) - 23) + 'px'
3460                                 });
3461                                 break;  
3462
3463                             case "centerLeft":
3464                                 var marginLeft =  10-(flyoutDimensions.width)-20;
3465                                 angular.element(element[0]).css({
3466                                     'margin-left': marginLeft + 'px'
3467                                 });
3468                                 break;
3469                             case "centerRight":
3470                                 angular.element(element[0]).css({
3471                                     'left': ((togglerDimensions.width + 9 )) + 'px'
3472                                 });
3473                                 break;    
3474
3475                             default:
3476                                 var marginLeft = (togglerDimensions.width / 2) - (flyoutDimensions.width / 2) - 8;
3477                                 angular.element(element[0]).css({
3478                                     'margin-left': marginLeft + 'px'
3479                                 });
3480                             }
3481
3482                             switch (scope.verticalPlacement) {
3483                             case "above":
3484                                 angular.element(element[0]).css({
3485                                     'top': -(flyoutDimensions.height + 13) + 'px'
3486                                 });
3487                                 break;
3488                             case "centerLeft":
3489                                 angular.element(element[0]).css({
3490                                     'top': -((togglerDimensions.height-13))+ 'px'
3491                                 });
3492                                 break;
3493                             case "centerRight":
3494                                 angular.element(element[0]).css({
3495                                     'top': -(flyoutDimensions.height - 23)+ 'px'
3496                                 });
3497                                 break;                                    
3498                             default:
3499                                 angular.element(element[0]).css({
3500                                     'top': (togglerDimensions.height + 13) + 'px'
3501                                 });
3502                             }
3503
3504                             angular.element(element[0]).css({
3505                                 'opacity': 1
3506                             });
3507                         }, 100);
3508                     } else {
3509                         scope.hideFlyout();
3510                     }
3511                 };
3512
3513                 scope.gotFocus = function () {
3514                     scope.openFlyout = false;
3515                     scope.hideFlyout();
3516                     ctrl.setTogglerFocus();
3517                     scope.$apply();
3518                 };
3519
3520                 scope.closeFromChild = function (e) {
3521                     scope.openFlyout = false;
3522                     scope.hideFlyout();
3523                     ctrl.setTogglerFocus();
3524                     scope.$apply();
3525                 };
3526
3527                 scope.hideFlyout = function () {
3528                     angular.element(element[0]).css({
3529                         'opacity': 0,
3530                         'display': 'none'
3531                     });
3532                 };
3533
3534                 scope.closeFlyout = function (e) {
3535                     var isElement = $isElement(angular.element(e.target), element, $document);
3536                     if ((e.type === "keydown" && e.which === 27) || ((e.type === "click" || e.type==="touchend") && !isElement)) {
3537                         scope.openFlyout = false;
3538                         scope.hideFlyout();
3539                         ctrl.setTogglerFocus();
3540                         scope.$apply();
3541                     }
3542                 };
3543
3544                 scope.$watch('openFlyout', function () {
3545                     ctrl.updateAriaModel(scope.openFlyout);
3546                 });
3547
3548                 $documentBind.click('openFlyout', scope.closeFlyout, scope);
3549                 $documentBind.event('keydown', 'openFlyout', scope.closeFlyout, scope);
3550                 $documentBind.event('touchend', 'openFlyout', scope.closeFlyout, scope);
3551                 ctrl.registerContentScope(scope);
3552
3553                 if (angular.isDefined(scope.contentUpdated) && scope.contentUpdated !== null) {
3554                     scope.$watch('contentUpdated', function (newVal, oldVal) {
3555                         if(newVal){
3556                             if (newVal !== oldVal) {
3557                                 ctrl.unbindTabbaleEvents();
3558                                 ctrl.associateTabEvent();
3559                             }
3560                             scope.contentUpdated = false;
3561                         } 
3562                     });
3563                 }  
3564
3565             }
3566         };
3567     }])
3568     .directive('b2bCloseFlyout', [function () {
3569         return {
3570             restrict: 'A',
3571             require: '^b2bFlyout',
3572             scope: {
3573                 closeFlyout: '&'
3574             },
3575             link: function (scope, element, attrs, ctrl) {
3576                 element.bind('click touchstart', function (e) {
3577                     scope.closeFlyout(e);
3578                     ctrl.closeFlyout(e);
3579                 });
3580             }
3581         };
3582     }])
3583     .directive('b2bFlyoutTrapFocusInside', [function () {
3584         return {
3585             restrict: 'A',
3586             transclude: false,
3587             require: '^b2bFlyout',
3588             link: function (scope, elem, attr, ctrl) {
3589                 /* Before opening modal, find the focused element */
3590                 ctrl.updateTabbableElements();
3591             }
3592         };
3593     }]);
3594 /**
3595  * @ngdoc directive
3596  * @name Layouts.att:footer
3597  *
3598  * @description
3599  *  <file src="src/footer/docs/readme.md" />
3600  *
3601  * @usage
3602  * 
3603  <footer class="b2b-footer-wrapper" role="contentinfo" aria-label="footer">
3604         <div class="b2b-footer-container" b2b-column-switch-footer footer-link-items='footerItems'>
3605             <hr>
3606             <div class="divider-bottom-footer">
3607                 <div class="span2 dispalyInline">&nbsp;</div>
3608                 <div class="span6 dispalyInline">
3609                     <ul class="footer-nav-content">
3610                         <li><a href="Terms_of_use.html" title="Terms of use" id="foot0">Terms of use</a>|</li>
3611                         <li><a href="Privacy_policy.html" title="Privacy policy" id="foot1" class="active">Privacy policy</a>|</li>
3612                         <li><a href="Tollfree_directory_assistance.html" title="Tollfree directory assistance" id="foot2">Tollfree directory assistance</a>|</li>
3613                         <li><a href="compliance.html" title="Accessibility" id="foot3">Accessibility</a></li>
3614
3615                     </ul>
3616                     <p><a href="//www.att.com/gen/privacy-policy?pid=2587" target="_blank">© <span class="copyright">2016</span> AT&amp;T Intellectual Property</a>. All rights reserved. AT&amp;T,the AT&amp;T Globe logo and all other AT&amp;T marks contained herein are tardemarks of AT&amp;T intellectual property and/or AT&amp;T affiliated companines.
3617
3618                     </p>
3619                 </div>
3620                 <div class="span3 footerLogo dispalyInline">
3621                     <a href="index.html" class="footer-logo">
3622                         <i class="icon-primary-att-globe"><span class="hidden-spoken">A T &amp; T</span></i>
3623                         <h2 class="logo-title">AT&amp;T</h2>
3624                     </a>
3625                 </div>
3626             </div>
3627
3628         </div>  
3629     </footer>
3630
3631  * @example
3632  *  <section id="code">   
3633  <example module="b2b.att">
3634  <file src="src/footer/docs/demo.html" />
3635  <file src="src/footer/docs/demo.js" />
3636  </example>
3637  </section>
3638  *
3639  */
3640 angular.module('b2b.att.footer', ['b2b.att.utilities']).
3641         directive('b2bColumnSwitchFooter', [function() {
3642                 return {
3643                     restrict: 'A',
3644                     transclude: true,
3645                     scope: {
3646                         footerLinkItems: "="
3647                     },
3648                     templateUrl: 'b2bTemplate/footer/footer_column_switch_tpl.html',
3649                     link: function(scope) {
3650                                                 var tempFooterColumns = scope.footerLinkItems.length;
3651                                                 scope.footerColumns = 3;
3652                         if ( (tempFooterColumns === 5) || (tempFooterColumns === 4) ) {
3653                                                         scope.footerColumns = tempFooterColumns;
3654                         }
3655                     }
3656
3657                 };
3658
3659             }]);
3660      
3661
3662 /**
3663  * @ngdoc directive
3664  * @name Layouts.att:header
3665  *
3666  * @description
3667  *  <file src="src/header/docs/readme.md" />
3668  *
3669  * @usage
3670  *  <li b2b-header-menu class="header__item b2b-headermenu" ng-repeat="item in tabItems" role="presentation">
3671         <a href="#" class="menu__item" role="menuitem">{{item.title}}</a>
3672         <div class="header-secondary-wrapper">
3673             <ul class="header-secondary" role="menu">
3674                 <li class="header-subitem" b2b-header-submenu ng-repeat="i in item.subitems" role="presentation">
3675                     <a href="#" class="menu__item" aria-haspopup="true" role="menuitem">{{i.value}}</a>
3676                     <div class="header-tertiary-wrapper" ng-if="i.links">
3677                         <ul class="header-tertiary" role="menu">
3678                             <li b2b-header-tertiarymenu ng-repeat="link in i.links" role="presentation">
3679                                 <label>{{link.title}}</label>
3680                                 <div b2b-tertiary-link ng-repeat="title in link.value">
3681                                     <a href="{{link.href}}" class="header-tertiaryitem" ng-if="!title.subitems" aria-haspopup="false" role="menuitem"><span class="b2b-label-hide">{{link.title}}</span>{{title.title}}</a>
3682                                     <a href="{{link.href}}" class="header-tertiaryitem" b2b-header-togglemenu ng-if="title.subitems" aria-haspopup="true" role="menuitem"><span class="b2b-label-hide">{{link.title}}</span>{{title.title}}</a>
3683                                     <ul class="header-quarternary" role="menu"  ng-if="title.subitems">
3684                                         <li b2b-header-quarternarymenu role="presentation">
3685                                             <a href="{{nav.href}}" ng-repeat="nav in title.subitems" role="menuitem" aria-haspopup="true">{{nav.title}}</a>
3686                                         </li>
3687                                     </ul>
3688                                 </div>
3689                             </li>
3690                         </ul>
3691                     </div>
3692                 </li>
3693             </ul>
3694         </div>
3695     </li> 
3696  *
3697  * @example
3698  *  <section id="code">
3699  <example module="b2b.att.header">
3700  <file src="src/header/docs/demo.html" />
3701  <file src="src/header/docs/demo.js" />
3702  </example>
3703  </section>
3704  *
3705  */
3706 angular.module('b2b.att.header', ['b2b.att.dropdowns','b2b.att.utilities'])
3707         .directive('b2bHeaderMenu', ['keymap', '$documentBind', '$timeout', '$isElement', '$document', function (keymap, $documentBind, $timeout, $isElement, $document) {
3708         return {
3709             restrict: 'A',
3710             controller:['$scope',function($scope){
3711                 this.nextSiblingFocus = function (elObj,flag) {
3712                         if (elObj.nextElementSibling) {
3713                             if(flag){
3714                                 var nextmenuItem = this.getFirstElement(elObj.nextElementSibling,'a');
3715                                 nextmenuItem.focus();
3716                             }else{
3717                                 elObj.nextElementSibling.focus();
3718                             }
3719                         }
3720                 };
3721                 
3722                 this.previousSiblingFocus = function (elObj,flag) {
3723                         if (elObj.previousElementSibling) {
3724                             if(flag){
3725                                 var prevmenuItem = this.getFirstElement(elObj.previousElementSibling,'a');
3726                                 prevmenuItem.focus();
3727                             }else{
3728                                 elObj.previousElementSibling.focus();
3729                             }
3730                         }
3731                 };
3732                     
3733                 this.getFirstElement = function(elmObj,selector){
3734                         return elmObj.querySelector(selector);                        
3735                     };
3736             }],
3737             link: function (scope, elem,attr,ctrl) {
3738                 scope.showMenu = false;
3739                 var activeElm, subMenu, tertiaryMenu, el= angular.element(elem)[0], 
3740                         menuItem = angular.element(elem[0].children[0]);
3741                 menuItem.bind('click', function () {
3742                     elem.parent().children().removeClass('active');
3743                     elem.addClass('active');
3744                     var elems= this.parentElement.parentElement.querySelectorAll('li[b2b-header-menu]>a');
3745                     for (var i=0; i<elems.length; i++) {
3746                         elems[i].setAttribute("aria-expanded",false);
3747                     }
3748                     scope.showMenu = true;
3749                     var elmTofocus = ctrl.getFirstElement(this.parentElement,'li[b2b-header-submenu]');
3750                     elmTofocus.firstElementChild.focus();
3751                     this.setAttribute('aria-expanded',true);
3752                     scope.$apply();
3753                 });
3754                
3755                 elem.bind('keydown', function (evt) {
3756                     activeElm = document.activeElement;
3757                     subMenu = ctrl.getFirstElement(activeElm.parentElement,'li[b2b-header-submenu]');
3758                     tertiaryMenu = ctrl.getFirstElement(activeElm.parentElement,'li[b2b-header-tertiarymenu]');
3759                     switch (evt.keyCode) {
3760                         case keymap.KEY.ENTER:
3761                         case keymap.KEY.SPACE:
3762                             elem[0].click();
3763                             break;
3764                         case keymap.KEY.UP:
3765                             evt.stopPropagation();
3766                             evt.preventDefault();
3767                             if (activeElm.parentElement.hasAttribute('b2b-header-submenu')) {
3768                                 menuItem[0].focus();
3769                             }
3770                             break;
3771                         case keymap.KEY.DOWN:
3772                             evt.stopPropagation();
3773                             evt.preventDefault();
3774                             if (subMenu) {
3775                                 subMenu.firstElementChild.focus();
3776                             } else if (tertiaryMenu) {
3777                                 var firstSubitem = ctrl.getFirstElement(tertiaryMenu,'a.header-tertiaryitem');
3778                                 firstSubitem.focus();
3779                             }
3780                             break;
3781                         case keymap.KEY.RIGHT:
3782                             evt.stopPropagation();
3783                             evt.preventDefault();
3784                             if (activeElm.parentElement.hasAttribute('b2b-header-submenu')) {
3785                                 var elm = angular.element(activeElm.parentElement)[0];
3786                                 ctrl.nextSiblingFocus(elm,true);
3787                             } else if (activeElm.parentElement.parentElement.hasAttribute('b2b-header-tertiarymenu')) {
3788                                 var tertiaryLI = angular.element(activeElm.parentElement.parentElement)[0];
3789                                 if (tertiaryLI.nextElementSibling) {
3790                                     var nextElm = ctrl.getFirstElement(tertiaryLI.nextElementSibling,"a.header-tertiaryitem");
3791                                     nextElm.focus();
3792                                 }
3793                             }
3794                             else if(activeElm.parentElement.hasAttribute('b2b-header-menu')){
3795                                 ctrl.nextSiblingFocus(el,true);
3796                             }
3797                             break;
3798                         case keymap.KEY.LEFT:
3799                             evt.stopPropagation();
3800                             evt.preventDefault();
3801                             if (activeElm.parentElement.hasAttribute('b2b-header-submenu')) {
3802                                 var previousElm = angular.element(activeElm.parentElement)[0];
3803                                 ctrl.previousSiblingFocus(previousElm,true);
3804                             } else if (activeElm.parentElement.parentElement.hasAttribute('b2b-header-tertiarymenu')) {
3805                                 var tertiaryLI = angular.element(activeElm.parentElement.parentElement)[0];
3806                                 if (tertiaryLI.previousElementSibling) {
3807                                     var prevElm = ctrl.getFirstElement(tertiaryLI.previousElementSibling,"a.header-tertiaryitem");
3808                                     prevElm.focus();
3809                                 }
3810                             }
3811                             else if(activeElm.parentElement.hasAttribute('b2b-header-menu')) {
3812                                 ctrl.previousSiblingFocus(el,true);
3813                             }
3814                             break;
3815                         case keymap.KEY.ESC:
3816                             evt.stopPropagation();
3817                             evt.preventDefault();
3818                             scope.showMenu = false;
3819                             elem.removeClass('active');
3820                                                         menuItem.attr('aria-expanded',false);
3821                                                         $timeout(function(){
3822                                                                 menuItem[0].focus();
3823                                                         },100);
3824                             scope.$apply();
3825                             break;
3826                         default:
3827                             break;
3828                     }
3829                 });
3830                 var outsideClick = function (e) {
3831                     var isElement = $isElement(angular.element(e.target), elem, $document);
3832                     if (!isElement) {
3833                         scope.showMenu = false;
3834                         elem.removeClass('active');
3835                         scope.$apply();
3836                     }
3837                 };
3838                 $documentBind.click('showMenu', outsideClick, scope);
3839             }
3840         };
3841     }]).directive('b2bHeaderSubmenu', ['$timeout',function ($timeout) {
3842         return{
3843             restrict: 'A',
3844             link: function (scope, elem) {
3845                 var caretSign = angular.element("<i class='menuCaret'></i>");
3846                 $timeout(function(){
3847                                         var menuItem = angular.element(elem[0].children[0]);
3848                                         menuItem.bind('focus mouseenter', function () {
3849                                                 elem.parent().children().removeClass('active');
3850                                                 elem.addClass('active');
3851                                                 if(elem[0].childElementCount > 1){ // > 1 has third level menu
3852                                                         menuItem.attr('aria-expanded',true);
3853                                                         menuItem.attr('aria-haspopup',true);
3854                                                 }
3855                                                 var caretLeft = (elem[0].offsetLeft +  elem[0].offsetWidth/2) - 10;
3856                                                 caretSign.css({left: caretLeft + 'px'});
3857                                                 angular.element(caretSign);
3858                                                 var tertiaryItems = elem[0].querySelectorAll('[b2b-header-tertiarymenu]');
3859                                                 if(tertiaryItems.length >=1){
3860                                                         elem.append(caretSign);
3861                                                 }
3862                                         });
3863                                         menuItem.bind('blur', function () {
3864                                                 $timeout(function () {
3865                                                         var parentElm = document.activeElement.parentElement.parentElement;
3866                                                         if(parentElm){
3867                                                                 if (!(parentElm.hasAttribute('b2b-header-tertiarymenu'))) {
3868                                                                         elem.removeClass('active');
3869                                                                         if(elem[0].childElementCount > 1){ // > 1 has third level menu
3870                                                                                 menuItem.attr('aria-expanded',false);
3871                                                                         }
3872                                                                         var caret = elem[0].querySelector('.menuCaret');
3873                                                                         if(caret){
3874                                                                                 caret.remove();
3875                                                                         }   
3876                                                                 }
3877                                                         }
3878                                                 });
3879                                         });
3880                 });
3881             }
3882         };
3883     }]).directive('b2bHeaderTertiarymenu', ['$timeout','keymap', function ($timeout,keymap){
3884         return{
3885             restrict: 'A',
3886             require:'^b2bHeaderMenu',
3887             link: function (scope, elem,attr,ctrl) {
3888                 
3889                 elem.bind('keydown', function (evt) {
3890                     var activeElm = document.activeElement;
3891                     var activeParentElm = activeElm.parentElement;
3892                     var activeParentObj  = angular.element(activeParentElm)[0];
3893                     
3894                     if(activeParentElm.hasAttribute('b2b-tertiary-link')){
3895                         var quarterNav = angular.element(activeParentElm)[0].querySelector('li[b2b-header-quarternarymenu]');
3896                         if(quarterNav){
3897                             var links = ctrl.getFirstElement(angular.element(quarterNav)[0],'a');
3898                         }
3899                     }
3900                     var tertiaryMenu = activeElm.parentElement.parentElement.parentElement;
3901                     var tertiaryMenuFlag = tertiaryMenu.hasAttribute('b2b-tertiary-link');
3902                     
3903                     switch (evt.keyCode) {
3904                         case keymap.KEY.DOWN:
3905                             evt.stopPropagation();
3906                             evt.preventDefault();
3907                             if (activeParentElm.hasAttribute('b2b-tertiary-link')) {
3908                                 if(angular.element(quarterNav).hasClass('active')){
3909                                     links.focus();
3910                                 }else if(activeParentObj.nextElementSibling){
3911                                     ctrl.nextSiblingFocus(activeParentObj,true);
3912                                 }
3913                             }
3914                             else if(angular.element(activeParentElm).hasClass('active')){
3915                                 ctrl.nextSiblingFocus(activeElm);
3916                             }
3917                             break;                        
3918                         case keymap.KEY.UP:
3919                             evt.stopPropagation();
3920                             evt.preventDefault();
3921                             if(activeParentElm.hasAttribute('b2b-tertiary-link')){
3922                                 if(activeParentObj.previousElementSibling.hasAttribute('b2b-tertiary-link')){
3923                                     ctrl.previousSiblingFocus(activeParentObj,true);
3924                                 }else{
3925                                     var elm = angular.element(activeElm.parentElement.parentElement.parentElement.parentElement.parentElement)[0];
3926                                     ctrl.getFirstElement(elm,"a").focus();
3927                                 }
3928                             }else if(angular.element(activeParentElm).hasClass('active')){
3929                                     if (activeElm.previousElementSibling) {
3930                                         ctrl.previousSiblingFocus(activeElm);
3931                                     }else if (tertiaryMenuFlag) {
3932                                         var elm = angular.element(tertiaryMenu)[0];
3933                                         ctrl.getFirstElement(elm,"a.header-tertiaryitem").focus();
3934                                     }
3935                                 }
3936                             break;
3937                         default:
3938                             break;
3939                     }
3940                 });
3941             }            
3942         };          
3943     }]).directive('b2bHeaderTogglemenu', ['$timeout', 'keymap', function ($timeout, keymap) {
3944         return{
3945             restrict: 'A',
3946             require: '^b2bHeaderMenu',
3947             link: function (scope, elem, attrs, ctrl) {
3948                 var quarterNav;
3949                 $timeout(function () {
3950                     quarterNav = angular.element(elem.parent())[0].querySelector('li[b2b-header-quarternarymenu]');
3951                     elem.bind('click', function () {
3952                         angular.element(quarterNav).toggleClass('active');
3953                     });
3954                 });
3955             }
3956         };
3957     }]).directive('b2bHeaderResponsive', ['$timeout',function ($timeout) {
3958         return{
3959             restrict: 'A',
3960                         controller: function($scope){
3961                                 this.applyMediaQueries = function(value){
3962                                         document.querySelector('style').textContent += 
3963                                                 "@media screen and (max-width:950px) { \
3964                                                         .header__item.profile { right: " + value + "px; } \
3965                                                 }";
3966                                 };
3967                                 this.arrangeResponsiveHeader = function(children){
3968                                         /* 
3969                                          * clientWidth of 1090 === max-width of 1100px
3970                                          * clientWidth of 920 === max-width of 950px
3971                                          * see b2b-angular.css for rest of responsive header CSS
3972                                          */
3973                                   if (document.documentElement.clientWidth <= 920) { 
3974                                                 switch(children){
3975                                                         case 1:
3976                                                                 this.applyMediaQueries(200);                                    
3977                                                                 break;
3978                                                         case 2:
3979                                                                 this.applyMediaQueries(200);                                                    
3980                                                                 break;
3981                                                         default: // anthing above 3, however, should not have more than 3 to date
3982                                                                 this.applyMediaQueries(200);                                                                                                                                                    
3983                                                 }
3984                                         }
3985                                 }
3986                         },
3987             link: function (scope, elem, attrs, ctrl) {
3988                                 var children;
3989                                 var profile;
3990                                 
3991                                 // onload of page
3992                                 $timeout(function(){ 
3993                                         profile = document.querySelector('li.header__item.profile');
3994                                         children = angular.element(profile).children().length;
3995                                         
3996                                         ctrl.arrangeResponsiveHeader(children); // shift right-side icon flyovers
3997                                 });
3998
3999                                 // on screen resize
4000                                 window.addEventListener('resize', function(event){ // caret adjustmet
4001                                         var activeSubmenu = elem[0].querySelector('[b2b-header-menu] [b2b-header-submenu].active');
4002                                         var activeSubmenuEl = angular.element(activeSubmenu);
4003                                         if(activeSubmenu){
4004                                                 var caretSign = activeSubmenu.querySelector('i.menuCaret');
4005                                                 if(caretSign){
4006                                                         var caretSignEl = angular.element(caretSign);
4007                                                         var caretLeft = (activeSubmenu.offsetLeft +  activeSubmenu.offsetWidth/2) - 10;
4008                                                         caretSignEl.css({left: caretLeft + 'px'});
4009                                                 }
4010                                         }
4011
4012                                         ctrl.arrangeResponsiveHeader(children); // shift right-side icon flyovers
4013                                 });
4014             }
4015         };
4016         }]);
4017
4018 /**
4019  * @ngdoc directive
4020  * @name Layouts.att:headings & copy
4021  *
4022  * @description
4023  *  <file src="src/headingsAndCopy/docs/readme.md" />
4024  *
4025  * @example
4026  <section id="code">
4027     <b>HTML + AngularJS</b>
4028     <example module="b2b.att">
4029     <file src="src/headingsAndCopy/docs/demo.html" />
4030 </example>
4031 </section>
4032  */
4033
4034 var b2bLegalCopy = angular.module('b2b.att.headingsAndCopy', []);
4035 /**
4036  * @ngdoc directive
4037  * @name Tabs, tables & accordions.att:horizontalTable
4038  *
4039  * @description
4040  *  <file src="src/horizontalTable/docs/readme.md" />
4041  *
4042  * @usage
4043  * @param {int} sticky - Number of sticky columns to have. Maximum of 3.
4044  * @param {boolean} refresh - A boolean that when set to true will force a re-render of table. Only use when using 'bulk mode'
4045  * @param {string} legendContent - A string of html to fill in the legend flyout. This should generally be a <ul> with <li> and should not rely on Angular for repeating.
4046  * @param {boolean} retainColumnSet - A boolean that on re-render of the table, determines if the columns visible should reset to 0 or not. Default is false. 
4047  * @example
4048  *  <section id="code">
4049         <example module="b2b.att">
4050             <file src="src/horizontalTable/docs/demo.html" />
4051             <file src="src/horizontalTable/docs/demo.js" />
4052        </example>
4053     </section>
4054  *
4055  */
4056 angular.module('b2b.att.horizontalTable', [])
4057     .constant('b2bHorizontalTableConfig', {
4058         'maxStickyColumns': 3
4059     })
4060     .directive('b2bHorizontalTable', ['$timeout', 'b2bHorizontalTableConfig', 'b2bDOMHelper', function ($timeout, b2bHorizontalTableConfig, b2bDOMHelper) {
4061         return {
4062             restrict: 'EA',
4063             scope: true,
4064             transclude: true,
4065             scope: {
4066                 numOfStickyCols: '=?sticky',
4067                 refresh: '=?',
4068                 legendContent: '=?',
4069                 retainColumnSet: '=?'
4070
4071             },
4072             templateUrl: 'b2bTemplate/horizontalTable/horizontalTable.html',
4073             link: function (scope, element, attrs, ctrl) {
4074                 scope.numOfStickyCols = scope.numOfStickyCols || 1;
4075                 scope.viewportIndex = scope.numOfStickyCols;
4076                 scope.countDisplayText = "";
4077                 var tableElement = element.find('table');
4078                 var thElements = element.find('th');
4079                 var innerContainer = angular.element(element[0].querySelector('.b2b-horizontal-table-inner-container'));
4080                 var outerContainer = angular.element(element[0].querySelector('.b2b-horizontal-table'));
4081
4082                 var tableColumns = [];
4083                 var tableRows = element.find('tr');
4084
4085                 var maxWidth = 0,
4086                     maxHeight = 0;
4087                 var totalWidth = element.children()[0].offsetWidth;
4088                 var lastVisibleColumn = 0;
4089                 var collectiveColumnWidth = [];
4090                 var collectiveRowHeight = [];
4091                 var columnSets = [];
4092                 var setIndex = 0; 
4093                 var stickyPixels = 0;
4094
4095                 var displayNoneCSS = {'display': 'none'};
4096                 var displayBlockCSS = {'display': 'table-cell'};
4097
4098                 var init = function() {
4099                     // Reset this from a previous execution
4100                     tableColumns = [];
4101                     collectiveColumnWidth = [];
4102                     collectiveRowHeight = [];
4103                     maxWidth = 0;
4104                     maxHeight = 0;
4105                     lastVisibleColumn = 0;
4106                     columnSets = [];
4107                     if ((!!scope.retainColumnSet)) {
4108                         setIndex = 0;
4109                     }
4110                     visibleColumns = [];
4111                     stickyPixels = 0;
4112
4113                     tableElement = element.find('table');
4114                     thElements = element.find('th');
4115                     innerContainer = angular.element(element[0].querySelector('.b2b-horizontal-table-inner-container'));
4116                     outerContainer = angular.element(element[0].querySelector('.b2b-horizontal-table'));
4117                     totalWidth = element.children()[0].offsetWidth;
4118                     tableRows = element.find('tr');
4119
4120                     scope.disableLeft = true;
4121                     scope.disableRight = false;
4122
4123                     if (scope.numOfStickyCols > b2bHorizontalTableConfig.maxStickyColumns) {
4124                         throw new Error('Table can only support ' + b2bHorizontalTableConfig.maxStickyColumns + ' sticky columns.');
4125                     }             
4126                     scope.countDisplayText = "";
4127                     for(var count = 1; count <= scope.numOfStickyCols; count++) {
4128                         scope.countDisplayText = scope.countDisplayText + count + ", "
4129                     }
4130                     angular.forEach(tableRows, function(row, rowIndex) {
4131                         for(var j = 0; j < row.children.length; j++) {
4132                             if (tableColumns[j] === undefined) {
4133                                 tableColumns[j] = [];
4134                             }
4135                             tableColumns[j].push(row.children[j]);
4136                         }
4137                     });
4138
4139                     // We need to reset all the displayNones from previous runs, if applicable
4140                     if (attrs.refresh !== undefined && attrs.refresh !== '')  {
4141                         for (var i = scope.numOfStickyCols+1; i < tableColumns.length; i++) {
4142                             angular.element(tableColumns[i]).css(displayBlockCSS);
4143                         }
4144                     }   
4145
4146                     // We must calculate here as we need cells to be reset after re-render. 
4147                     angular.forEach(tableRows, function(row, rowIndex) {
4148                         collectiveRowHeight.push(findMax(row.children, 'height')); // BUG: Keeping this here now causes row height bugs
4149                     });
4150                     
4151                     
4152                     for (var i = 0; i < tableColumns.length; i++) {
4153                         collectiveColumnWidth.push(findMax(tableColumns[i], 'width')); //offsetWidth doesn't take into account custom css inside
4154                     }
4155                     for(var i = 0; i < scope.numOfStickyCols; i++) {
4156                         maxWidth += collectiveColumnWidth[i];
4157                     }
4158
4159                     // BUG: The code I put in to fix the table not spanning 100%  width is now preventing 
4160                     // table cells from laying out more than stickyPixels and thus we have weird wrapping
4161                     stickyPixels = totalWidth-maxWidth;
4162
4163                     // At this point, for each tr, I need to set the properties (height) and each numOfStickyCols children
4164                     // should be set with sticky properties (margin-left and width)
4165                     var width = maxWidth;
4166                     var additive = 0; 
4167
4168                     if (angular.element(document).find('html').hasClass('isIE')) {
4169                         additive = 25;
4170                     }
4171                     var thObject = undefined;
4172                     for(var i = 0; i < scope.numOfStickyCols; i++) {
4173                         for (var j = 0; j < tableRows.length; j++) {
4174                             thObject = angular.element(tableRows[j].children[i]);
4175                             angular.element(thObject).css({
4176                                 'margin-left': -(width + 2) + 'px', 
4177                                 'width': (collectiveColumnWidth[i] + 3) + 'px', // instead of taking the max width, grab max width for that column
4178                                 'height': (collectiveRowHeight[j] + additive) + 'px',
4179                                 'position': 'absolute',
4180                                 'background-color': '#F2F2F2'
4181                             });
4182                         }
4183                         width -= collectiveColumnWidth[i];
4184                     }
4185                     angular.element(tableRows[0]).css('height', collectiveRowHeight[0] + 'px');
4186                     for(var i = 0; i < tableRows.length; i++) {
4187                         angular.element(tableRows[i]).css('height', (collectiveRowHeight[i] + additive) + 'px'); 
4188                     }
4189                     
4190                     innerContainer.css({
4191                         'padding-left': (maxWidth + 2) + 'px'
4192                     });
4193
4194
4195                     // Let's precompute all the (set) combinations beforehand
4196                     columnSets = []; 
4197                     for (var i = scope.numOfStickyCols; i < tableColumns.length;) {
4198                         visibleColumns = calculateVisibleColumns(i);
4199                         if(visibleColumns === tableColumns.length){
4200                             columnSets.push([i, visibleColumns-1]);
4201                         }else{
4202                             columnSets.push([i, visibleColumns]);
4203                         }
4204                         i = visibleColumns + 1;
4205                     }
4206                     
4207                     //columnSets = [[1, 1], [2,7]]; 
4208                     
4209                     updateCellDisplay(columnSets[setIndex]);
4210                     checkScrollArrows();
4211
4212                     scope.numOfCols = tableColumns.length;
4213
4214                 }
4215
4216                 // JM520E: This is a temporary hack until I solve the ngRepeat issue
4217                 function hack() {
4218                     if (element.find('th').length < scope.numOfStickyCols) {
4219                         // DOM ngRepeat is not ready, let's check back in 10 ms
4220                         $timeout(hack, 10, false);
4221                     } else {
4222                         if (scope.refresh !== undefined) {
4223                             scope.$watch('refresh', function(oldVal, newVal) { // this watch calls too many times
4224                                 if (!angular.equals(oldVal, newVal)) { //hackFinished && oldVal < newVal
4225                                     // From testing it takes about 30 ms before ngRepeat executes, so let's set initial timeout
4226                                     // NOTE: May need to expose timeout to developers. Application is known to have digest cycle of 3-5k watches.
4227                                     $timeout(init, 100, false);
4228                                     scope.refresh = false;
4229                                 }
4230                             });
4231                         }
4232
4233                         init();
4234                     }
4235                 }
4236
4237
4238                 
4239
4240                 // Let's get started with some math!
4241                 hack();
4242
4243                 function calculateVisibleColumns(startingPoint) {
4244                     var usedWidth = 0, 
4245                         visibleColumns = startingPoint || scope.numOfStickyCols;
4246
4247                     while(usedWidth < stickyPixels && visibleColumns < collectiveColumnWidth.length) {
4248                         if (usedWidth+collectiveColumnWidth[visibleColumns] > stickyPixels) {
4249                             if (startingPoint === visibleColumns) {
4250                                 return visibleColumns; // The next cell is too large to fit, it should be only thing to fit
4251                             }
4252                             visibleColumns--;
4253                             return visibleColumns;
4254                         }
4255                         usedWidth += collectiveColumnWidth[visibleColumns];
4256                         visibleColumns++;
4257                     }
4258
4259                     if (usedWidth > stickyPixels) {
4260                         return --visibleColumns;
4261                     }
4262                     return visibleColumns;
4263                 }
4264
4265                 function updateCellDisplay(set) {
4266                     for (var i = scope.numOfStickyCols; i < tableColumns.length; i++) {
4267                         angular.element(tableColumns[i]).css(displayNoneCSS);
4268                     }
4269
4270                     for (var i = set[0]; i <= set[1]; i++) {
4271                         angular.element(tableColumns[i]).css(displayBlockCSS);
4272                     }
4273                 }
4274
4275                 function findMax(arr, prop) {
4276                     var max = 0;
4277                     var localVal = 0;
4278                     var prevDisplay;
4279                     var item;
4280                     for (var i = 0; i < arr.length; i++) {
4281                         item = arr[i];
4282                         prevDisplay = angular.element(item).css('display');
4283
4284                         if (scope.$$phase) {
4285                             scope.$digest();
4286                         }
4287                         // Remove inline styles, they will mess up calculations from original run
4288                         angular.element(item).css('height', '');
4289                         angular.element(item).css('width', ''); 
4290                         if (prop === 'width') {
4291                             // If we do not undo previous run's inline styles, this will grow widths on each re-render.
4292                             localVal = Math.ceil(parseInt(window.getComputedStyle(item).width.split('px')[0], 10)) + 30; // 30 px is padding
4293                         } else if (prop === 'offsetWidth') {
4294                             localVal = item.offsetWidth;
4295                         } else if (prop === 'height') {
4296                             //localVal = item.offsetHeight;
4297                             localVal = Math.ceil(parseInt(window.getComputedStyle(item).height.split('px')[0], 10))
4298                         }
4299
4300                         if (localVal >= max) {
4301                             max = localVal;
4302                         }
4303                     }
4304                     
4305                     return max;
4306                 }
4307
4308                 function checkScrollArrows() {
4309                     scope.disableLeft = (setIndex === 0);
4310                     scope.disableRight = !(setIndex < columnSets.length-1);
4311                 }
4312
4313                 scope.moveViewportLeft = function () {
4314                     setIndex--;
4315                     updateCellDisplay(columnSets[setIndex]);
4316                     checkScrollArrows();
4317
4318                     if (scope.disableLeft) {
4319                         element[0].querySelector('.b2b-horizontal-table-column-info').focus();
4320                     }
4321                 };
4322                 
4323                 scope.moveViewportRight = function () {
4324                     setIndex++;
4325                     updateCellDisplay(columnSets[setIndex]);
4326                     checkScrollArrows();
4327                     
4328                     if (scope.disableRight) {
4329                         element[0].querySelector('.b2b-horizontal-table-column-info').focus();
4330                     }
4331                 };
4332
4333                 scope.getColumnSet = function () {
4334                     return columnSets[setIndex];
4335                 };
4336
4337                 innerContainer.bind('scroll', function () {
4338                     $timeout(function () {
4339                         checkScrollArrows();
4340                     }, 1);
4341                 });
4342
4343             }
4344         };
4345     }]);
4346 /**
4347  * @ngdoc directive
4348  * @name Forms.att:hourPicker
4349  *
4350  * @description
4351  *  <file src="src/hourPicker/docs/readme.md" />
4352  *
4353  * @usage
4354  * <div b2b-hourpicker ng-model="hourpickerValue.value"></div>
4355     
4356  * @example
4357  *  <section id="code">
4358         <example module="b2b.att">
4359             <file src="src/hourPicker/docs/demo.html" />
4360             <file src="src/hourPicker/docs/demo.js" />
4361         </example>
4362     </section>
4363  *
4364  */
4365 angular.module('b2b.att.hourPicker', ['b2b.att.utilities'])
4366
4367 .constant('b2bHourpickerConfig', {
4368     dayOptions: [{
4369         title: 'sunday',
4370         caption: 'Sun',
4371         label: 'S',
4372         disabled: false
4373     }, {
4374         title: 'monday',
4375         caption: 'Mon',
4376         label: 'M',
4377         disabled: false
4378     }, {
4379         title: 'tuesday',
4380         caption: 'Tues',
4381         label: 'T',
4382         disabled: false
4383     }, {
4384         title: 'wednesday',
4385         caption: 'Wed',
4386         label: 'W',
4387         disabled: false
4388     }, {
4389         title: 'thursday',
4390         caption: 'Thu',
4391         label: 'T',
4392         disabled: false
4393     }, {
4394         title: 'friday',
4395         caption: 'Fri',
4396         label: 'F',
4397         disabled: false
4398     }, {
4399         title: 'saturday',
4400         caption: 'Sat',
4401         label: 'S',
4402         disabled: false
4403     }],
4404     startTimeOptions: ['1:00', '2:00', '3:00', '4:00', '5:00', '6:00', '7:00', '8:00', '9:00', '10:00', '11:00', '12:00'],
4405     startTimeDefaultOptionIndex: -1,
4406     startTimeDefaultMeridiem: "am",
4407     endTimeOptions: ['1:00', '2:00', '3:00', '4:00', '5:00', '6:00', '7:00', '8:00', '9:00', '10:00', '11:00', '12:00'],
4408     endTimeDefaultOptionIndex: -1,
4409     endTimeDefaultMeridiem: "pm",
4410     sameDayOption: true
4411 })
4412
4413 .factory('b2bNormalizeHourpickerValues', [function () {
4414     var _normalize = function (hourpickerValues) {
4415         if (angular.isDefined(hourpickerValues) && hourpickerValues != null) {
4416             var finalHourpickerValues = [];
4417             var hourpickerValue = {};
4418             var days = {};
4419             for (var i = 0; i < hourpickerValues.length; i++) {
4420                 days = hourpickerValues[i].days ? hourpickerValues[i].days : {};
4421                 hourpickerValue.startTime = hourpickerValues[i].startTime ? hourpickerValues[i].startTime : '';
4422                 hourpickerValue.startMeridiem = hourpickerValues[i].startMeridiem ? hourpickerValues[i].startMeridiem : '';
4423                 hourpickerValue.endTime = hourpickerValues[i].endTime ? hourpickerValues[i].endTime : '';
4424                 hourpickerValue.endMeridiem = hourpickerValues[i].endMeridiem ? hourpickerValues[i].endMeridiem : '';
4425                 hourpickerValue.days = [];
4426
4427                 var retrieveDaysText = function (daysDetails) {
4428                     var daysTexts = [];
4429                     var first = -1;
4430                     var last = -1;
4431                     var index = -1;
4432                     for (var i in days) {
4433                         if (days[i].value) {
4434                             daysTexts.push(i);
4435                         }
4436                     }
4437
4438                     first = daysTexts[0];
4439                     last = daysTexts[0];
4440                     index = 0;
4441                     hourpickerValue.days[index] = days[first].caption;
4442                     if (daysTexts.length > 1) {
4443                         for (var i = 1; i < daysTexts.length; i++) {
4444                             if (daysTexts[i] - last === 1) {
4445                                 last = daysTexts[i];
4446                                 hourpickerValue.days[index] = days[first].caption + ' - ' + days[last].caption;
4447                             } else {
4448                                 index++;
4449                                 first = last = daysTexts[i];
4450                                 hourpickerValue.days[index] = days[first].caption;
4451                             }
4452                         }
4453                     }
4454                 };
4455                 retrieveDaysText();
4456
4457                 finalHourpickerValues.push(angular.copy(hourpickerValue));
4458             }
4459
4460             return angular.copy(finalHourpickerValues);
4461         }
4462     };
4463
4464     return {
4465         normalize: _normalize
4466     };
4467 }])
4468
4469 .directive('b2bHourpicker', ['b2bHourpickerConfig', 'b2bNormalizeHourpickerValues', function (b2bHourpickerConfig, b2bNormalizeHourpickerValues) {
4470     return {
4471         restrict: 'EA',
4472         replace: false,
4473         scope: true,
4474         require: 'ngModel',
4475         templateUrl: 'b2bTemplate/hourPicker/b2bHourpicker.html',
4476         controller: ['$scope', function (scope) {
4477
4478         }],
4479         link: function (scope, elem, attr, ctrl) {
4480             scope.hourpicker = {};
4481             scope.hourpicker.dayOptions = attr.dayOptions ? scope.$parent.$eval(attr.dayOptions) : b2bHourpickerConfig.dayOptions;
4482             scope.hourpicker.startTimeOptions = attr.startTimeOptions ? scope.$parent.$eval(attr.startTimeOptions) : b2bHourpickerConfig.startTimeOptions;
4483             scope.hourpicker.endTimeOptions = attr.endTimeOptions ? scope.$parent.$eval(attr.endTimeOptions) : b2bHourpickerConfig.endTimeOptions;
4484             scope.hourpicker.startTimeDefaultOptionIndex = attr.startTimeDefaultOptionIndex ? scope.$parent.$eval(attr.startTimeDefaultOptionIndex) : b2bHourpickerConfig.startTimeDefaultOptionIndex;
4485             scope.hourpicker.endTimeDefaultOptionIndex = attr.endTimeDefaultOptionIndex ? scope.$parent.$eval(attr.endTimeDefaultOptionIndex) : b2bHourpickerConfig.endTimeDefaultOptionIndex;
4486             scope.hourpicker.startTimeDefaultMeridiem = attr.startTimeDefaultMeridiem ? scope.$parent.$eval(attr.startTimeDefaultMeridiem) : b2bHourpickerConfig.startTimeDefaultMeridiem;
4487             scope.hourpicker.endTimeDefaultMeridiem = attr.endTimeDefaultMeridiem ? scope.$parent.$eval(attr.endTimeDefaultMeridiem) : b2bHourpickerConfig.endTimeDefaultMeridiem;
4488             scope.hourpicker.sameDayOption = attr.sameDayOption ? scope.$parent.$eval(attr.sameDayOption) : b2bHourpickerConfig.sameDayOption;
4489             scope.hourpicker.editMode = -1;
4490
4491             scope.hourpickerValues = [];
4492             scope.finalHourpickerValues = [];
4493             scope.addHourpickerValue = function (hourpickerPanelValue) {
4494                 if (hourpickerPanelValue) {
4495                     if (scope.hourpicker.editMode > -1) {
4496                         scope.hourpickerValues[scope.hourpicker.editMode] = hourpickerPanelValue;
4497                         scope.hourpicker.editMode = -1;
4498                     } else {
4499                         scope.hourpickerValues.push(hourpickerPanelValue);
4500                     }
4501                 }
4502                 scope.finalHourpickerValues = b2bNormalizeHourpickerValues.normalize(angular.copy(scope.hourpickerValues));
4503                 ctrl.$setViewValue(angular.copy(scope.hourpickerValues));
4504             };
4505             ctrl.$render = function () {
4506                 if (angular.isDefined(ctrl.$modelValue)) {
4507                     scope.hourpickerValues = angular.copy(ctrl.$modelValue);
4508                     scope.finalHourpickerValues = b2bNormalizeHourpickerValues.normalize(angular.copy(scope.hourpickerValues));
4509                 }
4510             };
4511             scope.editHourpickerValue = function (index) {
4512                 scope.hourpickerPanelValue = angular.copy(scope.hourpickerValues[index]);
4513                 scope.hourpicker.editMode = index;
4514             };
4515             scope.deleteHourpickerValue = function (index) {
4516                 scope.hourpickerValues.splice(index, 1);
4517                 scope.resetHourpickerPanelValue();
4518                 scope.addHourpickerValue();
4519             };
4520
4521             scope.setValidity = function (errorType, errorValue) {
4522                 ctrl.$setValidity(errorType, errorValue);
4523             }
4524         }
4525     }
4526 }])
4527
4528 .directive('b2bHourpickerPanel', [function () {
4529     return {
4530         restrict: 'EA',
4531         replace: false,
4532         templateUrl: 'b2bTemplate/hourPicker/b2bHourpickerPanel.html',
4533         controller: ['$scope', function (scope) {
4534
4535         }],
4536         link: function (scope, elem, attr, ctrl) {
4537             var hourpickerPanelValueTemplate = {
4538                 days: {},
4539                 startTime: '',
4540                 startMeridiem: 'am',
4541                 endTime: '',
4542                 endMeridiem: 'pm'
4543             };
4544             for (var i = 0; i < scope.hourpicker.dayOptions.length; i++) {
4545                 hourpickerPanelValueTemplate.days[i] = {
4546                     value: false,
4547                     title: scope.hourpicker.dayOptions[i].title,
4548                     caption: scope.hourpicker.dayOptions[i].caption
4549                 };
4550             }
4551             scope.hourpickerPanelValue = {};
4552             scope.disableAddBtn = true;
4553
4554             scope.$watch('hourpickerPanelValue.days', function(){
4555                 for(var i in scope.hourpickerPanelValue.days)
4556                 {
4557                     if(scope.hourpickerPanelValue.days[i].value)
4558                     {
4559                         scope.disableAddBtn = false;
4560                         break;
4561                     }
4562                     scope.disableAddBtn = true;
4563                 }
4564             }, true);
4565
4566             scope.resetHourpickerPanelValue = function () {
4567                 scope.hourpickerPanelValue = angular.copy(hourpickerPanelValueTemplate);
4568                 if (scope.hourpicker.startTimeDefaultOptionIndex > -1) {
4569                     scope.hourpickerPanelValue.startTime = scope.hourpicker.startTimeOptions[scope.hourpicker.startTimeDefaultOptionIndex];
4570                 }
4571                 if (scope.hourpicker.endTimeDefaultOptionIndex > -1) {
4572                     scope.hourpickerPanelValue.endTime = scope.hourpicker.endTimeOptions[scope.hourpicker.endTimeDefaultOptionIndex];
4573                 }
4574                 scope.hourpickerPanelValue.startMeridiem = scope.hourpicker.startTimeDefaultMeridiem;
4575                 scope.hourpickerPanelValue.endMeridiem = scope.hourpicker.endTimeDefaultMeridiem;
4576                 scope.hourpicker.editMode = -1;
4577                 scope.setValidity('invalidHourpickerData', true);
4578                 scope.setValidity('invalidHourpickerTimeRange', true);
4579             };
4580             scope.resetHourpickerPanelValue();
4581             scope.updateHourpickerValue = function () {
4582                 if (scope.isFormValid() && !scope.isTimeOverlap()) {
4583                     scope.addHourpickerValue(angular.copy(scope.hourpickerPanelValue));
4584                     scope.resetHourpickerPanelValue();
4585                 }
4586             };
4587
4588             scope.isFormValid = function () {
4589                 var isStartTimeAvailable = scope.hourpickerPanelValue.startTime ? true : false;
4590                 var isStartMeridiemAvailable = scope.hourpickerPanelValue.startMeridiem ? true : false;
4591                 var isEndTimeAvailable = scope.hourpickerPanelValue.endTime ? true : false;
4592                 var isEndMeridiemAvailable = scope.hourpickerPanelValue.endMeridiem ? true : false;
4593                 var currentStartTime = getTime(scope.hourpickerPanelValue.startTime, scope.hourpickerPanelValue.startMeridiem);
4594                 var currentEndTime = getTime(scope.hourpickerPanelValue.endTime, scope.hourpickerPanelValue.endMeridiem);
4595                 var isTimeInProperSequence = currentEndTime > currentStartTime;
4596                 var isDayChecked = false;
4597                 for (var i in scope.hourpickerPanelValue.days) {
4598                     if (scope.hourpickerPanelValue.days[i].value) {
4599                         isDayChecked = true;
4600                         break;
4601                     }
4602                 }
4603
4604                 if (isStartTimeAvailable && isStartMeridiemAvailable && isEndTimeAvailable && isEndMeridiemAvailable && isTimeInProperSequence && isDayChecked) {
4605                     scope.setValidity('invalidHourpickerData', true);
4606                     return true;
4607                 } else {
4608                     scope.setValidity('invalidHourpickerData', false);
4609                     return false;
4610                 }
4611             };
4612             scope.isTimeOverlap = function () {
4613                 var selectedDays = [];
4614                 for (var i in scope.hourpickerPanelValue.days) {
4615                     if (scope.hourpickerPanelValue.days[i].value) {
4616                         selectedDays.push(i);
4617                     }
4618                 }
4619
4620                 var currentStartTime, currentEndTime, existingStartTime, existingEndTime;
4621                 currentStartTime = getTime(scope.hourpickerPanelValue.startTime, scope.hourpickerPanelValue.startMeridiem);
4622                 currentEndTime = getTime(scope.hourpickerPanelValue.endTime, scope.hourpickerPanelValue.endMeridiem);
4623                 for (var i = 0; i < scope.hourpickerValues.length; i++) {
4624                     
4625                     if (i === scope.hourpicker.editMode) {
4626                         continue;
4627                     }
4628
4629                     for (var j = 0; j < selectedDays.length; j++) {
4630                         existingStartTime = getTime(scope.hourpickerValues[i].startTime, scope.hourpickerValues[i].startMeridiem);
4631                         existingEndTime = getTime(scope.hourpickerValues[i].endTime, scope.hourpickerValues[i].endMeridiem);
4632                         if (scope.hourpickerValues[i].days[selectedDays[j]].value) {
4633                             if(!scope.hourpicker.sameDayOption){
4634                                 scope.setValidity('dayAlreadySelected', false);
4635                                 return true;
4636                             } else if ((currentStartTime > existingStartTime && currentStartTime < existingEndTime) || (currentEndTime > existingStartTime && currentEndTime < existingEndTime)) {
4637                                 scope.setValidity('invalidHourpickerTimeRange', false);
4638                                 return true;
4639                             } else if ((existingStartTime > currentStartTime && existingStartTime < currentEndTime) || (existingEndTime > currentStartTime && existingEndTime < currentEndTime)) {
4640                                 scope.setValidity('invalidHourpickerTimeRange', false);
4641                                 return true;
4642                             } else if ((currentStartTime === existingStartTime) && (currentEndTime === existingEndTime)) {
4643                                 scope.setValidity('invalidHourpickerTimeRange', false);
4644                                 return true;
4645                             }
4646                         }
4647                     }
4648                 }
4649
4650                 scope.setValidity('dayAlreadySelected', true);
4651                 scope.setValidity('invalidHourpickerTimeRange', true);
4652                 return false;
4653             };
4654             var getTime = function (timeString, meridiem) {
4655                 var tempDate = new Date();
4656                 if (timeString && meridiem) {
4657                     var timeSplit = timeString.split(':');
4658                     var hour = ((meridiem === 'PM' || meridiem === 'pm') && timeSplit[0] !== '12') ? parseInt(timeSplit[0], 10) + 12 : parseInt(timeSplit[0], 10);
4659                     tempDate.setHours(hour, parseInt(timeSplit[1], 10), 0, 0);
4660                 }
4661
4662                 return tempDate.getTime();
4663             };
4664         }
4665     }
4666 }])
4667
4668 .directive('b2bHourpickerValue', [function () {
4669     return {
4670         restrict: 'EA',
4671         replace: false,
4672         templateUrl: 'b2bTemplate/hourPicker/b2bHourpickerValue.html',
4673         controller: ['$scope', function (scope) {
4674
4675         }],
4676         link: function (scope, elem, attr, ctrl) {
4677             scope.hourpickerValue = {};
4678             scope.hourpickerValue.startTime = attr.startTime ? scope.$eval(attr.startTime) : '';
4679             scope.hourpickerValue.startMeridiem = attr.startMeridiem ? scope.$eval(attr.startMeridiem) : '';
4680             scope.hourpickerValue.endTime = attr.endTime ? scope.$eval(attr.endTime) : '';
4681             scope.hourpickerValue.endMeridiem = attr.endMeridiem ? scope.$eval(attr.endMeridiem) : '';
4682             scope.hourpickerValue.days = attr.days ? scope.$eval(attr.days).join(', ') : '';
4683             scope.hourpickerValue.index = attr.b2bHourpickerValue ? scope.$eval(attr.b2bHourpickerValue) : -1;
4684         }
4685     }
4686 }]);
4687 /**
4688  * @ngdoc directive
4689  * @name Template.att:inputTemplate
4690  *
4691  * @description
4692  *  <file src="src/inputTemplate/docs/readme.md" />
4693  *
4694  * @usage
4695  *  <input type="text" id="fieldId" placeholder="placholder text here" class="span12 input-enhanced" name="fieldName">
4696  *
4697  * @example
4698  <section id="code">
4699     <b>HTML + AngularJS</b>
4700     <example module="b2b.att">
4701         <file src="src/inputTemplate/docs/demo.html" />
4702         <file src="src/inputTemplate/docs/demo.js" />
4703     </example>
4704  </section>
4705  */
4706 angular.module('b2b.att.inputTemplate', []);
4707
4708 /**
4709  * @ngdoc directive
4710  * @name Navigation.att:leftNavigation
4711  *
4712  * @description
4713  *  <file src="src/leftNavigation/docs/readme.md" />
4714  *
4715  * @usage
4716  *   <b2b-left-navigation data-menu="menuData"></b2b-left-navigation> 
4717  *
4718  * @example
4719  *  <section id="code">
4720         <example module="b2b.att">
4721             <file src="src/leftNavigation/docs/demo.html" />
4722             <file src="src/leftNavigation/docs/demo.js" />
4723        </example>
4724     </section>
4725  *
4726  */
4727 angular.module('b2b.att.leftNavigation', [])
4728     .directive('b2bLeftNavigation', [function () {
4729         return {
4730             restrict: 'EA',
4731             templateUrl: 'b2bTemplate/leftNavigation/leftNavigation.html',
4732             scope: {
4733                 menuData: '='
4734             },
4735             link: function (scope, element, attrs, ctrl) {
4736                 scope.idx = -1;
4737                 scope.itemIdx = -1;
4738                 scope.navIdx = -1;
4739                 scope.toggleNav = function (val) {
4740                     if (val === scope.idx) {
4741                         scope.idx = -1;
4742                         return;
4743                     }
4744                     scope.idx = val;
4745                 };
4746                 scope.liveLink = function (evt, val1, val2) {
4747                     scope.itemIdx = val1;
4748                     scope.navIdx = val2;
4749                     evt.stopPropagation();
4750                 };
4751             }
4752         };
4753     }]);
4754 /**
4755  * @ngdoc directive
4756  * @name Buttons, links & UI controls.att:links
4757  *
4758  * @description
4759  *  <file src="src/links/docs/readme.md" />
4760  * @usage
4761  *      <!-- See below examples for link implementation -->
4762  *      
4763  * @example
4764        <section id="code">              
4765            <b>HTML + AngularJS</b>
4766            <example module="b2b.att">
4767            <file src="src/links/docs/demo.html" />
4768             <file src="src/links/docs/demo.js" />            
4769           </example>          
4770         </section>
4771  */
4772 angular.module('b2b.att.links', []);
4773 /**
4774  * @ngdoc directive
4775  * @name Misc.att:listbox
4776  *
4777  * @description
4778  *  <file src="src/listbox/docs/readme.md" />
4779  *
4780  * @param {int} currentIndex - Current index of selected listbox item. Is not supported on multiselect listbox
4781  * @param {Array} listboxData - Data of listbox items. Should include full data regardless if HTML will be filtered.
4782
4783  * @example
4784  *  <section id="code">   
4785      <example module="b2b.att">
4786      <file src="src/listbox/docs/demo.html" />
4787      <file src="src/listbox/docs/demo.js" />
4788      </example>
4789     </section>
4790  *
4791  */
4792 angular.module('b2b.att.listbox', ['b2b.att.utilities'])
4793 .directive('b2bListBox', ['keymap', 'b2bDOMHelper', '$rootScope', function(keymap, b2bDOMHelper, $rootScope) {
4794                 return {
4795                     restrict: 'AE',
4796                     transclude: true,
4797                     replace: true,
4798                     scope: {
4799                         currentIndex: '=', 
4800                         listboxData: '='
4801                     },
4802                     templateUrl: 'b2bTemplate/listbox/listbox.html',
4803                     link: function(scope, elem, attr) {
4804
4805                         if (attr.ariaMultiselectable !== undefined || attr.ariaMultiselectable === 'true') {
4806                             scope.multiselectable = true;
4807                         } else {
4808                             scope.multiselectable = false;
4809                         }
4810
4811                         var shiftKey = false;
4812                         var elements = [];
4813                         var prevDirection = undefined; // previous direction is used for an edge case when shifting
4814                         var shiftKeyPressed = false; // Used to handle shift clicking
4815                         var ctrlKeyPressed = false;
4816
4817                         var currentIndexSet = {
4818                             'elementIndex': 0,
4819                             'listboxDataIndex': 0
4820                         };
4821
4822                         function isTrue(item) {
4823                             if (item.selected === true) {
4824                                 return true;
4825                             }
4826                         }
4827
4828                         function incrementIndex(elem) {
4829                             $rootScope.$apply();
4830
4831                             var nextElem = elem.next();
4832                             if (!angular.isDefined(nextElem) || nextElem.length === 0) {
4833                                 return;
4834                             }
4835
4836                             currentIndexSet.elementIndex += 1;
4837                             currentIndexSet.listboxDataIndex = parseInt(nextElem.attr('data-index'), 10);
4838                             scope.currentIndex = currentIndexSet.listboxDataIndex;
4839
4840                             if (currentIndexSet.elementIndex >= elements.length - 1) {
4841                                 currentIndexSet.elementIndex = elements.length-1;
4842                             }
4843                         }
4844
4845                         function decrementIndex(elem) {
4846                             $rootScope.$apply();
4847                             var prevElem = angular.element(b2bDOMHelper.previousElement(elem));
4848                             if (!angular.isDefined(prevElem) || prevElem.length === 0) {
4849                                 return;
4850                             }
4851
4852                             currentIndexSet.elementIndex -= 1;
4853                             currentIndexSet.listboxDataIndex = parseInt(prevElem.attr('data-index'), 10);
4854                             scope.currentIndex = currentIndexSet.listboxDataIndex;
4855
4856                             if (currentIndexSet.elementIndex <= 0) {
4857                                 currentIndexSet.elementIndex = 0;
4858                             }
4859                         }
4860
4861                         var focusOnElement = function(index) {
4862                             try {
4863                                 elements[index].focus();
4864                             } catch (e) {};
4865                         }
4866
4867                         function selectItems(startIndex, endIndex, forceValue) {
4868                             for (var i = startIndex; i < endIndex; i++) {
4869                                 if (forceValue === undefined) {
4870                                     // We will flip the value
4871                                     scope.listboxData[i].selected = !scope.listboxData[i].selected;
4872                                 } else {
4873                                     scope.listboxData[i].selected = forceValue;
4874                                 }
4875                             }
4876
4877                             if (!scope.$$phase) {
4878                                 scope.$apply();
4879                             }
4880                         }
4881
4882                         elem.bind('focus', function(evt) { 
4883                             // If multiselectable or not and nothing is selected, put focus on first element 
4884                             // If multiselectable and a range is set, put focus on first element of range 
4885                             // If not multiselectable and something selected, put focus on element 
4886                             elements = elem.children(); 
4887                              var selectedItems = scope.listboxData.filter(isTrue); 
4888                              var elementsIndies = Array.prototype.map.call(elements, function(item) {
4889                                 return parseInt(angular.element(item).attr('data-index'), 10);
4890                             });
4891  
4892                             if (selectedItems.length == 0) { 
4893                                 focusOnElement(0); 
4894                                 currentIndexSet.listboxDataIndex = 0;
4895                             } else if (attr.ariaMultiselectable) { 
4896                                 var index = scope.listboxData.indexOf(selectedItems[0]); 
4897                                 var indies = elementsIndies.filter(function(item) {
4898                                     return (item === index);
4899                                 });
4900
4901                                 if (indies.length === 0 || indies[0] != index) {
4902                                     // Set focused on 0
4903                                     currentIndexSet.elementIndex = elementsIndies[0]; 
4904                                     currentIndexSet.listboxDataIndex = 0;
4905                                     focusOnElement(currentIndexSet.elementIndex);
4906                                 } else {
4907                                     focusOnElement(indies[0]); 
4908                                     currentIndexSet.elementIndex = indies[0];
4909                                     currentIndexSet.listboxDataIndex = index;
4910                                 }
4911                             } else { 
4912                                 focusOnElement(currentIndexSet.elementIndex);  
4913                             }
4914                             scope.currentIndex = currentIndexSet.listboxDataIndex;
4915
4916                             if (!scope.$$phase) {
4917                                 scope.$apply();
4918                             }
4919                         });
4920                         elem.bind('keyup', function(evt) {
4921                             if (evt.keyCode === keymap.KEY.SHIFT) {
4922                                 shiftKeyPressed = false;
4923                             } else if (evt.keyCode === keymap.KEY.CTRL) {
4924                                 ctrlKeyPressed = false;
4925                             }
4926                         });
4927                 
4928                         elem.bind('keydown', function(evt) {
4929                             var keyCode = evt.keyCode;
4930                             elements = elem.children();
4931                             if (keyCode === keymap.KEY.SHIFT) {
4932                                 shiftKeyPressed = true;
4933                             } else if (evt.keyCode === keymap.KEY.CTRL) {
4934                                 ctrlKeyPressed = true;
4935                             }
4936
4937                             switch(keyCode) {
4938                                 case 65: // A key
4939                                 {
4940                                     if (scope.multiselectable && evt.ctrlKey) {
4941                                         var arr = scope.listboxData.filter(isTrue);
4942                                         var elementsIndies = Array.prototype.map.call(elements, function(item) {
4943                                             return parseInt(angular.element(item).attr('data-index'), 10);
4944                                         });
4945                                         var val = !(arr.length === scope.listboxData.length);
4946                                         for (var i = 0; i < elementsIndies.length; i++) {
4947                                             scope.listboxData[elementsIndies[i]].selected = val;
4948                                         }
4949
4950                                         if (!scope.$$phase) {
4951                                             scope.$apply();
4952                                         }
4953                                         
4954                                         evt.preventDefault();
4955                                         evt.stopPropagation();
4956                                     }
4957                                     break;
4958                                 }
4959                                 case keymap.KEY.END:
4960                                 {
4961                                     if (scope.multiselectable && evt.ctrlKey && evt.shiftKey) {
4962                                         var elementsIndies = Array.prototype.map.call(elements, function(item) {
4963                                             return parseInt(angular.element(item).attr('data-index'), 10);
4964                                         }).filter(function(item) {
4965                                             return (item >= currentIndexSet.listboxDataIndex);
4966                                         });
4967                                         for (var i = 0; i < elementsIndies.length; i++) {
4968                                             scope.listboxData[elementsIndies[i]].selected = true;
4969                                         }
4970                                         evt.preventDefault();
4971                                         evt.stopPropagation();
4972
4973                                         if (!scope.$$phase) {
4974                                             scope.$apply();
4975                                         }
4976                                     }
4977                                     break;
4978                                 }
4979                                 case keymap.KEY.HOME: 
4980                                 {
4981                                     if (scope.multiselectable && evt.ctrlKey && evt.shiftKey) {
4982                                         selectItems(0, currentIndexSet.listboxDataIndex+1, true); // currentIndex+1 is what is being focused on
4983                                         evt.preventDefault();
4984                                         evt.stopPropagation();
4985                                     }
4986                                     break;
4987                                 }
4988                                 case keymap.KEY.LEFT:
4989                                 case keymap.KEY.UP:
4990                                 {
4991                                     if (currentIndexSet.listboxDataIndex === 0) {
4992                                         evt.preventDefault();
4993                                         evt.stopPropagation();
4994                                         return;
4995                                     }
4996
4997                                     decrementIndex(elements.eq(currentIndexSet.elementIndex));
4998                                     if (scope.multiselectable && (evt.shiftKey || evt.ctrlKey)) {
4999                                         if (evt.shiftKey) {
5000                                             if (prevDirection === 'DOWN') {
5001                                                 scope.listboxData[currentIndexSet.listboxDataIndex+1].selected = !scope.listboxData[currentIndexSet.listboxDataIndex+1].selected;
5002                                             }
5003                                             scope.listboxData[currentIndexSet.listboxDataIndex].selected = !scope.listboxData[currentIndexSet.listboxDataIndex].selected;
5004                                         }
5005                                         prevDirection = 'UP';
5006                                     } else {
5007                                         // If no modifier keys are selected, all other items need to be unselected.
5008                                         prevDirection = undefined;
5009                                         selectItems(0, scope.listboxData.length, false);
5010                                         if(currentIndexSet.listboxDataIndex !== undefined && !isNaN(currentIndexSet.listboxDataIndex)){
5011                                             scope.listboxData[currentIndexSet.listboxDataIndex].selected = true;
5012                                         }
5013                                     }
5014                                     focusOnElement(currentIndexSet.elementIndex);
5015                                     if(!scope.$$phase) {
5016                                         scope.$apply();
5017                                     }
5018                                     evt.preventDefault();
5019                                     evt.stopPropagation();
5020                                     break;
5021                                 }
5022                                 case keymap.KEY.RIGHT:
5023                                 case keymap.KEY.DOWN:
5024                                 {
5025                                     if (currentIndexSet.listboxDataIndex === scope.listboxData.length-1) {
5026                                         evt.preventDefault();
5027                                         evt.stopPropagation();
5028                                         return;
5029                                     }
5030
5031                                     incrementIndex(elements.eq(currentIndexSet.elementIndex));
5032                                     
5033                                     if (scope.multiselectable && (evt.shiftKey || evt.ctrlKey)) {
5034                                         if (evt.shiftKey) {
5035                                             if (prevDirection === 'UP') {
5036                                                 scope.listboxData[currentIndexSet.listboxDataIndex-1].selected = !scope.listboxData[currentIndexSet.listboxDataIndex-1].selected;
5037                                             }
5038                                             
5039                                             scope.listboxData[currentIndexSet.listboxDataIndex].selected = !scope.listboxData[currentIndexSet.listboxDataIndex].selected;    
5040                                         }
5041                                         prevDirection = 'DOWN';
5042                                     } else {
5043                                         // If no modifier keys are selected, all other items need to be unselected.
5044                                         prevDirection = undefined;
5045                                         selectItems(0, scope.listboxData.length, false);
5046                                         if(currentIndexSet.listboxDataIndex !== undefined && !isNaN(currentIndexSet.listboxDataIndex)){
5047                                             scope.listboxData[currentIndexSet.listboxDataIndex].selected = true;
5048                                         }
5049                                     }
5050
5051                                     focusOnElement(currentIndexSet.elementIndex);
5052                                     if(!scope.$$phase) {
5053                                         scope.$apply();
5054                                     }
5055                                     evt.preventDefault();
5056                                     evt.stopPropagation();
5057                                     break;
5058                                 }
5059                                 case keymap.KEY.TAB:
5060                                     if(evt.shiftKey) {
5061                                         var previousElement = b2bDOMHelper.previousElement(elem.parent().parent(), true);
5062                                         evt.preventDefault();
5063                                         previousElement.focus();
5064                                     }
5065                                     break;
5066                                 default:
5067                                     break;
5068                             }
5069                         });
5070
5071                         elem.bind('click', function(evt) {
5072                             var index = parseInt(evt.target.dataset.index, 10);
5073                             if (index === undefined || isNaN(index)) {
5074                                 return;
5075                             }
5076                             if (scope.multiselectable && currentIndexSet.listboxDataIndex !== undefined) {
5077                                 if (shiftKeyPressed) {
5078                                     var min = Math.min(index, currentIndexSet.listboxDataIndex);
5079                                     var max = Math.max(index, currentIndexSet.listboxDataIndex);
5080
5081                                     if (index === min) { // clicking up
5082                                         var firstIndex = scope.listboxData.findIndex(function(item) { return item.selected === true;});
5083                                         // Given the firstIndex, let's find the matching element to get proper element match
5084                                         elements = elem.children();
5085                                         elements.eq(firstIndex)
5086                                         var elementsThatMatch = Array.prototype.filter.call(elements, function(item) {
5087                                             if (parseInt(angular.element(item).attr('data-index'), 10) === firstIndex) {
5088                                                 return true;
5089                                             }
5090                                         });
5091                                         firstIndex = parseInt(angular.element(elementsThatMatch).attr('data-index'), 10);
5092                                         
5093                                         if (index <= firstIndex && scope.listboxData.filter(isTrue).length > 1) {
5094                                             // Break the selection into 2
5095                                             selectItems(firstIndex + 1, max + 1, undefined); // + 1 needed because selectItems only selects up to MAX
5096                                             selectItems(min, firstIndex, undefined); 
5097                                         } else if (scope.listboxData.filter(isTrue).length == 1){
5098                                             selectItems(min, max, undefined); 
5099                                         } else {
5100                                             selectItems(min + 1, max + 1, undefined);
5101                                         }
5102                                     } else { // clicking down
5103                                         selectItems(min + 1, max + 1, scope.listboxData[min].selected);
5104                                     }
5105                                 } else if (ctrlKeyPressed) {
5106                                     scope.listboxData[index].selected = !scope.listboxData[index].selected;
5107                                 } else {
5108                                     selectItems(0, scope.listboxData.length, false);
5109                                     scope.listboxData[index].selected = !scope.listboxData[index].selected;
5110                                 }
5111                             } else {
5112                                 selectItems(0, scope.listboxData.length, false);
5113                                 scope.listboxData[index].selected = !scope.listboxData[index].selected;
5114                             }
5115                             currentIndexSet.elementIndex = index;
5116                             currentIndexSet.listboxDataIndex = index;
5117                             scope.currentIndex = currentIndexSet.listboxDataIndex;
5118                             if (!scope.$$phase) {
5119                                 scope.$apply();
5120                             }
5121                             focusOnElement(index);
5122                         });
5123                     }
5124                 };
5125             }]);
5126 /**
5127  * @ngdoc directive
5128  * @name Videos, audio & animation.att:loaderAnimation
5129  *
5130  * @description
5131  *  <file src="src/loaderAnimation/docs/readme.md" />
5132  *
5133  * @usage
5134  *   <!-- Below demo js shows-->
5135  *   Angular library uses Global.css's icon-primary-spinner.
5136  *
5137  * @example
5138  *  <section id="code">
5139         <example module="b2b.att">
5140             <file src="src/loaderAnimation/docs/demo.html" />
5141             <file src="src/loaderAnimation/docs/demo.js" />
5142        </example>
5143     </section>
5144  *
5145  */
5146 angular.module('b2b.att.loaderAnimation', [])
5147     .constant('b2bSpinnerConfig', {
5148         loadingText: 'Loading...',
5149         startEvent: 'startButtonSpinner',
5150         stopEvent: 'stopButtonSpinner'
5151     })
5152     .constant("progressTrackerConfig", {
5153         loadingText: 'Loading...',
5154         minDuration: "",
5155         activationDelay: "",
5156         minDurationPromise: "",
5157         activationDelayPromise: ""
5158     })
5159
5160 .provider('progressTracker', function () {
5161     this.$get = ['$q', '$timeout', function ($q, $timeout) {
5162         function cancelTimeout(promise) {
5163             if (promise) {
5164                 $timeout.cancel(promise);
5165             }
5166         }
5167         return function ProgressTracker(options) {
5168             //do new if user doesn't
5169             if (!(this instanceof ProgressTracker)) {
5170                 return new ProgressTracker(options);
5171             }
5172
5173             options = options || {};
5174             //Array of promises being tracked
5175             var tracked = [];
5176             var self = this;
5177             //Allow an optional "minimum duration" that the tracker has to stay active for.
5178             var minDuration = options.minDuration;
5179             //Allow a delay that will stop the tracker from activating until that time is reached
5180             var activationDelay = options.activationDelay;
5181             var minDurationPromise;
5182             var activationDelayPromise;
5183             self.active = function () {
5184                 //Even if we have a promise in our tracker, we aren't active until delay is elapsed
5185                 if (activationDelayPromise) {
5186                     return false;
5187                 }
5188                 return tracked.length > 0;
5189             };
5190             self.tracking = function () {
5191                 //Even if we aren't active, we could still have a promise in our tracker
5192                 return tracked.length > 0;
5193             };
5194             self.destroy = self.cancel = function () {
5195                 minDurationPromise = cancelTimeout(minDurationPromise);
5196                 activationDelayPromise = cancelTimeout(activationDelayPromise);
5197                 for (var i = tracked.length - 1; i >= 0; i--) {
5198                     tracked[i].resolve();
5199                 }
5200                 tracked.length = 0;
5201             };
5202             //Create a promise that will make our tracker active until it is resolved.
5203             // @return deferred - our deferred object that is being tracked
5204             self.createPromise = function () {
5205                 var deferred = $q.defer();
5206                 tracked.push(deferred);
5207                 //If the tracker was just inactive and this the first in the list of promises, we reset our delay and minDuration again.
5208                 if (tracked.length === 1) {
5209                     if (activationDelay) {
5210                         activationDelayPromise = $timeout(function () {
5211                             activationDelayPromise = cancelTimeout(activationDelayPromise);
5212                             startMinDuration();
5213                         }, activationDelay);
5214                     } else {
5215                         startMinDuration();
5216                     }
5217                 }
5218                 deferred.promise.then(onDone(false), onDone(true));
5219                 return deferred;
5220
5221                 function startMinDuration() {
5222                     if (minDuration) {
5223                         minDurationPromise = $timeout(angular.noop, minDuration);
5224                     }
5225                 }
5226                 //Create a callback for when this promise is done. It will remove our tracked promise from the array if once minDuration is complete
5227                 function onDone() {
5228                     return function () {
5229                         (minDurationPromise || $q.when()).then(function () {
5230                             var index = tracked.indexOf(deferred);
5231                             tracked.splice(index, 1);
5232                             //If this is the last promise, cleanup the timeouts for activationDelay
5233                             if (tracked.length === 0) {
5234                                 activationDelayPromise = cancelTimeout(activationDelayPromise);
5235                             }
5236                         });
5237                     };
5238                 }
5239             };
5240             self.addPromise = function (promise) {
5241                 
5242 //                we cannot assign then function in other var and then add the resolve and reject 
5243                 var thenFxn = promise && (promise.then || promise.$then || (promise.$promise && promise.$promise.then));                
5244                 if (!thenFxn) {
5245                     throw new Error("progressTracker expects a promise object :: Not found");
5246                 }
5247                 var deferred = self.createPromise();
5248                 //When given promise is done, resolve our created promise
5249                 //Allow $then for angular-resource objects
5250
5251                 promise.then(function (value) {
5252                         deferred.resolve(value);
5253                         return value;
5254                     }, function (value) {
5255                         deferred.reject(value);
5256                         return $q.reject(value);
5257                     }
5258                 );
5259                 return deferred;
5260             };
5261         };
5262     }];
5263 })
5264
5265 .config(['$httpProvider', function ($httpProvider) {
5266     $httpProvider.interceptors.push(['$q', 'progressTracker', function ($q) {
5267         return {
5268             request: function (config) {
5269                 if (config.tracker) {
5270                     if (!angular.isArray(config.tracker)) {
5271                         config.tracker = [config.tracker];
5272                     }
5273                     config.$promiseTrackerDeferred = config.$promiseTrackerDeferred || [];
5274
5275                     angular.forEach(config.tracker, function (tracker) {
5276                         var deferred = tracker.createPromise();
5277                         config.$promiseTrackerDeferred.push(deferred);
5278                     });
5279                 }
5280                 return $q.when(config);
5281             },
5282             response: function (response) {
5283                 if (response.config && response.config.$promiseTrackerDeferred) {
5284                     angular.forEach(response.config.$promiseTrackerDeferred, function (deferred) {
5285                         deferred.resolve(response);
5286                     });
5287                 }
5288                 return $q.when(response);
5289             },
5290             responseError: function (response) {
5291                 if (response.config && response.config.$promiseTrackerDeferred) {
5292                     angular.forEach(response.config.$promiseTrackerDeferred, function (deferred) {
5293                         deferred.reject(response);
5294                     });
5295                 }
5296                 return $q.reject(response);
5297             }
5298         };
5299     }]);
5300 }])
5301
5302 .directive('b2bClickSpin', ['$timeout', '$parse', '$rootScope', 'progressTracker', function ($timeout, $parse, $rootScope, progressTracker) {
5303     return {
5304         restrict: 'A',
5305         link: function (scope, elm, attrs) {
5306             var fn = $parse(attrs.b2bClickSpin);
5307             elm.on('click', function (event) {
5308                 var promise = $timeout(function () {console.log("inside Promise")}, 5000);
5309                 scope.$apply(function () {
5310                     fn(scope, {
5311                         $event: event
5312                     });
5313                 });
5314                 //comment this line if not running unit test
5315                 $rootScope.loadingTracker = progressTracker({
5316                     minDuration: 750
5317                 });
5318                 $rootScope.loadingTracker.addPromise(promise);
5319                 angular.forEach("$routeChangeSuccess $viewContentLoaded $locationChangeSuccess".split(" "), function (event) {
5320                     $rootScope.$on(event, function () {
5321
5322                         $timeout.cancel(promise);
5323                     });
5324                 });
5325             });
5326         }
5327     };
5328 }])
5329
5330 .directive('b2bProgressTracker', ['progressTrackerConfig', function (ptc) {
5331     return {
5332         restrict: 'EA',
5333         replace: true,
5334         template: '<div><div ng-show="loadingTracker.active()" style="width:100%; text-align:center"><i class=\"icon-primary-spinner\"></i></div><div ng-show="loadingTracker.active()" style="width:100%;margin-top:10px; text-align:center">'+ ptc.loadingText+'</div></div>'
5335     };
5336 }])
5337
5338 .directive('b2bLoadButton', ['b2bSpinnerConfig', '$timeout', function (spinnerConfig, $timeout) {
5339     var spinButton = function (state, element, data) {
5340         
5341         var attr = element.html() ? 'html' : 'val';
5342         state = state + 'Text';
5343         if (state === 'loadingText') {
5344             element[attr](data[state]);
5345             element.attr("disabled",'disabled');
5346             element.addClass('disabled');
5347         } else if (state === 'resetText') {
5348             element[attr](data[state]);
5349             element.removeAttr("disabled");
5350             element.removeClass('disabled');
5351         }
5352     };
5353
5354     return {
5355         restrict: 'A',
5356         replace: false,
5357         scope: {
5358             promise: '=promise',
5359             startEvent: '@startEvent',
5360             stopEvent: '@stopEvent'
5361         },
5362         link: function (scope, element, attr) {
5363             var validAttr = element.html() ? 'html' : 'val';
5364             var data = {
5365                 loadingText: '',
5366                 resetText: ''
5367             };
5368
5369             var updateLoadingText = function (val) {
5370                 var loadingText = val;
5371                 if (!angular.isDefined(loadingText) || loadingText === "") {
5372                     loadingText = spinnerConfig.loadingText;
5373                 }
5374                 data.loadingText = validAttr === 'html' ? "<i class=\"icon-primary-spinner small\"></i>" + loadingText : loadingText;
5375             };
5376             var updateResetText = function (val) {
5377                 data.resetText = val;
5378             };
5379
5380             attr.$observe('b2bLoadButton', function (val) {
5381                 updateLoadingText(val);
5382             });
5383             $timeout(function () {
5384                 updateResetText(element[validAttr]());
5385             }, 500);
5386
5387             if (!angular.isDefined(scope.startEvent) || scope.startEvent === "") {
5388                 scope.startEvent = spinnerConfig.startEvent;
5389             }
5390
5391             if (!angular.isDefined(scope.stopEvent) || scope.stopEvent === "") {
5392                 scope.stopEvent = spinnerConfig.stopEvent;
5393             }
5394
5395             scope.$watch('promise', function () {
5396                 if (angular.isDefined(scope.promise) && angular.isFunction(scope.promise.then)) {
5397                     spinButton('loading', element, data);
5398                     scope.promise.then(function () {
5399                         spinButton('reset', element, data);
5400                     }, function () {
5401                         spinButton('reset', element, data);
5402                     });
5403                 }
5404             });
5405
5406             scope.$on(scope.startEvent, function () {
5407                 spinButton('loading', element, data);
5408                 scope.$on(scope.stopEvent, function () {
5409                     spinButton('reset', element, data);
5410                 });
5411             });
5412         }
5413     };
5414 }]);
5415  /**
5416  * @ngdoc directive
5417  * @name Misc.att:messageWrapper
5418  * @scope
5419  * @param {boolean} trigger - A boolean that triggers directive to switch focus
5420  * @param {integer} delay  - Extra delay added to trigger code to allow for DOM to be ready. Default is 10ms.
5421  * @param {string} noFocus - Attribute-based API to trigger whether first focusable element receives focus on trigger or whole message (assumes tabindex="-1" set on first child)
5422  * @param {string} trapFocus - Attribute-based API to trap focus within the message. This should be enabled by default on all toast messages.
5423  * @description
5424  *  <file src="src/messageWrapper/docs/readme.md" />
5425  * @usage
5426  * <b2b-message-wrapper>Code that contains at least one focusable element and will be shown/hidden on some logic. This must have tabindex="-1".</b2b-message-wrapper>
5427  *
5428  * @example
5429  *  <section id="code">   
5430  <b>HTML + AngularJS</b>
5431  <example module="b2b.att">
5432  <file src="src/messageWrapper/docs/demo.html" />
5433  <file src="src/messageWrapper/docs/demo.js" />
5434  </example>
5435  </section>
5436  *
5437  */
5438 angular.module('b2b.att.messageWrapper', ['b2b.att.utilities'])
5439 .directive('b2bMessageWrapper', ['b2bDOMHelper', '$compile', '$timeout', '$log', function(b2bDOMHelper, $compile, $timeout, $log) {
5440   return {
5441     restrict: 'AE',
5442     scope: {
5443       trigger: '=',
5444       delay: '=?'
5445     },
5446     transclude: true,
5447     replace: true,
5448     template: '<div ng-transclude></div>',
5449     link: function(scope, elem, attrs) {
5450       scope.delay = scope.delay || 10;
5451
5452       if (attrs.trapFocus != undefined && !elem.children().eq(0).attr('b2b-trap-focus-inside-element')) {
5453         // Append b2bTrapFocusInsideElement onto first child and recompile
5454         elem.children().eq(0).attr('b2b-trap-focus-inside-element', 'false');
5455         elem.children().eq(0).attr('trigger', scope.trigger);
5456         $compile(elem.contents())(scope);
5457       }
5458
5459       var firstElement = undefined,
5460           launchingElement = undefined;
5461       
5462       scope.$watch('trigger', function(oldVal, newVal) {
5463         if (oldVal === newVal) return;
5464         if (!angular.isDefined(launchingElement)) {
5465           launchingElement = document.activeElement;
5466         }
5467         $timeout(function() {
5468           if (scope.trigger) {
5469
5470             if (attrs.noFocus === true || attrs.noFocus === "") {
5471               elem.children()[0].focus();
5472             } else {
5473               firstElement = b2bDOMHelper.firstTabableElement(elem);
5474
5475               if (angular.isDefined(firstElement)) {
5476                 firstElement.focus();
5477               }
5478             }
5479             
5480           } else {
5481             if (angular.isDefined(launchingElement) && launchingElement.nodeName !== 'BODY') {
5482               if (launchingElement === document.activeElement) {
5483                 return;
5484               }
5485
5486               if (b2bDOMHelper.isInDOM(launchingElement) && b2bDOMHelper.isTabable(launchingElement)) {
5487                   // At this point, launchingElement is still a valid element, but focus will fail and 
5488                   // activeElement will become body, hence we want to apply custom logic and find previousElement
5489                   var prevLaunchingElement = launchingElement;
5490                   launchingElement.focus();
5491
5492                   if (document.activeElement !== launchingElement || document.activeElement.nodeName === 'BODY') {
5493                     launchingElement = b2bDOMHelper.previousElement(angular.element(prevLaunchingElement), true);
5494                     launchingElement.focus();
5495                   }
5496               } else {
5497                 launchingElement = b2bDOMHelper.previousElement(launchingElement, true);
5498                 launchingElement.focus();
5499               }
5500             }
5501           }
5502         }, scope.delay); 
5503       });
5504     }
5505   };
5506 }]);
5507 /**
5508  * @ngdoc directive
5509  * @name Messages, modals & alerts.att:modalsAndAlerts
5510  *
5511  * @description
5512  *  <file src="src/modalsAndAlerts/docs/readme.md" />
5513  *
5514  * @usage
5515  *  <button class="btn" b2b-modal="b2bTemplate/modalsAndAlerts/demo_modal.html" modal-ok="ok()" modal-cancel="cancel()">Launch demo modal</button>
5516  *
5517  * @example
5518  *  <section id="code">
5519      <example module="b2b.att">
5520       <file src="src/modalsAndAlerts/docs/demo.html" />
5521       <file src="src/modalsAndAlerts/docs/demo.js" />
5522      </example>
5523     </section>
5524  *
5525  */
5526 angular.module('b2b.att.modalsAndAlerts', ['b2b.att.position', 'b2b.att.transition', 'b2b.att.utilities'])
5527
5528 /**
5529  * A helper, internal data structure that acts as a map but also allows getting / removing
5530  * elements in the LIFO order
5531  */
5532 .factory('$$stackedMap', function () {
5533     return {
5534         createNew: function () {
5535             var stack = [];
5536
5537             return {
5538                 add: function (key, value) {
5539                     stack.push({
5540                         key: key,
5541                         value: value
5542                     });
5543                 },
5544                 get: function (key) {
5545                     for (var i = 0; i < stack.length; i++) {
5546                         if (key === stack[i].key) {
5547                             return stack[i];
5548                         }
5549                     }
5550                 },
5551                 keys: function () {
5552                     var keys = [];
5553                     for (var i = 0; i < stack.length; i++) {
5554                         keys.push(stack[i].key);
5555                     }
5556                     return keys;
5557                 },
5558                 top: function () {
5559                     return stack[stack.length - 1];
5560                 },
5561                 remove: function (key) {
5562                     var idx = -1;
5563                     for (var i = 0; i < stack.length; i++) {
5564                         if (key === stack[i].key) {
5565                             idx = i;
5566                             break;
5567                         }
5568                     }
5569                     return stack.splice(idx, 1)[0];
5570                 },
5571                 removeTop: function () {
5572                     return stack.splice(stack.length - 1, 1)[0];
5573                 },
5574                 length: function () {
5575                     return stack.length;
5576                 }
5577             };
5578         }
5579     };
5580 }).factory('trapFocusInElement', ['$document', '$isElement', 'b2bDOMHelper', 'keymap', function ($document, $isElement, b2bDOMHelper, keymap) {
5581     var elementStack = [];
5582     var stackHead = undefined;
5583     var firstTabableElement, lastTabableElement;
5584
5585     var trapKeyboardFocusInFirstElement = function (e) {
5586         if (!e.keyCode) {
5587             e.keyCode = e.which;
5588         }
5589
5590         if (e.shiftKey === true && e.keyCode === keymap.KEY.TAB) {
5591             lastTabableElement[0].focus();
5592             e.preventDefault(e);
5593             e.stopPropagation(e);
5594         }
5595
5596     };
5597
5598     var trapKeyboardFocusInLastElement = function (e) {
5599         if (!e.keyCode) {
5600             e.keyCode = e.which;
5601         }
5602
5603         if (e.shiftKey === false && e.keyCode === keymap.KEY.TAB) {
5604             firstTabableElement[0].focus();
5605             e.preventDefault(e);
5606             e.stopPropagation(e);
5607         }
5608     };
5609     
5610     var trapFocusInElement = function (flag, firstTabableElementParam, lastTabableElementParam) {
5611         var bodyElements = $document.find('body').children();
5612
5613         firstTabableElement = firstTabableElementParam ? firstTabableElementParam : angular.element(b2bDOMHelper.firstTabableElement(stackHead));
5614         lastTabableElement = lastTabableElementParam ? lastTabableElementParam : angular.element(b2bDOMHelper.lastTabableElement(stackHead));
5615
5616         if (flag) {
5617             for (var i = 0; i < bodyElements.length; i++) {
5618                 if (bodyElements[i] !== stackHead[0]) {
5619                     bodyElements.eq(i).attr('aria-hidden', true);
5620                 }
5621             }
5622             firstTabableElement.bind('keydown', trapKeyboardFocusInFirstElement);
5623             lastTabableElement.bind('keydown', trapKeyboardFocusInLastElement);
5624         } else {
5625             for (var j = 0; j < bodyElements.length; j++) {
5626                 if (bodyElements[j] !== stackHead[0]) {
5627                     bodyElements.eq(j).removeAttr('aria-hidden');
5628                 }
5629             }
5630             firstTabableElement.unbind('keydown', trapKeyboardFocusInFirstElement);
5631             lastTabableElement.unbind('keydown', trapKeyboardFocusInLastElement);
5632         }
5633     };
5634     var toggleTrapFocusInElement = function (flag, element) {
5635         if (angular.isDefined(flag) && angular.isDefined(element)) {
5636             if (angular.isUndefined(stackHead)) {
5637                 stackHead = element;
5638                 trapFocusInElement(flag);
5639             } else {
5640                 if (flag) {
5641                     trapFocusInElement(false);
5642                     elementStack.push(stackHead);
5643                     stackHead = element;
5644                     trapFocusInElement(true);
5645                 } else {
5646                     if (stackHead.prop('$$hashKey') === element.prop('$$hashKey')) {
5647                         trapFocusInElement(false);
5648                         stackHead = elementStack.pop();
5649                         if (angular.isDefined(stackHead)) {
5650                             trapFocusInElement(true);
5651                         }
5652                     }
5653                 }
5654             }
5655         }else {
5656             if (angular.isDefined(stackHead)) {
5657                 trapFocusInElement(false, firstTabableElement, lastTabableElement);
5658                 trapFocusInElement(true);
5659             }
5660         }
5661     };
5662
5663     return toggleTrapFocusInElement;
5664 }])
5665
5666 /**
5667  * A helper directive for the $modal service. It creates a backdrop element.
5668  */
5669 .directive('b2bModalBackdrop', ['$modalStack', '$timeout', function ($modalStack, $timeout) {
5670     return {
5671         restrict: 'EA',
5672         replace: true,
5673         templateUrl: 'b2bTemplate/modalsAndAlerts/b2b-backdrop.html',
5674         link: function (scope, element, attrs) {
5675             scope.close = function (evt) {
5676                 var modal = $modalStack.getTop();
5677                 if (modal && modal.value.backdrop && modal.value.backdrop !== 'static') {
5678                     evt.preventDefault();
5679                     evt.stopPropagation();
5680                     $modalStack.dismiss(modal.key, 'backdrop click');
5681                 }
5682             };
5683         }
5684     };
5685 }])
5686
5687 .directive('b2bModalWindow', ['$timeout', 'windowOrientation', '$window', 'keymap', function ($timeout, windowOrientation, $window, keymap) {
5688     return {
5689         restrict: 'EA',
5690         scope: {
5691             index: '@'
5692         },
5693         replace: true,
5694         transclude: true,
5695         templateUrl: 'b2bTemplate/modalsAndAlerts/b2b-window.html',
5696         controller: ['$scope', '$element', '$attrs', function (scope, element, attrs) {
5697             scope.windowClass = attrs.windowClass || '';
5698             scope.sizeClass = attrs.sizeClass || '';
5699             scope.isNotifDialog = false;
5700             scope.modalClose = attrs.modalClose || false;
5701
5702             this.setTitle = function (title) {
5703                 scope.title = title;
5704             };
5705             this.setContent = function (content) {
5706                 scope.content = content;
5707                 scope.isNotifDialog = true;
5708             };
5709             this.isDockedModal = scope.windowClass.indexOf('modal-docked') > -1;
5710         }],
5711         link: function (scope, element, attrs, ctrl) {
5712             if (ctrl.isDockedModal) {
5713                 scope.isModalLandscape = false;
5714
5715                 var window = angular.element($window);
5716                 scope.updateCss = function () {
5717                     if (windowOrientation.isPotrait()) { // Potrait Mode
5718                         scope.isModalLandscape = false;
5719                     } else if (windowOrientation.isLandscape()) { // Landscape Mode
5720                         scope.isModalLandscape = true;
5721                     }
5722                 };
5723
5724                 $timeout(function () {
5725                     scope.updateCss();
5726                     scope.$apply();
5727                 }, 100);
5728                 window.bind('orientationchange', function () {
5729                     scope.updateCss();
5730                     scope.$apply();
5731                 });
5732                 window.bind('resize', function () {
5733                     scope.updateCss();
5734                     scope.$apply();
5735                 });
5736             }else {
5737                 angular.element(element[0].querySelectorAll(".awd-select-list")).css({
5738                     "max-height": "200px"
5739                 });
5740             }
5741
5742             var isIE = /msie|trident/i.test(navigator.userAgent);
5743             if (isIE) {
5744                 if(angular.element(element[0].querySelector('.corner-button button.close')).length > 0){
5745                     angular.element(element[0].querySelector('.corner-button button.close')).bind('focus', function () {
5746                        angular.element(element[0].querySelector('.b2b-modal-header'))[0].scrollLeft = 0;
5747                        angular.element(element[0].querySelector('.b2b-modal-header'))[0].scrollTop = 0;
5748                     });
5749                 }
5750             }
5751
5752             if(scope.modalClose){
5753                 element.bind('keydown', function (e) {
5754                     if(e.keyCode == keymap.KEY.ESC){
5755                         e.preventDefault();
5756                         e.stopPropagation();
5757                     }
5758                 });
5759             }
5760         }
5761     };
5762 }])
5763
5764 .directive('b2bModalTitle', [function () {
5765     return {
5766         restrict: 'A',
5767         require: '^b2bModalWindow',
5768         link: function (scope, elem, attr, ctrl) {
5769             ctrl.setTitle(attr.id);
5770         }
5771     };
5772 }])
5773
5774 .directive('b2bModalContent', [function () {
5775     return {
5776         restrict: 'A',
5777         require: '^b2bModalWindow',
5778         link: function (scope, elem, attr, ctrl) {
5779             ctrl.setContent(attr.id);
5780         }
5781     };
5782 }])
5783
5784
5785 .directive('b2bModalBody', ['$timeout', '$position', '$document', '$window', 'windowOrientation', 'b2bAwdBreakpoints', function ($timeout, $position, $document, $window, windowOrientation, b2bAwdBreakpoints) {
5786     return {
5787         restrict: 'AC',
5788         scope: {
5789             index: '@'
5790         },
5791         require: '^b2bModalWindow',
5792         link: function (scope, element, attrs, ctrl) {
5793             var window = angular.element($window);
5794             var body = $document.find('body').eq(0);
5795             scope.setModalHeight = function () {
5796                 var modalHeaderHeight, modalFooterHeight, modalBodyHeight, windowHeight, windowWidth, modalHeight;
5797                 modalHeaderHeight = 0;
5798                 modalFooterHeight = 0;
5799                 windowHeight = $window.innerHeight;
5800                 windowWidth = $window.innerWidth;
5801                 body.css({
5802                     'height': windowHeight + 'px'
5803                 });
5804
5805                 if (ctrl.isDockedModal) {
5806                     var modalElements = element.parent().children();
5807                     for (var i = 0; i < modalElements.length; i++) {
5808                         if (modalElements.eq(i).hasClass('b2b-modal-header')) {
5809                             modalHeaderHeight = $position.position(modalElements.eq(i)).height;
5810                         } else if (modalElements.eq(i).hasClass('b2b-modal-footer')) {
5811                             modalFooterHeight = $position.position(modalElements.eq(i)).height;
5812                         }
5813                     }
5814
5815                     modalHeight = $position.position(element.parent()).height;
5816
5817                     modalBodyHeight = modalHeight - (modalHeaderHeight + modalFooterHeight) + 'px';
5818
5819                     if (windowOrientation.isPotrait()) { // Potrait Mode
5820                         element.removeAttr('style').css({
5821                             height: modalBodyHeight
5822                         });
5823                     } else if (windowOrientation.isLandscape() && windowWidth < b2bAwdBreakpoints.breakpoints.mobile.max) { // Landscape Mode Mobile
5824                         element.removeAttr('style');
5825                     } else if (windowOrientation.isLandscape() && windowWidth >= b2bAwdBreakpoints.breakpoints.mobile.max) { // Landscape Mode Non-Mobile
5826                         element.removeAttr('style').css({
5827                             height: modalBodyHeight
5828                         });
5829                     }
5830                 }
5831             };
5832
5833             $timeout(function () {
5834                 scope.setModalHeight();
5835                 scope.$apply();
5836             }, 100);
5837             window.bind('orientationchange', function () {
5838                 scope.setModalHeight();
5839                 scope.$apply();
5840             });
5841             window.bind('resize', function () {
5842                 scope.setModalHeight();
5843                 scope.$apply();
5844             });
5845         }
5846     };
5847 }])
5848
5849 .directive('b2bModalFooter', ['windowOrientation', '$window', function (windowOrientation, $window) {
5850     return {
5851         restrict: 'AC',
5852         scope: {
5853             index: '@'
5854         },
5855         link: function (scope, element, attrs) {
5856
5857         }
5858     };
5859 }])
5860
5861 .factory('$modalStack', ['$document', '$compile', '$rootScope', '$$stackedMap', '$log', '$timeout', 'trapFocusInElement', function ($document, $compile, $rootScope, $$stackedMap, $log, $timeout, trapFocusInElement) {
5862     var backdropjqLiteEl, backdropDomEl;
5863     var backdropScope = $rootScope.$new(true);
5864     var body = $document.find('body').eq(0);
5865     var html = $document.find('html').eq(0);
5866     var openedWindows = $$stackedMap.createNew();
5867     var $modalStack = {};
5868
5869     function backdropIndex() {
5870         var topBackdropIndex = -1;
5871         var opened = openedWindows.keys();
5872         for (var i = 0; i < opened.length; i++) {
5873             if (openedWindows.get(opened[i]).value.backdrop) {
5874                 topBackdropIndex = i;
5875             }
5876         }
5877         return topBackdropIndex;
5878     }
5879
5880     $rootScope.$watch(backdropIndex, function (newBackdropIndex) {
5881         backdropScope.index = newBackdropIndex;
5882     });
5883
5884     function removeModalWindow(modalInstance) {
5885         //background scroll fix
5886         html.removeAttr('style');
5887         body.removeAttr('style');
5888         body.removeClass('styled-by-modal');
5889
5890         var modalWindow = openedWindows.get(modalInstance).value;
5891         trapFocusInElement(false, modalWindow.modalDomEl);
5892
5893         //clean up the stack
5894         openedWindows.remove(modalInstance);
5895
5896         //remove window DOM element
5897         modalWindow.modalDomEl.remove();
5898
5899         //remove backdrop if no longer needed
5900         if (backdropDomEl && backdropIndex() === -1) {
5901             backdropDomEl.remove();
5902             backdropDomEl = undefined;
5903         }
5904
5905         //destroy scope
5906         modalWindow.modalScope.$destroy();
5907     }
5908
5909     $document.bind('keydown', function (evt) {
5910         var modal;
5911
5912         if (evt.which === 27) {
5913             modal = openedWindows.top();
5914             if (modal && modal.value.keyboard) {
5915                 $rootScope.$apply(function () {
5916                     $modalStack.dismiss(modal.key);
5917                 });
5918             }
5919         }
5920     });
5921
5922     $modalStack.open = function (modalInstance, modal) {
5923
5924         openedWindows.add(modalInstance, {
5925             deferred: modal.deferred,
5926             modalScope: modal.scope,
5927             backdrop: modal.backdrop,
5928             keyboard: modal.keyboard
5929         });
5930
5931         var angularDomEl = angular.element('<div b2b-modal-window></div>');
5932         angularDomEl.attr('window-class', modal.windowClass);
5933         angularDomEl.attr('size-class', modal.sizeClass);
5934         angularDomEl.attr('index', openedWindows.length() - 1);
5935         angularDomEl.attr('modal-close', modal.modalClose);
5936         angularDomEl.html(modal.content);
5937
5938         var modalDomEl = $compile(angularDomEl)(modal.scope);
5939         openedWindows.top().value.modalDomEl = modalDomEl;
5940         //background page scroll fix
5941         html.css({
5942             'overflow-y': 'hidden'
5943         });
5944         body.css({
5945             'overflow-y': 'hidden',
5946             'width': '100%',
5947             'height': window.innerHeight + 'px'
5948         });
5949         body.addClass('styled-by-modal');
5950         body.append(modalDomEl);
5951
5952         if (backdropIndex() >= 0 && !backdropDomEl) {
5953             backdropjqLiteEl = angular.element('<div b2b-modal-backdrop></div>');
5954             backdropDomEl = $compile(backdropjqLiteEl)(backdropScope);
5955             body.append(backdropDomEl);
5956         }
5957
5958         $timeout(function () {
5959
5960             if (modal.scope.$$childHead.isNotifDialog) {
5961                 angular.element(modalDomEl).find('button')[0].focus();
5962             } else {
5963                 angular.element(modalDomEl)[0].focus();
5964             }
5965             trapFocusInElement(true, angular.element(modalDomEl).eq(0));
5966         }, 200);
5967     };
5968
5969     $modalStack.close = function (modalInstance, result) {
5970         var modal = openedWindows.get(modalInstance);
5971         if (modal) {
5972             modal.value.deferred.resolve(result);
5973             removeModalWindow(modalInstance);
5974         }
5975     };
5976
5977     $modalStack.dismiss = function (modalInstance, reason) {
5978         var modalWindow = openedWindows.get(modalInstance).value;
5979         if (modalWindow) {
5980             modalWindow.deferred.reject(reason);
5981             removeModalWindow(modalInstance);
5982         }
5983     };
5984
5985     $modalStack.getTop = function () {
5986         return openedWindows.top();
5987     };
5988
5989     return $modalStack;
5990 }])
5991
5992 .provider('$modal', function () {
5993     var $modalProvider = {
5994         options: {
5995             backdrop: true, //can be also false or 'static'
5996             keyboard: true
5997         },
5998         $get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack', function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) {
5999             var $modal = {};
6000
6001             function getTemplatePromise(options) {
6002                 return options.template ? $q.when(options.template) :
6003                     $http.get(options.templateUrl, {
6004                         cache: $templateCache
6005                     }).then(function (result) {
6006                         return result.data;
6007                     });
6008             }
6009
6010             function getResolvePromises(resolves) {
6011                 var promisesArr = [];
6012                 angular.forEach(resolves, function (value, key) {
6013                     if (angular.isFunction(value) || angular.isArray(value)) {
6014                         promisesArr.push($q.when($injector.invoke(value)));
6015                     }
6016                 });
6017                 return promisesArr;
6018             }
6019
6020             $modal.open = function (modalOptions) {
6021
6022                 var modalResultDeferred = $q.defer();
6023                 var modalOpenedDeferred = $q.defer();
6024                 //prepare an instance of a modal to be injected into controllers and returned to a caller
6025                 var modalInstance = {
6026                     result: modalResultDeferred.promise,
6027                     opened: modalOpenedDeferred.promise,
6028                     close: function (result) {
6029                         $modalStack.close(modalInstance, result);
6030                     },
6031                     dismiss: function (reason) {
6032                         $modalStack.dismiss(modalInstance, reason);
6033                     }
6034                 };
6035
6036                 //merge and clean up options
6037                 modalOptions = angular.extend({}, $modalProvider.options, modalOptions);
6038                 modalOptions.resolve = modalOptions.resolve || {};
6039
6040                 //verify options
6041                 if (!modalOptions.template && !modalOptions.templateUrl) {
6042                     throw new Error('One of template or templateUrl options is required.');
6043                 }
6044
6045                 var templateAndResolvePromise =
6046                     $q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve)));
6047
6048
6049                 templateAndResolvePromise.then(function resolveSuccess(tplAndVars) {
6050
6051                     var modalScope = (modalOptions.scope || $rootScope).$new();
6052                     modalScope.$close = modalInstance.close;
6053                     modalScope.$dismiss = modalInstance.dismiss;
6054
6055                     var ctrlInstance, ctrlLocals = {};
6056                     var resolveIter = 1;
6057
6058                     //controllers
6059                     if (modalOptions.controller) {
6060                         ctrlLocals.$scope = modalScope;
6061                         ctrlLocals.$modalInstance = modalInstance;
6062                         angular.forEach(modalOptions.resolve, function (value, key) {
6063                             ctrlLocals[key] = tplAndVars[resolveIter++];
6064                         });
6065
6066                         ctrlInstance = $controller(modalOptions.controller, ctrlLocals);
6067                     }
6068
6069                     $modalStack.open(modalInstance, {
6070                         scope: modalScope,
6071                         deferred: modalResultDeferred,
6072                         content: tplAndVars[0],
6073                         backdrop: modalOptions.backdrop,
6074                         keyboard: modalOptions.keyboard,
6075                         windowClass: modalOptions.windowClass,
6076                         sizeClass: modalOptions.sizeClass,
6077                         modalClose: modalOptions.modalClose
6078                     });
6079
6080                 }, function resolveError(reason) {
6081                     modalResultDeferred.reject(reason);
6082                 });
6083
6084                 templateAndResolvePromise.then(function () {
6085                     modalOpenedDeferred.resolve(true);
6086                 }, function () {
6087                     modalOpenedDeferred.reject(false);
6088                 });
6089
6090                 return modalInstance;
6091             };
6092
6093             return $modal;
6094         }]
6095     };
6096
6097     return $modalProvider;
6098 })
6099
6100 .directive("b2bModal", ["$modal", "$log", '$scrollTo', function ($modal, $log, $scrollTo) {
6101     return {
6102         restrict: 'A',
6103         scope: {
6104             b2bModal: '@',
6105             modalController: '@',
6106             modalOk: '&',
6107             modalCancel: '&',
6108             windowClass: '@',
6109             sizeClass: '@', 
6110             modalClose: '@'
6111         },
6112         link: function (scope, elm, attr) {
6113             elm.bind('click', function (ev) {
6114                 var currentPosition = ev.pageY - ev.clientY;
6115                 ev.preventDefault();
6116                 if (angular.isDefined(elm.attr("href")) && elm.attr("href") !== "") {
6117                     scope.b2bModal = elm.attr("href");
6118                 }
6119                 $modal.open({
6120                     templateUrl: scope.b2bModal,
6121                     controller: scope.modalController,
6122                     windowClass: scope.windowClass,
6123                     sizeClass: scope.sizeClass, 
6124                     modalClose: scope.modalClose
6125                 }).result.then(function (value) {
6126                     scope.modalOk({
6127                         value: value
6128                     });
6129                     elm[0].focus();
6130                 }, function (value) {
6131                     scope.modalCancel({
6132                         value: value
6133                     });
6134                     elm[0].focus();
6135                 });
6136             });
6137         }
6138     };
6139 }])
6140
6141 .directive("utilityFilter", ["$modal", "$log", '$scrollTo', function ($modal, $log, $scrollTo) {
6142     return {
6143         restrict: 'EA',
6144         scope: {
6145             utilityFilter: '@'
6146         },
6147         require: 'ngModel',
6148         templateUrl: 'b2bTemplate/modal/u-filter.html',
6149         link: function (scope, element, attribute, ctrl) {
6150             //controller to be passed to $modal service
6151             scope.options = angular.copy(scope.$parent.$eval(attribute.ngModel));
6152             scope.$parent.$watch(attribute.ngModel, function (newVal, oldVal) {
6153                 if (newVal !== oldVal) {
6154                     scope.options = newVal;
6155                 }
6156             });
6157             var modalCtrl = function ($scope, options) {
6158                 $scope.options = angular.copy(options);
6159             };
6160
6161             if (angular.isDefined(scope.utilityFilter)) {
6162                 scope.templateUrl = scope.utilityFilter;
6163             } else {
6164                 scope.templateUrl = 'b2bTemplate/modal/u-filter-window.html';
6165             }
6166             element.bind('click', function (ev) {
6167                 var currentPosition = ev.pageY - ev.clientY;
6168                 $modal.open({
6169                     templateUrl: scope.templateUrl,
6170                     controller: modalCtrl,
6171                     resolve: {
6172                         options: function () {
6173                             return scope.options;
6174                         }
6175                     }
6176                 }).result.then(function (value) {
6177                     ctrl.$setViewValue(value);
6178                     element[0].focus();
6179                     $scrollTo(0, currentPosition, 0);
6180                 }, function () {
6181                     element[0].focus();
6182                     $scrollTo(0, currentPosition, 0);
6183                 });
6184             });
6185         }
6186     };
6187 }]);
6188 /**
6189  * @ngdoc directive
6190  * @name Forms.att:monthSelector
6191  *
6192  * @description
6193  *  <file src="src/monthSelector/docs/readme.md" />
6194  *
6195  * @usage
6196  * <div b2b-monthpicker ng-model="dt" min="minDate" max="maxDate" mode="monthpicker"></div>
6197     
6198  * @example
6199  *  <section id="code">
6200         <example module="b2b.att">
6201             <file src="src/monthSelector/docs/demo.html" />
6202             <file src="src/monthSelector/docs/demo.js" />
6203         </example>
6204     </section>
6205  *
6206  */
6207 angular.module('b2b.att.monthSelector', ['b2b.att.position', 'b2b.att.utilities'])
6208
6209 .constant('b2bMonthpickerConfig', {
6210     dateFormat: 'MM/dd/yyyy',
6211     dayFormat: 'd',
6212     monthFormat: 'MMMM',
6213     yearFormat: 'yyyy',
6214     dayHeaderFormat: 'EEEE',
6215     dayTitleFormat: 'MMMM yyyy',
6216     disableWeekend: false,
6217     disableSunday: false,
6218     disableDates: null,
6219     onSelectClose: null,
6220     startingDay: 0,
6221     minDate: null,
6222     maxDate: null,
6223     dueDate: null,
6224     fromDate: null,
6225     legendIcon: null,
6226     legendMessage: null,
6227     calendarDisabled: false,
6228     collapseWait: 0,
6229     orientation: 'left',
6230     inline: false,
6231     mode:0,
6232     helperText: 'The date you selected is $date. Double tap to open calendar. Select a date to close the calendar.',
6233     descriptionText: 'Use tab to navigate between previous button, next button and month. Use arrow keys to navigate between months. Use space or enter to select a month.',
6234     MonthpickerEvalAttributes: ['dateFormat', 'dayFormat', 'monthFormat', 'yearFormat', 'dayHeaderFormat', 'dayTitleFormat', 'disableWeekend', 'disableSunday', 'startingDay', 'collapseWait', 'orientation','mode','id'],
6235     MonthpickerWatchAttributes: ['min', 'max', 'due', 'from', 'legendIcon', 'legendMessage', 'ngDisabled'],
6236     MonthpickerFunctionAttributes: ['disableDates', 'onSelectClose']
6237 })
6238
6239 .factory('b2bMonthpickerService', ['b2bMonthpickerConfig', 'dateFilter', function (b2bMonthpickerConfig, dateFilter) {
6240     var setAttributes = function (attr, elem) {
6241         if (angular.isDefined(attr) && attr !== null && angular.isDefined(elem) && elem !== null) {
6242             var attributes = b2bMonthpickerConfig.MonthpickerEvalAttributes.concat(b2bMonthpickerConfig.MonthpickerWatchAttributes, b2bMonthpickerConfig.MonthpickerFunctionAttributes);
6243             for (var key in attr) {
6244                 var val = attr[key];
6245                 if (attributes.indexOf(key) !== -1 && angular.isDefined(val)) {
6246                     elem.attr(key.toSnakeCase(), key);
6247                 }
6248             }
6249         }
6250     };
6251
6252     var bindScope = function (attr, scope) {
6253         if (angular.isDefined(attr) && attr !== null && angular.isDefined(scope) && scope !== null) {
6254             var evalFunction = function (key, val) {
6255                 scope[key] = scope.$parent.$eval(val);
6256             };
6257
6258             var watchFunction = function (key, val) {
6259                 scope.$parent.$watch(val, function (value) {
6260                     scope[key] = value;
6261                 });
6262                 scope.$watch(key, function (value) {
6263                     scope.$parent[val] = value;
6264                 });
6265             };
6266
6267             var evalAttributes = b2bMonthpickerConfig.MonthpickerEvalAttributes;
6268             var watchAttributes = b2bMonthpickerConfig.MonthpickerWatchAttributes;
6269             for (var key in attr) {
6270                 var val = attr[key];
6271                 if (evalAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {
6272                     evalFunction(key, val);
6273                 } else if (watchAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {
6274                     watchFunction(key, val);
6275                 }
6276             }
6277         }
6278     };
6279
6280     return {
6281         setAttributes: setAttributes,
6282         bindScope: bindScope
6283     };
6284 }])
6285
6286 .controller('b2bMonthpickerController', ['$scope', '$attrs', 'dateFilter', '$element', '$position', 'b2bMonthpickerConfig', function ($scope, $attrs, dateFilter, $element, $position, dtConfig) {
6287     var format = {
6288             date: getValue($attrs.dateFormat, dtConfig.dateFormat),
6289             day: getValue($attrs.dayFormat, dtConfig.dayFormat),
6290             month: getValue($attrs.monthFormat, dtConfig.monthFormat),
6291             year: getValue($attrs.yearFormat, dtConfig.yearFormat),
6292             dayHeader: getValue($attrs.dayHeaderFormat, dtConfig.dayHeaderFormat),
6293             dayTitle: getValue($attrs.dayTitleFormat, dtConfig.dayTitleFormat),
6294             disableWeekend: getValue($attrs.disableWeekend, dtConfig.disableWeekend),
6295             disableSunday: getValue($attrs.disableSunday, dtConfig.disableSunday),
6296             disableDates: getValue($attrs.disableDates, dtConfig.disableDates)
6297         },
6298         startingDay = getValue($attrs.startingDay, dtConfig.startingDay);
6299
6300     $scope.minDate = dtConfig.minDate ? $scope.resetTime(dtConfig.minDate) : null;
6301     $scope.maxDate = dtConfig.maxDate ? $scope.resetTime(dtConfig.maxDate) : null;
6302     $scope.dueDate = dtConfig.dueDate ? $scope.resetTime(dtConfig.dueDate) : null;
6303     $scope.fromDate = dtConfig.fromDate ? $scope.resetTime(dtConfig.fromDate) : null;
6304     $scope.legendIcon = dtConfig.legendIcon ? dtConfig.legendIcon : null;
6305     $scope.legendMessage = dtConfig.legendMessage ? dtConfig.legendMessage : null;
6306     $scope.ngDisabled = dtConfig.calendarDisabled ? dtConfig.calendarDisabled : null;
6307     $scope.collapseWait = getValue($attrs.collapseWait, dtConfig.collapseWait);
6308     $scope.orientation = getValue($attrs.orientation, dtConfig.orientation);
6309     $scope.onSelectClose = getValue($attrs.onSelectClose, dtConfig.onSelectClose);
6310     $scope.mode = getValue($attrs.mode, dtConfig.mode);
6311     
6312     $scope.inline = $attrs.inline === 'true' ? true : dtConfig.inline;
6313
6314     function getValue(value, defaultValue) {
6315         return angular.isDefined(value) ? $scope.$parent.$eval(value) : defaultValue;
6316     }
6317
6318     function getDaysInMonth(year, month) {
6319         return new Date(year, month, 0).getDate();
6320     }
6321
6322     function getDates(startDate, n) {
6323         var dates = new Array(n);
6324         var current = startDate,
6325             i = 0;
6326         while (i < n) {
6327             dates[i++] = new Date(current);
6328             current.setDate(current.getDate() + 1);
6329         }
6330         return dates;
6331     }
6332
6333     this.updatePosition = function (b2bMonthpickerPopupTemplate) {
6334         $scope.position = $position.offset($element);
6335         if($element.find('input').length > 0 ){
6336             $scope.position.top += $element.find('input').prop('offsetHeight');
6337         }else{
6338             $scope.position.top += $element.find('a').prop('offsetHeight');
6339         }
6340         
6341         if ($scope.orientation === 'right') {
6342             $scope.position.left -= (((b2bMonthpickerPopupTemplate && b2bMonthpickerPopupTemplate.prop('offsetWidth')) || 290) - $element.find('input').prop('offsetWidth'));
6343         }
6344     };
6345
6346     function isSelected(dt) { 
6347         if (dt && angular.isDate($scope.currentDate) && compare(dt, $scope.currentDate) === 0) {
6348             return true;
6349         }
6350         return false;
6351     }
6352
6353     function isFromDate(dt) {
6354         if (dt && angular.isDate($scope.fromDate) && compare(dt, $scope.fromDate) === 0) {
6355             return true;
6356         }
6357         return false;
6358     }
6359
6360     function isDateRange(dt) {
6361         if (dt && $scope.fromDate && angular.isDate($scope.currentDate) && (compare(dt, $scope.fromDate) >= 0) && (compare(dt, $scope.currentDate) <= 0)) {
6362             return true;
6363         } else if (dt && $scope.fromDate && compare(dt, $scope.fromDate) === 0) {
6364             return true;
6365         }
6366         return false;
6367     }
6368
6369     function isOld(date, currentMonthDate) {
6370         if (date && currentMonthDate && (new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0).getTime() < new Date(currentMonthDate.getFullYear(), currentMonthDate.getMonth(), 1, 0, 0, 0).getTime())) {
6371             return true;
6372         } else {
6373             return false;
6374         }
6375     }
6376
6377     function isNew(date, currentMonthDate) {
6378         if (date && currentMonthDate && (new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0).getTime() > new Date(currentMonthDate.getFullYear(), currentMonthDate.getMonth(), 1, 0, 0, 0).getTime())) {
6379             return true;
6380         } else {
6381             return false;
6382         }
6383     }
6384
6385     function isPastDue(dt) {
6386         if ($scope.dueDate) {
6387             return (dt > $scope.dueDate);
6388         }
6389         return false;
6390     }
6391
6392     function isDueDate(dt) {
6393         if ($scope.dueDate) {
6394             return (dt.getTime() === $scope.dueDate.getTime());
6395         }
6396         return false;
6397     }
6398
6399     var isDisabled = function (date, currentMonthDate) {
6400         if ($attrs.from && !angular.isDate($scope.fromDate)) {
6401             return true;
6402         }
6403         if (format.disableWeekend === true && (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday")) {
6404             return true;
6405         }
6406         if (format.disableSunday === true && (dateFilter(date, format.dayHeader) === "Sunday")) {
6407             return true;
6408         }
6409         if (isOld(date, currentMonthDate) || isNew(date, currentMonthDate)) {
6410             return true;
6411         }
6412         return (($scope.minDate && compare(date, $scope.minDate) < 0) || ($scope.maxDate && compare(date, $scope.maxDate) > 0) || (format.disableDates && format.disableDates({
6413             date: date
6414         })));
6415     };
6416     
6417     var isDisabledMonth = function (date, currentMonthDate) {
6418         if ($attrs.from && !angular.isDate($scope.fromDate)) {
6419             return true;
6420         }
6421         if (format.disableWeekend === true && (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday")) {
6422             return true;
6423         }
6424         if (format.disableSunday === true && (dateFilter(date, format.dayHeader) === "Sunday")) {
6425             return true;
6426         }
6427         return (($scope.minDate && compare(date, $scope.minDate) < 0) || ($scope.maxDate && compare(date, $scope.maxDate) > 0) || (format.disableDates && format.disableDates({
6428             date: date
6429         })));
6430     };    
6431          
6432     var compare = function (date1, date2) {
6433         return (new Date(date1.getFullYear(), date1.getMonth(), date1.getDate()) - new Date(date2.getFullYear(), date2.getMonth(), date2.getDate()));
6434     };
6435
6436     function isMinDateAvailable(startDate, endDate) {
6437         if (($scope.minDate && $scope.minDate.getTime() >= startDate.getTime()) && ($scope.minDate.getTime() <= endDate.getTime())) {
6438             $scope.disablePrev = true;
6439             $scope.visibilityPrev = "hidden";
6440         } else {
6441             $scope.disablePrev = false;
6442             $scope.visibilityPrev = "visible";
6443         }
6444     }
6445     
6446     function isMaxDateAvailable(startDate, endDate) {
6447         if (($scope.maxDate && $scope.maxDate.getTime() >= startDate.getTime()) && ($scope.maxDate.getTime() <= endDate.getTime())) {
6448             $scope.disableNext = true;
6449             $scope.visibilityNext = "hidden";
6450         } else {
6451             $scope.disableNext = false;
6452             $scope.visibilityNext = "visible";
6453         }
6454     }    
6455     
6456     function isYearInRange(currentYear) {
6457             
6458         if ($scope.minDate && currentYear === $scope.minDate.getFullYear()) {
6459             $scope.disablePrev = true;
6460             $scope.visibilityPrev = "hidden";
6461         } else {
6462             $scope.disablePrev = false;
6463             $scope.visibilityPrev = "visible";
6464         }
6465         
6466         if ($scope.maxDate && currentYear === $scope.maxDate.getFullYear()) {
6467             $scope.disableNext = true;
6468             $scope.visibilityNext = "hidden";
6469         } else {
6470             $scope.disableNext = false;
6471             $scope.visibilityNext = "visible";
6472         }
6473         
6474     }    
6475
6476     this.focusNextPrev = function(b2bMonthpickerPopupTemplate,init){
6477         if(init){
6478             if (!$scope.disablePrev){
6479                 b2bMonthpickerPopupTemplate[0].querySelector('th.prev').focus();
6480             }else if (!$scope.disableNext){
6481                 b2bMonthpickerPopupTemplate[0].querySelector('th.next').focus();
6482             }else{
6483                 b2bMonthpickerPopupTemplate[0].querySelector('th.b2b-monthSelector-label').focus();
6484             }
6485         }else{
6486             if ($scope.disableNext || $scope.disablePrev){
6487                 b2bMonthpickerPopupTemplate[0].querySelector('th.b2b-monthSelector-label').focus();
6488             }       
6489         }    
6490     };
6491
6492     function getLabel(label) {
6493         if (label) {
6494             var labelObj = {
6495                 pre: label.substr(0, 1).toUpperCase(),
6496                 post: label
6497             };
6498             return labelObj;
6499         }
6500         return;
6501     }
6502
6503     function makeDate(date, dayFormat, dayHeaderFormat, isSelected, isFromDate, isDateRange, isOld, isNew, isDisabled, dueDate, pastDue) {
6504         return {
6505             date: date,
6506             label: dateFilter(date, dayFormat),
6507             header: dateFilter(date, dayHeaderFormat),
6508             selected: !!isSelected,
6509             fromDate: !!isFromDate,
6510             dateRange: !!isDateRange,
6511             oldMonth: !!isOld,
6512             nextMonth: !!isNew,
6513             disabled: !!isDisabled,
6514             dueDate: !!dueDate,
6515             pastDue: !!pastDue,
6516             focusable: !((isDisabled && !(isSelected || isDateRange)) || (isOld || isNew))
6517         };
6518     }
6519     
6520     this.modes = [
6521         {
6522             name: 'day',
6523             getVisibleDates: function (date) {
6524                 var year = date.getFullYear(),
6525                     month = date.getMonth(),
6526                     firstDayOfMonth = new Date(year, month, 1),
6527                     lastDayOfMonth = new Date(year, month + 1, 0);
6528                 var difference = startingDay - firstDayOfMonth.getDay(),
6529                     numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : -difference,
6530                     firstDate = new Date(firstDayOfMonth),
6531                     numDates = 0;
6532
6533                 if (numDisplayedFromPreviousMonth > 0) {
6534                     firstDate.setDate(-numDisplayedFromPreviousMonth + 1);
6535                     numDates += numDisplayedFromPreviousMonth; // Previous
6536                 }
6537                 numDates += getDaysInMonth(year, month + 1); // Current
6538                 numDates += (7 - numDates % 7) % 7; // Next
6539
6540                 var days = getDates(firstDate, numDates),
6541                     labels = new Array(7);
6542                 for (var i = 0; i < numDates; i++) {
6543                     var dt = new Date(days[i]);
6544                     days[i] = makeDate(dt,
6545                         format.day,
6546                         format.dayHeader,
6547                         isSelected(dt),
6548                         isFromDate(dt),
6549                         isDateRange(dt),
6550                         isOld(dt, date),
6551                         isNew(dt, date),
6552                         isDisabled(dt, date),
6553                         isDueDate(dt),
6554                         isPastDue(dt));
6555                 }
6556                 for (var j = 0; j < 7; j++) {
6557                     labels[j] = getLabel(dateFilter(days[j].date, format.dayHeader));
6558                 }
6559                 isMinDateAvailable(firstDayOfMonth, lastDayOfMonth);
6560                 isMaxDateAvailable(firstDayOfMonth, lastDayOfMonth);
6561                 return {
6562                     objects: days,
6563                     title: dateFilter(date, format.dayTitle),
6564                     labels: labels
6565                 };
6566             },
6567             split: 7,
6568             step: {
6569                 months: 1
6570             }
6571         },
6572         {
6573             name: 'month',
6574             getVisibleDates: function(date) {
6575                 var months = [], 
6576                     labels = [], 
6577                     year = date.getFullYear();
6578                     for (var i = 0; i < 12; i++) {
6579                         var dt = new Date(year,i,1);                
6580                         months[i] = makeDate(dt,
6581                                     format.month,
6582                                     format.dayHeader,
6583                                     isSelected(dt), 
6584                                     isFromDate(dt),
6585                                     isDateRange(dt),
6586                                     false,
6587                                     false,
6588                                     isDisabledMonth(dt, date),
6589                                     isDueDate(dt),                                       
6590                                     isPastDue(dt));                                                                                                                                                         
6591                     }
6592                 isYearInRange(year);  
6593                 return {objects: months, title: dateFilter(date, format.year), labels: labels};
6594             },
6595             split:4,
6596             step: {years: 1}
6597         }
6598     ];
6599 }])
6600
6601 .directive('b2bMonthpickerPopup', ['$parse', '$log', '$timeout', '$document', '$documentBind', '$isElement', '$templateCache', '$compile','$interval', 'trapFocusInElement', 'keymap', function ($parse, $log, $timeout, $document, $documentBind, $isElement, $templateCache, $compile, $interval,trapFocusInElement, keymap) {
6602     return {
6603         restrict: 'EA',
6604         scope: {
6605           trigger: '='
6606         },
6607         replace: true,
6608         transclude: true,
6609         templateUrl: function (elem, attr) {
6610             if (attr.inline === 'true') {
6611                 return 'b2bTemplate/monthSelector/monthSelector-popup.html';
6612             }else if (attr.link === 'true') {
6613                 return 'b2bTemplate/monthSelector/monthSelectorLink.html';
6614             }else {
6615                 return 'b2bTemplate/monthSelector/monthSelector.html';
6616             }
6617         },
6618         scope: {},
6619         require: ['b2bMonthpickerPopup', 'ngModel', '?^b2bMonthpickerGroup'],
6620         controller: 'b2bMonthpickerController',
6621         link: function (scope, element, attrs, ctrls) {
6622             var MonthpickerCtrl = ctrls[0],
6623                 ngModel = ctrls[1],
6624                 b2bMonthpickerGroupCtrl = ctrls[2];
6625             var b2bMonthpickerPopupTemplate;
6626
6627             if (!ngModel) {
6628                 $log.error("ng-model is required.");
6629                 return; // do nothing if no ng-model
6630             }
6631
6632             // Configuration parameters
6633             var mode = scope.mode,
6634                 selected;
6635             scope.isOpen = false;
6636
6637             scope.headers = [];
6638             scope.footers = [];
6639             scope.triggerInterval=undefined;
6640
6641
6642             if (b2bMonthpickerGroupCtrl) {
6643                 b2bMonthpickerGroupCtrl.registerMonthpickerScope(scope);
6644             }
6645
6646             element.bind('keydown', function (ev) {                   
6647                 if (!ev.keyCode) {
6648                     if (ev.which) {
6649                         ev.keyCode = ev.which;
6650                     } else if (ev.charCode) {
6651                         ev.keyCode = ev.charCode;
6652                     }
6653                 }                                
6654                 if(ev.keyCode === keymap.KEY.ESC)
6655                 {
6656                     scope.isOpen = false;
6657                     toggleCalendar(scope.isOpen);
6658                     scope.$apply();
6659                 }
6660             });
6661             
6662             element.find('button').bind('click', function () {
6663                 onClicked();                
6664             });
6665
6666             element.find('a').bind('click', function () {
6667                 onClicked();                
6668             });
6669
6670             
6671             element.find('input').bind('click', function () {
6672                 onClicked();
6673             });
6674
6675             var onClicked = function() {        
6676                 if (!scope.ngDisabled) {
6677                     scope.isOpen = !scope.isOpen;
6678                     toggleCalendar(scope.isOpen);                    
6679                     MonthpickerCtrl.updatePosition(b2bMonthpickerPopupTemplate);
6680                     scope.$apply();
6681                 }
6682             };
6683         
6684             var toggleCalendar = function (flag) {
6685                 if (!scope.inline) {
6686                     if (flag) {
6687                         b2bMonthpickerPopupTemplate = angular.element($templateCache.get('b2bTemplate/monthSelector/monthSelector-popup.html'));
6688                         b2bMonthpickerPopupTemplate.attr('b2b-trap-focus-inside-element', 'false');
6689                         b2bMonthpickerPopupTemplate.attr('trigger', 'true');
6690                         b2bMonthpickerPopupTemplate = $compile(b2bMonthpickerPopupTemplate)(scope);
6691                         $document.find('body').append(b2bMonthpickerPopupTemplate);
6692                         b2bMonthpickerPopupTemplate.bind('keydown', escPress);
6693                         $timeout(function () {
6694                             scope.getFocus = true;
6695                             scope.trigger=0;
6696                             scope.$apply();
6697                             $timeout(function () {
6698                                 scope.getFocus = false;
6699                                 scope.$apply();
6700                                 MonthpickerCtrl.focusNextPrev(b2bMonthpickerPopupTemplate,true);
6701                             }, 100);
6702                         });
6703                         scope.triggerInterval = $interval(function () {
6704                             //This value is updated to trigger init() function of directive on year change.
6705                             scope.trigger=(scope.trigger === 0 ? 1 : 0);
6706                         }, 200);
6707
6708                     } else {
6709                         b2bMonthpickerPopupTemplate.unbind('keydown', escPress);
6710                         if(scope.triggerInterval)
6711                         {
6712                             $interval.cancel(scope.triggerInterval);
6713                             scope.triggerInterval=undefined;
6714                         }
6715                         b2bMonthpickerPopupTemplate.remove();
6716                         if(element.find('button').length > 0){
6717                             element.find('button')[0].focus();
6718                         }else{
6719                             element.find('a')[0].focus();
6720                         }
6721                         
6722                         scope.getFocus = false;
6723                     }
6724                 }
6725             };
6726
6727             var outsideClick = function (e) {
6728                 var isElement = $isElement(angular.element(e.target), element, $document);
6729                 var isb2bMonthpickerPopupTemplate = $isElement(angular.element(e.target), b2bMonthpickerPopupTemplate, $document);
6730                 if (!(isElement || isb2bMonthpickerPopupTemplate)) {
6731                     scope.isOpen = false;
6732                     toggleCalendar(scope.isOpen);
6733                     scope.$apply();
6734                 }
6735             };
6736
6737             var escPress = function (ev) {
6738                 if (!ev.keyCode) {
6739                     if (ev.which) {
6740                         ev.keyCode = ev.which;
6741                     } else if (ev.charCode) {
6742                         ev.keyCode = ev.charCode;
6743                     }
6744                 }
6745                 if (ev.keyCode) {
6746                     if (ev.keyCode === keymap.KEY.ESC) {
6747                         scope.isOpen = false;
6748                         toggleCalendar(scope.isOpen);
6749                         ev.preventDefault();
6750                         ev.stopPropagation();
6751                     } else if (ev.keyCode === 33) {
6752                         !scope.disablePrev && scope.move(-1);
6753                         $timeout(function () {
6754                             scope.getFocus = true;
6755                             scope.$apply();
6756                             $timeout(function () {
6757                                 scope.getFocus = false;
6758                                 scope.$apply();
6759                             }, 100);
6760                         });
6761                         ev.preventDefault();
6762                         ev.stopPropagation();
6763                     } else if (ev.keyCode === 34) {
6764                         !scope.disableNext && scope.move(1);
6765                         $timeout(function () {
6766                             scope.getFocus = true;
6767                             scope.$apply();
6768                             $timeout(function () {
6769                                 scope.getFocus = false;
6770                                 scope.$apply();
6771                             }, 100);
6772                         });
6773                         ev.preventDefault();
6774                         ev.stopPropagation();
6775                     }
6776                     scope.$apply();
6777                 }
6778             };                          
6779                                         
6780             $documentBind.click('isOpen', outsideClick, scope);
6781
6782             scope.$on('$destroy', function () {
6783                 if (scope.isOpen) {
6784                     scope.isOpen = false;
6785                     toggleCalendar(scope.isOpen);
6786                 }
6787             });
6788
6789             scope.resetTime = function (date) {
6790                 if (typeof date === 'string') {
6791                     date = date + 'T12:00:00';
6792                 }
6793                 var dt;
6794                 if (!isNaN(new Date(date))) {
6795                     dt = new Date(date);
6796                     if(scope.mode === 1){
6797                         dt = new Date(dt.getFullYear(), dt.getMonth());
6798                     }else{
6799                         dt = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());
6800                     }                                                            
6801                 } else {
6802                     return null;
6803                 }
6804                 return new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());
6805             };
6806             
6807             if (attrs.min) {
6808                 scope.$parent.$watch($parse(attrs.min), function (value) {
6809                     scope.minDate = value ? scope.resetTime(value) : null;
6810                     refill();
6811                 });
6812             }
6813             if (attrs.max) {
6814                 scope.$parent.$watch($parse(attrs.max), function (value) {
6815                     scope.maxDate = value ? scope.resetTime(value) : null;
6816                     refill();
6817                 });
6818             }
6819             if (attrs.due) {
6820                 scope.$parent.$watch($parse(attrs.due), function (value) {
6821                     scope.dueDate = value ? scope.resetTime(value) : null;
6822                     refill();
6823                 });
6824             }
6825             if (attrs.from) {
6826                 scope.$parent.$watch($parse(attrs.from), function (value) {
6827                     scope.fromDate = value ? scope.resetTime(value) : null;
6828                     refill();
6829                 });
6830             }
6831
6832             if (attrs.legendIcon) {
6833                 scope.$parent.$watch(attrs.legendIcon, function (value) {
6834                     scope.legendIcon = value ? value : null;
6835                     refill();
6836                 });
6837             }
6838             if (attrs.legendMessage) {
6839                 scope.$parent.$watch(attrs.legendMessage, function (value) {
6840                     scope.legendMessage = value ? value : null;
6841                     refill();
6842                 });
6843             }
6844             if (attrs.ngDisabled) {
6845                 scope.$parent.$watch(attrs.ngDisabled, function (value) {
6846                     scope.ngDisabled = value ? value : null;
6847                 });
6848             }      
6849             
6850
6851             // Split array into smaller arrays
6852             function split(arr, size) {
6853                 var arrays = [];
6854                 while (arr.length > 0) {
6855                     arrays.push(arr.splice(0, size));
6856                 }
6857                 return arrays;
6858             }
6859             
6860             var moveMonth = function(selectedDate, direction) {
6861                 var step = MonthpickerCtrl.modes[scope.mode].step;
6862                 selectedDate.setDate(1);
6863                 selectedDate.setMonth(selectedDate.getMonth() + direction * (step.months || 0));
6864                 selectedDate.setFullYear(selectedDate.getFullYear() + direction * (step.years || 0));
6865
6866                 return selectedDate;
6867             };            
6868
6869             function refill(date) {
6870                 if (angular.isDate(date) && !isNaN(date)) {
6871                     selected = new Date(date);
6872                 } else {
6873                     if (!selected) {
6874                         selected = new Date();
6875                     }
6876                 }
6877
6878                 if (selected) {                    
6879                     var selectedCalendar;
6880                     if(scope.mode === 1){
6881                         if(!angular.isDate(selected))
6882                            {                           
6883                                 selected = new Date();
6884                            }
6885                         selectedCalendar = moveMonth(angular.copy(selected), -1);
6886                     } else {
6887                         selectedCalendar = angular.copy(selected);
6888                     }
6889                     
6890                     var currentMode = MonthpickerCtrl.modes[mode],
6891                         data = currentMode.getVisibleDates(selected);
6892
6893                     scope.rows = split(data.objects, currentMode.split);
6894             
6895                     var flag=false;
6896                     var startFlag=false;
6897                     var firstSelected = false;
6898                     for(var i=0; i<scope.rows.length; i++)
6899                     {
6900                         for(var j=0; j<scope.rows[i].length; j++)
6901                         {
6902                             if(!scope.rows[i][j].disabled && !firstSelected)
6903                             {
6904                                 firstSelected=true;
6905                                 var firstDay = scope.rows[i][j];
6906                             }
6907
6908                             if(scope.rows[i][j].selected)
6909                             {
6910                                 flag=true;
6911                                 break;
6912                             }                  
6913                         }
6914                         if(flag)
6915                         {
6916                             break;
6917                         }
6918                     }
6919                     if(!flag && firstSelected)
6920                     {
6921                        firstDay.firstFocus=true;
6922                     }
6923
6924                     scope.labels = data.labels || [];
6925                     scope.title = data.title;                    
6926                 }
6927             }
6928
6929             scope.select = function (date,$event) {
6930                 var dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());
6931                 scope.currentDate = dt;
6932                 if (!scope.onSelectClose || (scope.onSelectClose && scope.onSelectClose({
6933                         date: dt
6934                     }) !== false)) {
6935                     if (angular.isNumber(scope.collapseWait)) {
6936                         $timeout(function () {
6937                             scope.isOpen = false;
6938                             toggleCalendar(scope.isOpen);
6939                         }, scope.collapseWait);
6940                     } else {
6941                         scope.isOpen = false;
6942                         toggleCalendar(scope.isOpen);
6943                     }
6944                 }
6945             };
6946
6947             scope.move = function (direction,$event) {
6948                 var step = MonthpickerCtrl.modes[mode].step;
6949                 selected.setDate(1);
6950                 selected.setMonth(selected.getMonth() + direction * (step.months || 0));
6951                 selected.setFullYear(selected.getFullYear() + direction * (step.years || 0));
6952                 refill();
6953                 scope.getFocus = true;
6954                 $timeout(function () {
6955                     if (attrs.inline === 'true') {
6956                         MonthpickerCtrl.focusNextPrev(element,false); 
6957                     }else{
6958                         MonthpickerCtrl.focusNextPrev(b2bMonthpickerPopupTemplate,false);
6959                     }
6960                 },100);
6961                 $event.preventDefault();
6962                 $event.stopPropagation();
6963             };
6964
6965             scope.$watch('currentDate', function (value) {
6966                 if (angular.isDefined(value) && value !== null) {
6967                     refill(value);
6968                 } else {
6969                     refill();
6970                 }
6971                 ngModel.$setViewValue(value);
6972             });
6973
6974             ngModel.$render = function () {
6975                 scope.currentDate = ngModel.$viewValue;
6976             };
6977
6978             var stringToDate = function (value) {
6979                 if (!isNaN(new Date(value))) {
6980                     value = new Date(value);
6981                 }
6982                 return value;
6983             };
6984             ngModel.$formatters.unshift(stringToDate);
6985         }
6986     };
6987 }])
6988
6989 .directive('b2bMonthpicker', ['$compile', '$log', 'b2bMonthpickerConfig', 'b2bMonthpickerService', function ($compile, $log, b2bMonthpickerConfig, b2bMonthpickerService) {
6990     return {
6991         restrict: 'A',
6992         scope: {
6993             disableDates: '&',
6994             onSelectClose: '&'
6995         },
6996         require: 'ngModel',
6997         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
6998             var dateFormatString = angular.isDefined(attr.dateFormat) ? scope.$parent.$eval(attr.dateFormat) : b2bMonthpickerConfig.dateFormat;
6999             var helperText = angular.isDefined(attr.helperText) ? scope.$parent.$eval(attr.helperText) : b2bMonthpickerConfig.helperText; 
7000             helperText = helperText.replace('$date', '{{dt | date : \'' + dateFormatString + '\'}}');
7001
7002             var descriptionText = angular.isDefined(attr.descriptionText) ? scope.$parent.$eval(attr.descriptionText) : b2bMonthpickerConfig.descriptionText;  
7003
7004
7005             var inline = false;
7006             if (elem.prop('nodeName') !== 'INPUT' && elem.prop('nodeName') !== 'A') {
7007                 inline = true;
7008             }
7009
7010             var selectedDateMessage = "";
7011             
7012             if (elem.prop('nodeName') !== 'A'){
7013                 selectedDateMessage = '<button type="button" class="span12 faux-input" ng-disabled="ngDisabled" aria-describedby="monthpicker-description'+scope.$id+'"><span class="hidden-spoken" aria-live="assertive" aria-atomic="false">' + helperText + '</span></button>';    
7014                 elem.attr('tabindex', '-1'); 
7015                 elem.attr('aria-hidden', 'true');  
7016                 elem.attr('readonly', 'true'); 
7017             }else{
7018                 selectedDateMessage = ''
7019                 elem.attr('aria-label', helperText);
7020             }
7021             
7022             var descriptionTextSpan = '<span class="offscreen-text" id="monthpicker-description'+scope.$id+'">'+descriptionText+'</span>';
7023             elem.removeAttr('b2b-Monthpicker');
7024             elem.removeAttr('ng-model');
7025             elem.removeAttr('ng-disabled');
7026             elem.addClass('Monthpicker-input');
7027             elem.attr('ng-model', 'dt');
7028             elem.attr('aria-describedby', 'monthpicker-description'+scope.$id);
7029             
7030             
7031             
7032             elem.attr('ng-disabled', 'ngDisabled');
7033             elem.attr('b2b-format-date', dateFormatString);
7034
7035             var wrapperElement = angular.element('<div></div>');
7036             wrapperElement.attr('b2b-Monthpicker-popup', '');
7037             wrapperElement.attr('ng-model', 'dt');
7038             if (inline) {
7039                 wrapperElement.attr('inline', inline);
7040             }
7041             if (elem.prop('nodeName') === 'A'){
7042                 wrapperElement.attr('link', true);
7043             }
7044             b2bMonthpickerService.setAttributes(attr, wrapperElement);
7045             b2bMonthpickerService.bindScope(attr, scope);
7046
7047             wrapperElement.html('');
7048             wrapperElement.append(selectedDateMessage);
7049             wrapperElement.append('');
7050             wrapperElement.append(descriptionTextSpan);
7051             wrapperElement.append('');
7052             wrapperElement.append(elem.prop('outerHTML'));
7053
7054             var elm = wrapperElement.prop('outerHTML');
7055             elm = $compile(elm)(scope);
7056             elem.replaceWith(elm);
7057         }],
7058         link: function (scope, elem, attr, ctrl) {
7059             if (!ctrl) {
7060                 $log.error("ng-model is required.");
7061                 return; // do nothing if no ng-model
7062             }
7063             
7064             scope.$watch('dt', function (value) {
7065                 ctrl.$setViewValue(value);
7066             });
7067             ctrl.$render = function () {
7068                 scope.dt = ctrl.$viewValue;
7069             };
7070         }
7071     };
7072 }])
7073
7074 .directive('b2bMonthpickerGroup', [function () {
7075     return {
7076         restrict: 'EA',
7077         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
7078             this.$$headers = [];
7079             this.$$footers = [];
7080             this.registerMonthpickerScope = function (MonthpickerScope) {
7081                 MonthpickerScope.headers = this.$$headers;
7082                 MonthpickerScope.footers = this.$$footers;
7083             };
7084         }],
7085         link: function (scope, elem, attr, ctrl) {}
7086     };
7087 }])
7088
7089 .directive('b2bFormatDate', ['dateFilter', function (dateFilter) {
7090     return {
7091         restrict: 'A',
7092         require: 'ngModel',
7093         link: function (scope, elem, attr, ctrl) {
7094             var b2bFormatDate = "";
7095             attr.$observe('b2bFormatDate', function (value) {
7096                 b2bFormatDate = value;
7097             });
7098             var dateToString = function (value) {
7099                 if (!isNaN(new Date(value))) {
7100                     return dateFilter(new Date(value), b2bFormatDate);
7101                 }
7102                 return value;
7103             };
7104             ctrl.$formatters.unshift(dateToString);
7105         }
7106     };
7107 }])
7108
7109 .directive('b2bMonthpickerHeader', [function () {
7110     return {
7111         restrict: 'EA',
7112         require: '^b2bMonthpickerGroup',
7113         transclude: true,
7114         replace: true,
7115         template: '',
7116         compile: function (elem, attr, transclude) {
7117             return function link(scope, elem, attr, ctrl) {
7118                 if (ctrl) {
7119                     ctrl.$$headers.push(transclude(scope, function () {}));
7120                 }
7121                 elem.remove();
7122             };
7123         }
7124     };
7125 }])
7126
7127 .directive('b2bMonthpickerFooter', [function () {
7128     return {
7129         restrict: 'EA',
7130         require: '^b2bMonthpickerGroup',
7131         transclude: true,
7132         replace: true,
7133         template: '',
7134         compile: function (elem, attr, transclude) {
7135             return function link(scope, elem, attr, ctrl) {
7136                 if (ctrl) {
7137                     ctrl.$$footers.push(transclude(scope, function () {}));
7138                 }
7139                 elem.remove();
7140             };
7141         }
7142     };
7143 }]);
7144 /**
7145  * @ngdoc directive
7146  * @name Navigation.att:multiLevelNavigation
7147  *
7148  * @description
7149  *  <file src="src/multiLevelNavigation/docs/readme.md" />
7150  *
7151  * @usage
7152  *       <div class="b2b-ml-nav">
7153  *          <ul role="tree">
7154  *             <li aria-label="{{child.name}}" tabindex="-1" b2b-ml-nav="{{child.type}}" role="treeitem" ng-repeat="child in treeStructure">
7155  *                  <a tabindex="-1" href="javascript:void(0);" title="{{child.name}}">{{child.name}}<span><i class="{{child.type=='endNode'?'icon-primary-circle':'icon-primary-collapsed'}}"></i></span></a>
7156  *                      <!-- Below UL tag is RECURSIVE to generate n-childs -->
7157  *                      <ul role="group" ng-if="child.child">
7158  *                          <li aria-label="{{child.name}}" b2b-ml-nav="{{child.type}}" tabindex="-1" role="treeitem" ng-repeat="child in child.child">
7159  *                          <a tabindex="-1" href="javascript:void(0);" title="{{child.name}}">{{child.name}}<span><i class="{{child.type=='endNode'?'icon-primary-circle':'icon-primary-collapsed'}}"></i></span></a>
7160  *                               <!-- RECURSIVE UL tag goes here -->
7161  *                          </li>
7162  *                      </ul>
7163  *             </li>
7164  *           </ul>
7165  *        </div>
7166  *
7167  * @example
7168  *  <section id="code">
7169         <example module="b2b.att">
7170             <file src="src/multiLevelNavigation/docs/demo.html" />
7171             <file src="src/multiLevelNavigation/docs/demo.js" />
7172        </example>
7173     </section>
7174  *
7175  */
7176 angular.module('b2b.att.multiLevelNavigation', ['b2b.att.utilities'])
7177     //directive b2bMlNav Test coverage 100% on 5/13
7178     .directive('b2bMlNav', ['keymap', function (keymap) {
7179         return {
7180             restrict: 'EA',
7181             link: function (scope, element) {
7182                 var rootE, parentE, upE, downE, lastE, homeE, endE;
7183                 //default root tree element tabindex set zero
7184                 if (element.parent().parent().hasClass('b2b-ml-nav') && (element[0].previousElementSibling === null)) {
7185                     element.attr('tabindex', 0);
7186                 }
7187                 //check root via class
7188                 var isRoot = function (elem) {
7189                         if (elem.parent().parent().eq(0).hasClass('b2b-ml-nav')) {
7190                             return true;
7191                         } else {
7192                             return false;
7193                         }
7194
7195                     }
7196                     //for any expandable tree item on click
7197                 var toggleState = function (e) {
7198                                     
7199                     if (angular.element(e.target).attr("b2b-ml-nav") !== "endNode") {
7200                         var eLink = element.find('a').eq(0);
7201                         if (eLink.hasClass('active')) {
7202                             eLink.removeClass('active');
7203                             eLink.parent().attr("aria-expanded", "false");
7204                             eLink.find('i').eq(0).removeClass('icon-primary-expanded');
7205                             eLink.find('i').eq(0).addClass('icon-primary-collapsed');
7206                         } else {
7207                             eLink.addClass('active');
7208                             eLink.parent().attr("aria-expanded", "true");
7209                             eLink.find('i').eq(0).removeClass('icon-primary-collapsed');
7210                             eLink.find('i').eq(0).addClass('icon-primary-expanded');
7211                         }
7212                     }
7213                 };
7214                 //function finds the main root-item from particular tree-group
7215                 var findRoot = function (elem) {
7216                     if (isRoot(elem)) {
7217                         rootE = elem;
7218                         return;
7219                     }
7220                     if (elem.attr("b2b-ml-nav") === "middleNode" || elem.attr("b2b-ml-nav") === "endNode") {
7221                         parentE = elem.parent().parent();
7222                     } else {
7223                         parentE = elem;
7224                     }
7225                     if (parentE.attr("b2b-ml-nav") === "rootNode") {
7226                         rootE = parentE;
7227                     } else {
7228                         findRoot(parentE);
7229                     }
7230                 };
7231                 //finds the last visible node of the previous tree-group
7232                 var findPreActive = function (elem) {
7233                     if (!(elem.hasClass("active"))) {
7234                         return;
7235                     } else {
7236                         var childElems = angular.element(elem[0].nextElementSibling.children);
7237                         lastE = angular.element(childElems[childElems.length - 1]);
7238                         if (lastE.attr("b2b-ml-nav") === "middleNode" && lastE.find('a').eq(0).hasClass('active')) {
7239                             findPreActive(lastE.find('a').eq(0));
7240                         }
7241                         upE = lastE;
7242                     }
7243                 };
7244                 //find above visible link
7245                 var findUp = function (elem) {
7246                     if (elem[0].previousElementSibling !== null) {
7247                         upE = angular.element(elem[0].previousElementSibling);
7248                     } else {
7249                         upE = elem.parent().parent();
7250                     }
7251                     if (isRoot(elem) || (upE.attr('b2b-ml-nav') === "middleNode" && upE[0] !== elem.parent().parent()[0])) {
7252                         findPreActive(upE.find('a').eq(0)); 
7253                     }
7254                 };
7255                 //find below visible link
7256                 var findDown = function (elem) {
7257                     if (elem.hasClass('active')) {
7258                         downE = elem.next().find('li').eq(0);
7259                     } else {
7260                         if (elem.parent().next().length !== 0) {
7261                             downE = elem.parent().next().eq(0);
7262                         } else {
7263                             if (elem.parent().parent().parent().next().length !== 0) {
7264                                 downE = elem.parent().parent().parent().next().eq(0);
7265                                 return;
7266                             }
7267                             downE = elem.parent().eq(0);
7268                         }
7269                     }
7270                 };
7271                 //finds last root-group element of the tree
7272                 var findEnd = function (elem) {
7273                     findRoot(elem);
7274                     endE = angular.element(rootE.parent()[0].children[rootE.parent()[0].children.length - 1]);
7275                 };
7276                 //finds first root element of tree
7277                 var findHome = function (elem) {
7278                     findRoot(elem);
7279                     homeE = angular.element(rootE.parent()[0].children[0]);
7280                 };
7281                 element.bind('click', function (e) {
7282                     if(element.attr("b2b-ml-nav") !== "endNode") { 
7283                         toggleState(e); 
7284                     }
7285                     if (rootE==undefined){
7286                         findRoot(element);
7287                     }
7288                     var currSelected = rootE.parent()[0].querySelector('.selected');
7289                     if(currSelected){
7290                         angular.element(currSelected).removeClass('selected');
7291                     }                    
7292                     element.find('a').eq(0).addClass('selected');
7293                     e.stopPropagation();
7294                 });
7295                 element.bind('focus', function (e) {
7296                     if(element.attr("b2b-ml-nav") !== "endNode") {
7297                         if(element.find('a').eq(0).hasClass('active')) {
7298                             element.attr("aria-expanded", true);
7299                         }
7300                         else {
7301                             element.attr("aria-expanded", false);
7302                         }
7303                         
7304                     }
7305                 })
7306                 //Keyboard functionality approach:
7307                 //find keycode
7308                 //set set tabindex -1 on the current focus element
7309                 //find the next element to be focussed, set tabindex 0 and throw focus
7310                 element.bind('keydown', function (evt) {
7311                     switch (evt.keyCode) {
7312                     case keymap.KEY.ENTER:
7313                     case keymap.KEY.SPACE:
7314                         element.triggerHandler('click');
7315                         evt.stopPropagation();
7316                         evt.preventDefault();
7317                         break;
7318                     case keymap.KEY.END:
7319                         evt.preventDefault();
7320                         element.attr('tabindex', -1);
7321                         findEnd(element);
7322                         endE.eq(0).attr('tabindex', 0);
7323                         endE[0].focus();
7324                         evt.stopPropagation();
7325                         break;
7326                     case keymap.KEY.HOME:
7327                         evt.preventDefault();
7328                         element.attr('tabindex', -1);
7329                         findHome(element);
7330                         homeE.eq(0).attr('tabindex', 0);
7331                         homeE[0].focus();
7332                         evt.stopPropagation();
7333                         break;
7334                     case keymap.KEY.LEFT:
7335                         evt.preventDefault();
7336                         if (!isRoot(element)) {
7337                             element.attr('tabindex', -1);
7338                             parentE = element.parent().parent();
7339                             parentE.eq(0).attr('tabindex', 0);
7340                             parentE[0].focus();
7341                             parentE.eq(0).triggerHandler('click');
7342                         } else {
7343                             if (element.find('a').eq(0).hasClass('active')) {
7344                                 element.triggerHandler('click');
7345                             }
7346                         }
7347                         evt.stopPropagation();
7348                         break;
7349                     case keymap.KEY.UP:
7350                         evt.preventDefault();
7351                         if (!(isRoot(element) && element[0].previousElementSibling === null)) {
7352                             element.attr('tabindex', -1);
7353                             findUp(element);
7354                             upE.eq(0).attr('tabindex', 0);
7355                             upE[0].focus();
7356                         }
7357                         evt.stopPropagation();
7358                         break;
7359                     case keymap.KEY.RIGHT:
7360                         evt.preventDefault();
7361                         if (element.attr("b2b-ml-nav") !== "endNode") {
7362                             if (!element.find('a').eq(0).hasClass('active')) {
7363                                 element.triggerHandler('click');
7364                             }
7365                             element.attr('tabindex', -1);
7366                             findDown(element.find('a').eq(0));
7367                             downE.eq(0).attr('tabindex', 0);
7368                             downE[0].focus();
7369                         }
7370                         evt.stopPropagation();
7371                         break;
7372                     case keymap.KEY.DOWN:
7373                         evt.preventDefault();
7374                         element.attr('tabindex', -1);
7375                         if (!(element.attr("b2b-ml-nav") === "middleNode" && element.find('a').eq(0).hasClass('active')) && (element.next().length === 0)) {
7376                             if(element.parent().parent().attr("b2b-ml-nav") !== "rootNode" && element.parent().parent()[0].nextElementSibling !== null)
7377                             {
7378                                 findDown(element.find('a').eq(0));
7379                                 downE.eq(0).attr('tabindex', 0);
7380                                 downE[0].focus();
7381                                 evt.stopPropagation();
7382                                 break;
7383                             }
7384                             findRoot(element);
7385                             if (!(rootE.next().length === 0)) {
7386                                 rootE.next().eq(0).attr('tabindex', 0);
7387                                 rootE.next()[0].focus();
7388                             } else {
7389                                 rootE.eq(0).attr('tabindex', 0);
7390                                 rootE[0].focus();
7391                             }
7392                             evt.stopPropagation();
7393                             break;
7394                         }
7395                         findDown(element.find('a').eq(0));
7396                         downE.eq(0).attr('tabindex', 0);
7397                         downE[0].focus();
7398                         evt.stopPropagation();
7399                         break;
7400                     default:
7401                         break;
7402                     }
7403                 });
7404             }
7405         };
7406     }]);
7407 /**
7408  * @ngdoc directive
7409  * @name Tabs, tables & accordions.att:multipurposeExpander
7410  *
7411  * @description
7412  *  <file src="src/multipurposeExpander/docs/readme.md" />
7413  *
7414  * @usage
7415  * <!--With Close Other -->
7416  * <b2b-expander-group close-others="true">
7417  *  <b2b-expanders class="mpc-expanders" is-open="testmpc">            
7418  *      <b2b-expander-heading ng-class=" { 'b2b-toggle-header-active': !testmpc, 'b2b-toggle-header-inactive': testmpc } ">Heading content goes here</b2b-expander-heading>               
7419  *      <b2b-expander-body>
7420             <p>body content goes here</p>
7421         </b2b-expander-body>
7422  *  </b2b-expanders>
7423  *  </b2b-expander-group>
7424  *  
7425  * <!-- Without Close Other -->
7426  *  <b2b-expanders class="mpc-expanders" is-open="testmpc2">            
7427  *      <b2b-expander-heading ng-class=" { 'b2b-toggle-header-active': !testmpc2, 'b2b-toggle-header-inactive': testmpc2 } ">Heading content goes here</b2b-expander-heading>               
7428  *      <b2b-expander-body>
7429             <p>body content goes here</p>
7430         </b2b-expander-body>
7431  *  </b2b-expanders>
7432  *  
7433  * @example
7434  *  <section id="code">
7435         <example module="b2b.att.multipurposeExpander">
7436             <file src="src/multipurposeExpander/docs/demo.html" />
7437             <file src="src/multipurposeExpander/docs/demo.js" />
7438         </example>
7439     </section>
7440  *
7441  */
7442
7443 angular.module('b2b.att.multipurposeExpander', ['b2b.att', 'b2b.att.collapse'])
7444 .directive('b2bExpanderGroup', function () {
7445     return {
7446         restrict: 'EA',
7447         transclude: true,
7448         template: "<ng-transclude></ng-transclude>",
7449         controller:['$scope','$attrs', function($scope,$attrs){
7450             this.groups = [];
7451             this.index = -1;            
7452             this.scope = $scope;
7453             
7454             this.addGroup = function (groupScope) {
7455                 var that = this;
7456                 groupScope.index = this.groups.length;
7457                 this.groups.push(groupScope);
7458                 if(this.groups.length > 0){
7459                     this.index = 0;
7460                 }
7461                 groupScope.$on('$destroy', function () {
7462                 that.removeGroup(groupScope);
7463             });
7464             };
7465
7466             this.closeOthers = function (openGroup) {
7467                 var closeOthers = angular.isDefined($attrs.closeOthers);
7468                 if (closeOthers && !$scope.forceExpand) {
7469                     angular.forEach(this.groups, function (group) {
7470                         if (group !== openGroup) {
7471                             group.isOpen = false;
7472                         }
7473                     });
7474                 }
7475                 if (this.groups.indexOf(openGroup) === (this.groups.length - 1) && $scope.forceExpand) {
7476                     $scope.forceExpand = false;
7477                 }
7478             };
7479             this.removeGroup = function (group) {
7480             var index = this.groups.indexOf(group);
7481             if (index !== -1) {
7482                 this.groups.splice(this.groups.indexOf(group), 1);
7483             }
7484         };
7485         }]
7486        
7487     };
7488     
7489 })
7490 .directive('b2bExpanders', function () {
7491     return{
7492         restrict: 'EA',
7493         replace: true,
7494         require:['b2bExpanders','?^b2bExpanderGroup'],
7495         transclude: true,
7496         scope:{isOpen:'=?'},
7497         template: "<div ng-transclude></div>",
7498         controller: ['$scope', function ($scope){
7499                 var bodyScope = null;
7500                 var expanderScope = null;
7501                 this.isOpened = function(){                
7502                     if($scope.isOpen)
7503                     {
7504                         return  true;
7505                     }else
7506                     {
7507                         return false;
7508                     }
7509                 };                
7510                 this.setScope = function (scope) {
7511                     bodyScope = scope; 
7512                     bodyScope.isOpen = $scope.isOpen;                   
7513                 };                
7514                 this.setExpanderScope = function (scope) {
7515                     expanderScope = scope;                                   
7516                 };
7517                 this.toggle = function () {
7518                     $scope.isOpen = bodyScope.isOpen = !bodyScope.isOpen;                    
7519                     return bodyScope.isOpen;
7520                     
7521                 };
7522                 this.watchToggle = function(io){ 
7523                     bodyScope.isOpen = io;
7524                     expanderScope.updateIcons(io);
7525                 };  
7526             }],
7527         link: function (scope, elem, attr, myCtrl)
7528         {
7529             //scope.isOpen = false; 
7530             if(myCtrl[1]){
7531                 myCtrl[1].addGroup(scope);
7532             }
7533             scope.$watch('isOpen', function(val){                               
7534                 myCtrl[0].watchToggle(scope.isOpen);
7535                 if(val && myCtrl[1]){
7536                     myCtrl[1].closeOthers(scope);
7537                 }
7538             });            
7539         }
7540     };
7541 })
7542
7543 .directive('b2bExpanderHeading', function () {
7544     return{
7545         require: "^b2bExpanders",
7546         restrict: 'EA',
7547         replace: true,
7548         transclude: true,
7549         scope: true,
7550         template: "<div style='padding:10px 10px 10px 0 !important' ng-transclude></div>"
7551     };
7552 })
7553
7554 .directive('b2bExpanderBody', function () {
7555     return{
7556         restrict: 'EA',
7557         require: "^b2bExpanders",
7558         replace: true,
7559         transclude: true,
7560         scope: {},
7561         template: "<div b2b-collapse='!isOpen' ><div ng-transclude></div></div>",
7562         link: function (scope, elem, attr, myCtrl) {
7563             scope.isOpen = false;
7564             myCtrl.setScope(scope);
7565         }
7566     };
7567 })
7568
7569 .directive('b2bExpanderToggle', function () {
7570     return{
7571         restrict: 'EA',
7572         require: "^b2bExpanders",
7573         scope: {
7574             expandIcon: '@',
7575             collapseIcon: '@'
7576         },
7577         
7578         link: function (scope, element, attr, myCtrl)
7579         {
7580             myCtrl.setExpanderScope(scope);
7581             var isOpen = myCtrl.isOpened();   
7582
7583             scope.setIcon = function () {
7584                 element.attr("role", "button");
7585
7586                 if (scope.expandIcon && scope.collapseIcon)
7587                 {
7588                     if (isOpen) {
7589                         element.removeClass(scope.expandIcon);
7590                         element.addClass(scope.collapseIcon);
7591
7592                         element.attr("aria-expanded", "true");
7593                     }
7594                     else {
7595                         element.removeClass(scope.collapseIcon);
7596                         element.addClass(scope.expandIcon);
7597
7598                         element.attr("aria-expanded", "false");
7599                     }
7600                 }                                                               
7601             };
7602             
7603             element.bind('click', function (){
7604                 scope.toggleit();
7605             });
7606             scope.updateIcons = function(nStat){
7607                 isOpen = nStat;
7608                 scope.setIcon();                
7609             };
7610             scope.toggleit = function (){
7611                 isOpen = myCtrl.toggle();
7612                 scope.setIcon();
7613                 scope.$apply();
7614             };                    
7615             scope.setIcon();
7616         }
7617     };
7618 });
7619 /**
7620  * @ngdoc directive
7621  * @name Messages, modals & alerts.att:notesMessagesAndErrors
7622  *
7623  * @description
7624  *  <file src="src/notesMessagesAndErrors/docs/readme.md" />
7625  *
7626  * @usage
7627  *  See Demo
7628  *
7629  * @example
7630  *  <section id="code">
7631         <example module="b2b.att">
7632             <file src="src/notesMessagesAndErrors/docs/demo.html" />
7633             <file src="src/notesMessagesAndErrors/docs/demo.js" />
7634        </example>
7635         </section>
7636  *
7637  */
7638 angular.module('b2b.att.notesMessagesAndErrors', []);
7639 /** 
7640  * @ngdoc directive 
7641  * @name Template.att:Notification Card
7642  * 
7643  * @description 
7644  *  <file src="src/notificationCardTemplate/docs/readme.md" /> 
7645  * 
7646  * @example 
7647  *  <section id="code"> 
7648         <b>HTML + AngularJS</b> 
7649         <example module="b2b.att"> 
7650             <file src="src/notificationCardTemplate/docs/demo.html" /> 
7651             <file src="src/notificationCardTemplate/docs/demo.js" /> 
7652        </example> 
7653     </section>    
7654  * 
7655  */
7656 angular.module('b2b.att.notificationCardTemplate', [])
7657   
7658 /** 
7659  * @ngdoc directive 
7660  * @name Template.att:Order Confirmation Template
7661  * 
7662  * @description 
7663  *  <file src="src/orderConfirmationTemplate/docs/readme.md" /> 
7664  * 
7665  * @example 
7666  *  <section id="code"> 
7667         <b>HTML + AngularJS</b> 
7668         <example module="b2b.att"> 
7669             <file src="src/orderConfirmationTemplate/docs/demo.html" /> 
7670             <file src="src/orderConfirmationTemplate/docs/demo.js" /> 
7671        </example> 
7672     </section>    
7673  * 
7674  */
7675 angular.module('b2b.att.orderConfirmationTemplate', []);
7676   
7677 /**
7678  * @ngdoc directive
7679  * @name Navigation.att:pagination
7680  *
7681  * @description
7682  *  <file src="src/pagination/docs/readme.md" />
7683  * @param {int} total-pages - Total # of pages, set in your controller $scope
7684  * @param {int} current-page - Current selected page, set in your controller $scope
7685  * @param {function} click-handler - Handler function on click of page number, defined in your controller $scope
7686  * @param {string} input-id - _UNIQUE ID_ __MUST__ be provided for 508 compliance, set in your HTML as static text
7687  * @param {string} input-class - optional class that can be given to use for the go to page container
7688  *
7689  * @usage
7690  *   <div b2b-pagination="" input-id="goto-page-2" total-pages="totalPages1" current-page="currentPage1" click-handler="customHandler"></div> 
7691  *
7692  * @example
7693  *  <section id="code">
7694         <example module="b2b.att">
7695             <file src="src/pagination/docs/demo.html" />
7696             <file src="src/pagination/docs/demo.js" />
7697        </example>
7698         </section>
7699  *
7700  */
7701 angular.module('b2b.att.pagination', ['b2b.att.utilities', 'ngTouch'])
7702     .directive('b2bPagination', ['b2bUserAgent', 'keymap', '$window', '$timeout', function (b2bUserAgent, keymap, $window, $timeout) {
7703         return {
7704             restrict: 'A',
7705             scope: {
7706                 totalPages: '=',
7707                 currentPage: '=',
7708                 clickHandler: '=?',
7709                 inputId: '=',
7710                 isDroppable: '=?'
7711             },
7712             replace: true,
7713             templateUrl: 'b2bTemplate/pagination/b2b-pagination.html',
7714             link: function (scope, elem, attr) {
7715                 scope.isMobile = b2bUserAgent.isMobile();
7716                 scope.notMobile = b2bUserAgent.notMobile();
7717                 scope.focusedPage;
7718                 scope.meanVal = 3;
7719                 scope.inputClass = attr.inputClass;
7720                 scope.droppableAttribute = scope.isDroppable ? true : false;
7721                 scope.$watch('totalPages', function (value) {
7722                     if (angular.isDefined(value) && value !== null) {
7723                         scope.pages = [];
7724                         if (value < 1) {
7725                             scope.totalPages = 1;
7726                             return;
7727                         }
7728                         if (value <= 10) {
7729                             for (var i = 1; i <= value; i++) {
7730                                 scope.pages.push(i);
7731                             }
7732                         } else if (value > 10) {
7733                             var midVal = Math.ceil(value / 2);
7734                             scope.pages = [midVal - 2, midVal - 1, midVal, midVal + 1, midVal + 2];
7735                         }
7736                         if(scope.currentPage === undefined || scope.currentPage === 1)
7737                         {
7738                             currentPageChanged(1);
7739                         }
7740                     }
7741                 });
7742                 scope.$watch('currentPage', function (value) {
7743                     currentPageChanged(value);
7744                     callbackHandler(value);
7745                 });
7746                 var callbackHandler = function (num) {
7747                     if (angular.isFunction(scope.clickHandler)) {
7748                         scope.clickHandler(num);
7749                     }
7750                 };
7751                 var getBoundary = function(value){
7752                     if ( value < 100 ) {
7753                         return 5;
7754                     } else if ( 100 <= value && value < 1000 ) {
7755                         return 4;
7756                     } else if ( 1000 <= value ) {
7757                         return 3;
7758                     } else {
7759                         return 5; // error
7760                     }
7761                 };
7762                 function currentPageChanged(value) {
7763                     if (angular.isDefined(value) && value !== null) {
7764                         if (!value || value < 1) {
7765                             value = 1;
7766                         }
7767                         if (value > scope.totalPages) {
7768                             value = scope.totalPages;
7769                         }
7770                         if (scope.currentPage !== value) {
7771                             scope.currentPage = value;
7772                             callbackHandler(scope.currentPage);
7773                         }
7774                         if (scope.totalPages > 10) {
7775                             var val = parseInt(value);
7776                             scope.boundary = getBoundary(val);
7777                             if (val <= 6) { // Left (first) section
7778                                 scope.pages = [1, 2, 3, 4, 5, 6, 7];
7779                             } else if ( val <= (scope.totalPages - scope.boundary) ) { // Middle section
7780                                 if ( 7 <= val && val < 9 ) {
7781                                     if(scope.totalPages < 100) {
7782                                         scope.pages = [val - 3, val - 2, val - 1, val, val + 1, val + 2];
7783                                     } else if(scope.totalPages < 1000) {
7784                                         scope.pages = [val - 2, val - 1, val, val + 1, val + 2];
7785                                     } else if(scope.totalPages < 1000) {
7786                                         scope.pages = [val - 2, val - 1, val, val + 1, val + 2];
7787                                     }
7788                                 } else if ( 9 <= val && val < 100 ) {
7789                                     scope.pages = [val - 3, val - 2, val - 1, val, val + 1, val + 2];
7790                                 } else if ( 100 <= val && val < 1000 ) {
7791                                     scope.pages = [val - 2, val - 1, val, val + 1];
7792                                 } else if ( 1000 <= val ) {
7793                                     scope.pages = [val - 1, val, val + 1];
7794                                 }
7795                             } else if ( (scope.totalPages - scope.boundary) < val ) { // Right (last) section
7796                                 if ( val < 100 ) {
7797                                     scope.pages = [scope.totalPages - 5, scope.totalPages - 4, scope.totalPages - 3, scope.totalPages - 2, scope.totalPages - 1, scope.totalPages];
7798                                 } else if ( 100 <= val && val < 1000 ) {
7799                                     scope.pages = [scope.totalPages - 4, scope.totalPages - 3, scope.totalPages - 2, scope.totalPages - 1, scope.totalPages];
7800                                 } else if ( 1000 <= val ) {
7801                                     scope.pages = [scope.totalPages - 3, scope.totalPages - 2, scope.totalPages - 1, scope.totalPages];
7802                                 }
7803                             }
7804                         }
7805                         if (scope.isMobile) {
7806                             var inWidth = $window.innerWidth;
7807                             var viewLimit = 7;
7808                             if (inWidth <= 400) {
7809                                 viewLimit = 7;
7810                             } else if (inWidth > 400 && inWidth < 500) {
7811                                 viewLimit = 9;
7812                             } else if (inWidth >= 500 && inWidth < 600) {
7813                                 viewLimit = 11;
7814                             } else if (inWidth >= 600 && inWidth < 700) {
7815                                 viewLimit = 13;
7816                             } else if (inWidth >= 700 && inWidth < 800) {
7817                                 viewLimit = 15;
7818                             }
7819
7820                             var val = parseInt(value);
7821
7822                             scope.meanVal = Math.floor(viewLimit / 2);
7823                             var lowerLimit = (val - scope.meanVal) < 1 ? 1 : val - scope.meanVal;
7824                             var upperLimit = (lowerLimit + viewLimit - 1) > scope.totalPages ? scope.totalPages : lowerLimit + viewLimit - 1;
7825                             scope.pages = [];
7826                             for (var i = lowerLimit; i <= upperLimit; i++) {
7827                                 scope.pages.push(i);
7828                             }
7829                         }
7830                     }
7831                 }
7832                 scope.gotoKeyClick = function (keyEvent) {
7833                   if (keyEvent.which === keymap.KEY.ENTER) {
7834                     scope.gotoBtnClick()
7835                   }
7836                 }
7837                 scope.gotoBtnClick = function () {
7838                     currentPageChanged(parseInt(scope.gotoPage)); 
7839                     callbackHandler(scope.currentPage);
7840                     var qResult = elem[0].querySelector('button');
7841                     angular.element(qResult).attr('disabled','true');
7842                     $timeout(function(){
7843                         elem[0].querySelector('.b2b-pager__item--active').focus();
7844                     }, 50); 
7845                     scope.gotoPage = null;               
7846                 }
7847                 scope.onfocusIn = function(evt)
7848                 {
7849                     var qResult = elem[0].querySelector('button');
7850                     angular.element(qResult).removeAttr('disabled');
7851                 }
7852                 scope.onfocusOut = function(evt)
7853                 {
7854                     if(evt.target.value === "")
7855                     {
7856                         var qResult = elem[0].querySelector('button');
7857                         angular.element(qResult).attr('disabled','true');
7858                     }                    
7859                 }
7860                 scope.next = function (event) {
7861                     if (event != undefined) {
7862                         event.preventDefault();
7863                     }
7864                     if (scope.currentPage < scope.totalPages) {
7865                         scope.currentPage += 1;
7866                         callbackHandler(scope.currentPage);
7867                     }
7868                 };
7869                 scope.prev = function (event) {
7870                     if (event != undefined) {
7871                         event.preventDefault();
7872                     }
7873                     if (scope.currentPage > 1) {
7874                         scope.currentPage -= 1;
7875                         callbackHandler(scope.currentPage);
7876                     }
7877                 };
7878                 scope.selectPage = function (value, event) {
7879                     event.preventDefault();
7880                     scope.currentPage = value;
7881                     scope.focusedPage = value;
7882                     callbackHandler(scope.currentPage);
7883                 };
7884                 scope.checkSelectedPage = function (value) {
7885                     if (scope.currentPage === value) {
7886                         return true;
7887                     }
7888                     return false;
7889                 };
7890                 scope.isFocused = function (page) {
7891                     return scope.focusedPage === page;
7892                 };
7893             }
7894         };
7895     }]);
7896
7897 /**
7898  * @ngdoc directive
7899  * @name Navigation.att:paneSelector
7900  *
7901  * @description
7902  *  <file src="src/paneSelector/docs/readme.md" />
7903  *
7904  * @usage
7905  *  Please refer demo.html tab in Example section below.
7906  *
7907  * @example
7908     <section id="code">
7909         <b>HTML + AngularJS</b>
7910         <example module="b2b.att">
7911             <file src="src/paneSelector/docs/demo.html" />
7912             <file src="src/paneSelector/docs/demo.js" />
7913         </example>
7914     </section>
7915  */
7916
7917 angular.module('b2b.att.paneSelector', ['b2b.att.tabs', 'b2b.att.utilities'])
7918
7919 .filter('paneSelectorSelectedItemsFilter', [function () {
7920     return function (listOfItemsArray) {
7921
7922         if (!listOfItemsArray) {
7923             listOfItemsArray = [];
7924         }
7925
7926         var returnArray = [];
7927
7928         for (var i = 0; i < listOfItemsArray.length; i++) {
7929             if (listOfItemsArray[i].isSelected) {
7930                 returnArray.push(listOfItemsArray[i]);
7931             }
7932         }
7933
7934         return returnArray;
7935     };
7936 }])
7937
7938 .filter('paneSelectorFetchChildItemsFilter', [function () {
7939     return function (listOfItemsArray) {
7940
7941         if (!listOfItemsArray) {
7942             listOfItemsArray = [];
7943         }
7944
7945         var returnArray = [];
7946
7947         for (var i = 0; i < listOfItemsArray.length; i++) {
7948             for (var j = 0; j < listOfItemsArray[i].childItems.length; j++) {
7949                 returnArray.push(listOfItemsArray[i].childItems[j]);
7950             }
7951         }
7952
7953         return returnArray;
7954     };
7955 }])
7956
7957 .directive('b2bPaneSelector', [function () {
7958     return {
7959         restrict: 'AE',
7960         replace: true,
7961         templateUrl: 'b2bTemplate/paneSelector/paneSelector.html',
7962         transclude: true,
7963         scope: {}
7964     };
7965 }])
7966
7967 .directive('b2bPaneSelectorPane', [ function () {
7968     return {
7969         restrict: 'AE',
7970         replace: true,
7971         templateUrl: 'b2bTemplate/paneSelector/paneSelectorPane.html',
7972         transclude: true,
7973         scope: {}
7974     };
7975 }])
7976
7977 .directive('b2bTabVertical', ['$timeout', 'keymap', function ($timeout, keymap) {
7978     return {
7979         restrict: 'A',
7980         require: '^b2bTab',
7981         link: function (scope, element, attr, b2bTabCtrl) {
7982
7983             if (!b2bTabCtrl) {
7984                 return;
7985             }
7986
7987             // retreive the isolateScope
7988             var iScope = angular.element(element).isolateScope();
7989
7990             $timeout(function () {
7991                 angular.element(element[0].querySelector('a')).unbind('keydown');
7992                 angular.element(element[0].querySelector('a')).bind('keydown', function (evt) {
7993
7994                     if (!(evt.keyCode)) {
7995                         evt.keyCode = evt.which;
7996                     }
7997
7998                     switch (evt.keyCode) {
7999                         case keymap.KEY.DOWN:
8000                             evt.preventDefault();
8001                             iScope.nextKey();
8002                             break;
8003
8004                         case keymap.KEY.UP:
8005                             evt.preventDefault();
8006                             iScope.previousKey();
8007                             break;
8008
8009                         default:;
8010                     }
8011                 });
8012             });
8013         }
8014     };
8015 }]);
8016 /**
8017  * @ngdoc directive
8018  * @name Forms.att:phoneNumberInput
8019  *
8020  * @description
8021  *  <file src="src/phoneNumberInput/docs/readme.md" />
8022  *
8023  * @usage
8024 <form name="userForm1">
8025     <div class="form-row" ng-class="{'error':!userForm1.text.$valid && userForm1.text.$dirty}">
8026         <label>Phone Mask<span style="color:red">*</span>: (npa) nxx-line &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Model Value: {{mask.text}}</label>
8027         <div>
8028             <input b2b-phone-mask="phoneMask" name="text" ng-model="mask.text" type="text" placeholder="e.g. (123) 456-7890" title="Phone Number" class="b2b-phone-mask-input" required />
8029             <div ng-messages="userForm1.text.$error" class="error-msg" aria-live="polite" aria-atomic="true">
8030                 <span ng-message="required" role="alert">This field is mandatory!</span>
8031                 <span ng-message="invalidPhoneNumber" role="alert">Please enter valid phone number!</span>
8032                 <span ng-message="mask" role="alert">Please enter valid phone number!</span>
8033             </div>
8034         </div>
8035     </div>
8036 </form>
8037  *
8038  * @example
8039  *  <section id="code">
8040         <example module="b2b.att">
8041             <file src="src/phoneNumberInput/docs/demo.html" />
8042             <file src="src/phoneNumberInput/docs/demo.js" />
8043        </example>
8044     </section>
8045  *
8046  */
8047 angular.module('b2b.att.phoneNumberInput', ['ngMessages', 'b2b.att.utilities'])
8048     .constant("CoreFormsUiConfig", {
8049         phoneMask: '(___) ___-____',
8050         phoneMaskDot: '___.___.____',
8051         phoneMaskHyphen: '___-___-____'
8052     })
8053     .directive('b2bPhoneMask', ['$parse', 'CoreFormsUiConfig', 'keymap', 'b2bUserAgent', function ($parse, CoreFormsUiConfig, keymap, b2bUserAgent) {
8054         return {
8055             require: 'ngModel',
8056             scope: {
8057                 ngModel: '='
8058             },
8059             link: function (scope, iElement, iAttrs, ctrl) {
8060                 
8061                 var mask = '';
8062                 var validPhoneNumber = false;
8063                 var currentKey = '';
8064                 if (b2bUserAgent.isMobile()) {
8065                     mask = "__________";
8066                 } else {
8067                     switch (iAttrs.b2bPhoneMask) {
8068                     case "phoneMask":
8069                         mask = CoreFormsUiConfig.phoneMask;
8070                         break;
8071                     case "phoneMaskDot":
8072                         mask = CoreFormsUiConfig.phoneMaskDot;
8073                         break;
8074                     case "phoneMaskHyphen":
8075                         mask = CoreFormsUiConfig.phoneMaskHyphen;
8076                         break;
8077                     default:
8078                         mask = CoreFormsUiConfig.phoneMask;
8079                     }
8080                 }
8081                 iElement.attr("maxlength", mask.length);
8082                 var checkValidity = function (unmaskedValue, rawValue) {
8083                     var valid = false;
8084                     if (angular.isUndefined(rawValue) || rawValue === '') {
8085                         valid = true;
8086                     } else if (unmaskedValue) {
8087                         valid = (unmaskedValue.length === 10);
8088                     }
8089                     ctrl.$setValidity('invalidPhoneNumber', validPhoneNumber);
8090                     ctrl.$setValidity('mask', valid);
8091                     return valid;
8092                 };
8093                 var handleKeyup = function (evt) {
8094
8095                     if (evt && evt.keyCode === keymap.KEY.SHIFT) {
8096                         return;
8097                     }
8098
8099                     var index, formattedNumber;
8100                     if (ctrl.$modelValue) {
8101                         formattedNumber = ctrl.$modelValue;
8102                     } else {
8103                         formattedNumber = iElement.val();
8104                     }
8105                     if (!formattedNumber.length && currentKey === '') {
8106                         return;
8107                     }
8108                     var maskLength, inputNumbers, maskArray, tempArray, maskArrayLength;
8109                     tempArray = [];
8110                     maskArray = mask.split("");
8111                     maskArrayLength = maskArray.length;
8112                     maskLength = formattedNumber.substring(0, mask.length);
8113                     inputNumbers = formattedNumber.replace(/[^0-9]/g, "").split("");
8114                     for (index = 0; index < maskArrayLength; index++) {
8115                         tempArray.push(maskArray[index] === "_" ? inputNumbers.shift() : maskArray[index]);
8116                         if (inputNumbers.length === 0) {
8117                             break;
8118                         }
8119                     }
8120                     formattedNumber = tempArray.join("");
8121                     if (formattedNumber === '(') {
8122                         formattedNumber = '';
8123                     }
8124
8125                     if ( (angular.isDefined(evt) && evt.which) && currentKey !== '') {
8126                         if (maskArray[0] === currentKey && formattedNumber === '') {
8127                             formattedNumber = '(';
8128                         } else if (evt.which === keymap.KEY.SPACE && currentKey === ' ') {
8129                             formattedNumber = formattedNumber + ') ';
8130                         } else if (maskArray[0] === currentKey && formattedNumber === '') {
8131                             formattedNumber = formattedNumber + currentKey;
8132                         } else if (maskArray[formattedNumber.length] === currentKey) {
8133                             formattedNumber = formattedNumber + currentKey;
8134                         }
8135                         currentKey = '';
8136                     }
8137
8138                     ctrl.$setViewValue(formattedNumber);
8139                     ctrl.$render();
8140                     return formattedNumber;
8141                 };
8142
8143
8144                 // since we are only allowing 0-9, why even let the keypress go forward?
8145                 // also added in delete... in case they want to delete :)
8146                 var handlePress = function (e) {
8147                     if (e.which) {
8148                         if ((e.which < 48 || e.which > 57) && (e.which < 96 || e.which > 105)) {
8149                             if (e.which !== keymap.KEY.BACKSPACE && e.which !== keymap.KEY.TAB && e.which !== keymap.KEY.DELETE && e.which !== keymap.KEY.ENTER && e.which !== keymap.KEY.LEFT && e.which !== keymap.KEY.RIGHT &&
8150                                 // Allow: Ctrl+V/v
8151                                 (!(e.ctrlKey) && (e.which !== '118' || e.which !== '86')) &&
8152                                 // Allow: Ctrl+C/c
8153                                 (!(e.ctrlKey) && (e.which !== '99' || e.which !== '67')) &&
8154                                 // Allow: Ctrl+X/x
8155                                 (!(e.ctrlKey) && (e.which !== '120' || e.which !== '88')) &&
8156                                 /* 229 key code will sent as placeholder key for andriod devices */
8157                                 (e.which != 229 )) {
8158                                 e.preventDefault ? e.preventDefault() : e.returnValue = false;
8159                                 validPhoneNumber = false;
8160                             }
8161                         } else {
8162                             validPhoneNumber = true;
8163                         }
8164
8165                         setCurrentKey(e);
8166                     }
8167                     scope.$apply();
8168                 };
8169                 // i moved this out because i thought i might need focus as well..
8170                 // to handle setting the model as the view changes
8171                 var parser = function (fromViewValue) {
8172                     var letters = /^[A-Za-z]+$/;
8173                     var numbers = /^[0-9]+$/;
8174                     if (angular.isUndefined(fromViewValue) || fromViewValue === '') {
8175                         validPhoneNumber = true;
8176                     } else {
8177                         if (fromViewValue.match(letters)) {
8178                             validPhoneNumber = false;
8179                         }
8180                         if (fromViewValue.match(numbers)) {
8181                             validPhoneNumber = true;
8182                         }
8183                     }
8184                     var clean = "";
8185                     if (fromViewValue && fromViewValue.length > 0) {
8186                         clean = fromViewValue.replace(/[^0-9]/g, '');
8187                     }
8188                     checkValidity(clean, fromViewValue);
8189                     return clean;
8190                 };
8191
8192                 //to handle reading the model and formatting it
8193                 var formatter = function (fromModelView) {
8194                     var input = '';
8195                     checkValidity(fromModelView);
8196                     if (fromModelView) {
8197                         input = handleKeyup();
8198                     }
8199                     return input;
8200                 };
8201
8202                 var setCurrentKey = function (e) {
8203                     switch (e.which) {
8204                     case 189:
8205                     case 109:
8206                         currentKey = '-';
8207                         break;
8208                     case 190:
8209                     case 110:
8210                         currentKey = '.';
8211                         break;
8212                     case 57:
8213                         if (e.shiftKey === true) {
8214                             currentKey = '(';
8215                         }
8216                         break;
8217                     case 48:
8218                         if (e.shiftKey === true) {
8219                             currentKey = ')';
8220                         }
8221                         break;
8222                     case 32:
8223                         currentKey = ' ';
8224                         break;
8225                     }
8226                 };
8227
8228                 if (angular.isDefined(scope.ngModel)) {
8229                     parser(scope.ngModel);
8230                 }
8231
8232                 ctrl.$parsers.push(parser);
8233                 ctrl.$formatters.push(formatter);
8234                 iElement.bind('keyup', handleKeyup);
8235                 iElement.bind('keydown', handlePress);
8236             }
8237         };
8238 }]);
8239 /** 
8240  * @ngdoc directive 
8241  * @name Template.att:Profile Blocks 
8242  * 
8243  * @description 
8244  *  <file src="src/profileBlockTemplate/docs/readme.md" /> 
8245  * @example 
8246  *  <section id="code">  
8247         <example module="b2b.att"> 
8248             <file src="src/profileBlockTemplate/docs/demo.html" /> 
8249             <file src="src/profileBlockTemplate/docs/demo.js" /> 
8250        </example>  
8251     </section>  
8252  *  
8253  */   
8254
8255 angular.module('b2b.att.profileBlockTemplate', [])
8256     
8257      
8258   
8259 /**
8260  * @ngdoc directive
8261  * @name Layouts.att:profileCard
8262  *
8263  * @description
8264  *  <file src="src/profileCard/docs/readme.md" />
8265  *
8266  * @usage
8267  *  <b2b-profile-card></b2b-profile-card>
8268  *
8269  * @example
8270     <section id="code">   
8271         <example module="b2b.att">
8272             <file src="src/profileCard/docs/demo.html" />
8273             <file src="src/profileCard/docs/demo.js" />
8274         </example>
8275     </section>
8276  */
8277
8278 angular.module('b2b.att.profileCard', ['b2b.att'])
8279 .constant('profileStatus',{
8280     status: {
8281         ACTIVE: {
8282             status: "Active",
8283             color: "green"
8284         },
8285         DEACTIVATED: {
8286             status: "Deactivated",
8287             color: "red"
8288         },
8289         LOCKED: {
8290             status: "Locked",
8291             color: "red"
8292         },
8293         IDLE: {
8294             status: "Idle",
8295             color: "yellow"
8296         },
8297         PENDING: {
8298             status: "Pending",
8299             color: "blue"
8300         }
8301     },
8302     role: "COMPANY ADMINISTRATOR"
8303
8304 })
8305 .directive('b2bProfileCard',['$http','$q','profileStatus', function($http,$q,profileStatus) {
8306    return {
8307         restrict: 'EA',
8308         replace: 'true',
8309         templateUrl: function(element, attrs){
8310             if(!attrs.addUser){
8311                 return 'b2bTemplate/profileCard/profileCard.html';
8312             }
8313             else{
8314                 return 'b2bTemplate/profileCard/profileCard-addUser.html';
8315             }
8316         },
8317         scope: {
8318             profile:'=',
8319             characterLimit: '@'
8320         },
8321         link: function(scope, elem, attr){
8322                 scope.characterLimit = parseInt(attr.characterLimit, 10) || 25;
8323                 scope.shouldClip = function(str) {
8324                         return str.length > scope.characterLimit;
8325                 };
8326
8327                 scope.showEmailTooltip = false;
8328
8329             scope.image=true;
8330             function isImage(src) {
8331                 var deferred = $q.defer();
8332                 var image = new Image();
8333                 image.onerror = function() {
8334                     deferred.reject(false);
8335                 };
8336                 image.onload = function() {
8337                     deferred.resolve(true);
8338                 };
8339                 if(src !== undefined && src.length>0 ){
8340                     image.src = src;
8341                 } else {
8342                      deferred.reject(false);
8343                 }
8344                 return deferred.promise;
8345             }
8346             if(!attr.addUser){
8347             scope.image=false;
8348             isImage(scope.profile.img).then(function(img) {
8349                 scope.image=img;
8350             });
8351             var splitName=(scope.profile.name).split(' ');
8352             scope.initials='';
8353             for(var i=0;i<splitName.length;i++){
8354                 scope.initials += splitName[i][0];
8355             }
8356             if(scope.profile.role.toUpperCase() === profileStatus.role){
8357                 scope.badge=true;
8358             }
8359             var profileState=profileStatus.status[scope.profile.state.toUpperCase()];
8360             if(profileState) {
8361                 scope.profile.state=profileStatus.status[scope.profile.state.toUpperCase()].status;
8362                 scope.colorIcon=profileStatus.status[scope.profile.state.toUpperCase()].color;
8363                 if(scope.profile.state.toUpperCase()===profileStatus.status.PENDING.status.toUpperCase()||scope.profile.state.toUpperCase()===profileStatus.status.LOCKED.status.toUpperCase()){
8364                         scope.profile.lastLogin=scope.profile.state;
8365                 }
8366             }
8367             var today=new Date().getTime();
8368             var lastlogin=new Date(scope.profile.lastLogin).getTime();
8369             var diff=(today-lastlogin)/(1000*60*60*24);
8370             if(diff<=1){
8371                 scope.profile.lastLogin="Today";
8372             }
8373             else if(diff<=2){
8374                 scope.profile.lastLogin="Yesterday";
8375             }
8376         }
8377     }
8378 };
8379 }]);
8380 /**
8381  * @ngdoc directive
8382  * @name Forms.att:radios
8383  *
8384  * @description
8385  *  <file src="src/radios/docs/readme.md" />
8386  *
8387  * @usage
8388  *  See demo section
8389  *
8390  * @param {boolean} refreshRadioGroup - A trigger that recalculates and updates the accessibility roles on radios in a group.
8391  * 
8392  * @example
8393     <section id="code">
8394                <b>HTML + AngularJS</b>
8395                <example module="b2b.att">
8396                 <file src="src/radios/docs/demo.html" />
8397                 <file src="src/radios/docs/demo.js" />
8398                </example>
8399             </section>
8400  */
8401 angular.module('b2b.att.radios', ['b2b.att.utilities'])
8402 .directive('b2bRadioGroupAccessibility', ['$timeout', 'b2bUserAgent', function($timeout, b2bUserAgent) {
8403     return {
8404         restrict: "A",
8405         scope: {
8406             refreshRadioGroup: "=",
8407         },
8408         link: function(scope, ele, attr) {
8409
8410             var roleRadioElement, radioProductSelectElement, radioInputTypeElement;
8411
8412             $timeout(calculateNumberOfRadio);
8413
8414             scope.$watch('refreshRadioGroup', function(value) {
8415                 if (value === true) {
8416                     addingRoleAttribute();
8417                     $timeout(calculateNumberOfRadio);
8418                     scope.refreshRadioGroup = false;
8419                 } else {
8420                     return;
8421                 }
8422             })
8423
8424
8425             function calculateNumberOfRadio() {
8426                 roleRadioElement = ele[0].querySelectorAll('[role="radio"]');
8427
8428                 radioProductSelectElement = ele[0].querySelectorAll('[role="radiogroup"] li.radio-box');
8429
8430                 radioInputTypeElement = ele[0].querySelectorAll('input[type="radio"]');
8431
8432                 for (var i = 0; i < radioInputTypeElement.length; i++) {
8433                     var isChecked = radioInputTypeElement[i].checked ? 'true' : 'false';
8434                     var isDisabled = radioInputTypeElement[i].disabled ? 'true' : 'false';
8435                     var numOfx = i + 1 + ' of ' + radioInputTypeElement.length;
8436                     angular.element(roleRadioElement[i]).attr({
8437                         'aria-checked': isChecked,
8438                         'aria-disabled': isDisabled,
8439                         'data-opNum': numOfx
8440                     });
8441                     if (b2bUserAgent.notMobile()) {
8442                         angular.element(roleRadioElement[i]).removeAttr("role");
8443                     }
8444
8445                     if (radioProductSelectElement.length) {
8446                         isChecked === 'true' ? angular.element(radioProductSelectElement[i]).addClass('active') : angular.element(radioProductSelectElement[i]).removeClass('active');
8447                     }
8448
8449                     if (/Android/i.test(navigator.userAgent)) {
8450                         angular.element(roleRadioElement[i]).append('<span class="hidden-spoken">. ' + numOfx + '.</span>');
8451                     }
8452
8453
8454                     angular.element(radioInputTypeElement[i]).bind('click', radioStateChangeonClick);
8455
8456                 }
8457             }
8458
8459             function addingRoleAttribute() {
8460                 for (var i = 0; i < radioInputTypeElement.length; i++) {
8461                     if (b2bUserAgent.notMobile()) {
8462                         angular.element(roleRadioElement[i]).attr("role", "radio");
8463                     }
8464                 }
8465             }
8466
8467             function radioStateChangeonClick() {
8468                 for (var i = 0; i < radioInputTypeElement.length; i++) {
8469                     var isChecked = radioInputTypeElement[i].checked ? 'true' : 'false';
8470                     var isDisabled = radioInputTypeElement[i].disabled ? 'true' : 'false';
8471                     if (radioProductSelectElement.length) {
8472                         isChecked === 'true' ? angular.element(radioProductSelectElement[i]).addClass('active') : angular.element(radioProductSelectElement[i]).removeClass('active');
8473                     }
8474                     angular.element(roleRadioElement[i]).attr({
8475                         'aria-checked': isChecked,
8476                         'aria-disabled': isDisabled
8477                     });
8478                 }
8479
8480             }
8481         }
8482     }
8483
8484 }]);
8485
8486 /**
8487  * @ngdoc directive
8488  * @name Forms.att:searchField
8489  *
8490  * @description
8491  *  <file src="src/searchField/docs/readme.md" />
8492  *
8493  * @usage
8494  *  <div b2b-search-field dropdown-list="listdata" on-click-callback="clickFn(value)" class="span12" input-model='typedString' config-obj='keyConfigObj'></div>
8495  *
8496  * @example
8497  <section id="code">
8498     <example module="b2b.att">
8499     <file src="src/searchField/docs/demo.html" />
8500     <file src="src/searchField/docs/demo.js" />
8501     </example>
8502 </section>
8503  */
8504
8505 angular.module('b2b.att.searchField', ['b2b.att.utilities', 'b2b.att.position'])
8506     .filter('b2bFilterInput', [function() {
8507         return function(list, str, keyArray, displayListKey, isContainsSearch, searchSeperator) {
8508             var res = [];
8509             var searchLabel;
8510             var searchCondition;
8511             var conditionCheck = function(searchSeperator, listItem, displayListKey, splitString) {
8512                 var displayTitle = null;
8513                 if (splitString) {
8514                     for (var i = 0; i < displayListKey.length; i++) {
8515                         if (i <= 0) {
8516                             displayTitle = listItem[displayListKey[i]].toLowerCase().indexOf(splitString[i].toLowerCase()) > -1;
8517                         } else {
8518                             displayTitle = (splitString[i]) ? displayTitle && listItem[displayListKey[i]].toLowerCase().indexOf(splitString[i].toLowerCase().trim()) > -1 : displayTitle;
8519                         }
8520                     }
8521                 } else {
8522                     angular.forEach(displayListKey, function(value) {
8523                         if (!displayTitle) {
8524                             displayTitle = listItem[value];
8525                         } else {
8526                             displayTitle = displayTitle + (listItem[value] ? searchSeperator + ' ' + listItem[value] : '');
8527                         }
8528                     });
8529                 }
8530                 return displayTitle;
8531             }
8532             angular.forEach(list, function(listItem) {
8533                 var splitString = str.indexOf(searchSeperator) > -1 ? str.split(searchSeperator) : false;
8534                 var displayList = conditionCheck(searchSeperator, listItem, displayListKey, splitString)
8535                 for (var i = 0; i < keyArray.length; i++) {
8536                     searchLabel = keyArray[i];
8537                     if (listItem[searchLabel]) {
8538                         if (isContainsSearch) {
8539                             var displaySearchList = listItem[searchLabel].toLowerCase().indexOf(str.toLowerCase()) > -1;
8540                             if (splitString.length > 1) {
8541                                 displaySearchList = (splitString.length <= keyArray.length) ? displayList : false;
8542                             }
8543                             searchCondition = displaySearchList;
8544                         } else {
8545                             searchCondition = listItem[searchLabel].match(new RegExp('^' + str, 'gi'));
8546                         }
8547                         if (searchCondition) {
8548                             res.push({
8549                                 'title': conditionCheck(searchSeperator, listItem, displayListKey),
8550                                 'valueObj': listItem
8551                             });
8552                             break;
8553                         }
8554                     }
8555                 }
8556             });
8557             return res;
8558         };
8559     }]).directive('b2bSearchField', ['$filter', 'b2bFilterInputFilter', 'keymap', '$documentBind', '$isElement', '$document', 'events', '$timeout', function($filter, b2bFilterInput, keymap, $documentBind, $isElement, $document, events, $timeout) {
8560         return {
8561             restrict: 'A',
8562             scope: {
8563                 dataList: '=dropdownList',
8564                 onClickCallback: '&',
8565                 inputModel: '=',
8566                 configObj: '=',
8567                 objModel: '=',
8568                 inputDeny: '=?',
8569                 disabled: '=?'
8570             },
8571             replace: true,
8572             templateUrl: 'b2bTemplate/searchField/searchField.html',
8573             controller: ['$scope', function($scope) {
8574                 this.searchKeyArray = [];
8575                 if ($scope.configObj.searchKeys) {
8576                     this.searchKeyArray = $scope.configObj.searchKeys;
8577                 }
8578                 if (angular.isUndefined($scope.disabled)) {
8579                     $scope.disabled = false;
8580                 }
8581                 this.triggerInput = function(searchString) {
8582                     $scope.originalInputModel = searchString;
8583                     if (searchString === '') {
8584                         $scope.currentIndex = -1;
8585                         $scope.filterList = [];
8586                         $scope.showListFlag = false;
8587                     } else if (searchString !== '' && !$scope.isFilterEnabled) {
8588                         $scope.filterList = $filter('b2bFilterInput')($scope.dataList, searchString, this.searchKeyArray, $scope.configObj.displayListDataKey, $scope.configObj.isContainsSearch, $scope.configObj.searchSeperator);
8589                         $scope.showListFlag = true;
8590                     }
8591                 };
8592                 this.denyRegex = function() {
8593                     return $scope.inputDeny;
8594                 };
8595             }],
8596             link: function(scope, elem) {
8597                 scope.isFilterEnabled = false;
8598                 scope.showListFlag = false;
8599                 scope.currentIndex = -1;
8600                 scope.setCurrentIdx = function(idx) {
8601                     scope.currentIndex = idx;
8602                     if (idx > -1) {
8603                         scope.inputModel = scope.filterList[idx].title;
8604                         scope.objModel = scope.filterList[idx];
8605                     }
8606                 };
8607                 scope.isActive = function(index, dropdownLength) {
8608                     scope.dropdownLength = dropdownLength;
8609                     return scope.currentIndex === index;
8610                 };
8611                 scope.selectItem = function(idx) {
8612                     scope.setCurrentIdx(idx);
8613                     scope.onClickCallback({
8614                         value: scope.inputModel,
8615                         objValue: scope.objModel
8616                     });
8617                     scope.showListFlag = false;
8618                     $timeout(function() {
8619                         elem.find('div').find('input')[0].focus();
8620                     }, 150);
8621                 };
8622                 scope.startSearch = function() {
8623                     scope.onClickCallback({
8624                         value: scope.inputModel,
8625                         objValue: scope.objModel
8626                     });
8627                 };
8628                 scope.selectPrev = function() {
8629                     if (scope.currentIndex > 0 && scope.filterList.length > 0) {
8630                         scope.currentIndex = scope.currentIndex - 1;
8631                         scope.setCurrentIdx(scope.currentIndex);
8632                     } else if (scope.currentIndex === 0) {
8633                         scope.currentIndex = scope.currentIndex - 1;
8634                         scope.inputModel = scope.originalInputModel;
8635                         scope.isFilterEnabled = true;
8636                     }
8637                 };
8638                 scope.selectNext = function() {
8639                     if (scope.currentIndex < scope.configObj.noOfItemsDisplay - 1) {
8640                         if (scope.currentIndex < scope.filterList.length - 1) {
8641                             scope.currentIndex = scope.currentIndex + 1;
8642                             scope.setCurrentIdx(scope.currentIndex);
8643                         }
8644                     }
8645                 };
8646                 scope.selectCurrent = function() {
8647                     scope.selectItem(scope.currentIndex);
8648                 };
8649                 scope.selectionIndex = function(e) {
8650                     switch (e.keyCode) {
8651                         case keymap.KEY.DOWN:
8652                             events.preventDefault(e);
8653                             scope.isFilterEnabled = true;
8654                             scope.selectNext();
8655                             break;
8656                         case keymap.KEY.UP:
8657                             events.preventDefault(e);
8658                             scope.isFilterEnabled = true;
8659                             scope.selectPrev();
8660                             break;
8661                         case keymap.KEY.ENTER:
8662                             events.preventDefault(e);
8663                             scope.isFilterEnabled = true;
8664                             scope.selectCurrent();
8665                             break;
8666                         case keymap.KEY.ESC:
8667                             events.preventDefault(e);
8668                             scope.isFilterEnabled = false;
8669                             scope.showListFlag = false;
8670                             scope.inputModel = '';
8671                             break;
8672                         default:
8673                             scope.isFilterEnabled = false;
8674                             break;
8675                     }
8676                     if (elem[0].querySelector('.filtercontainer')) {
8677                         elem[0].querySelector('.filtercontainer').scrollTop = (scope.currentIndex - 1) * 35;
8678                     }
8679                 };
8680                 scope.$watch('filterList', function(newVal, oldVal) {
8681                     if (newVal !== oldVal) {
8682                         scope.currentIndex = -1;
8683                     }
8684                 });
8685                 scope.blurInput = function() {
8686                     $timeout(function() {
8687                         scope.showListFlag = false;
8688                     }, 150);
8689                 };
8690                 var outsideClick = function(e) {
8691                     var isElement = $isElement(angular.element(e.target), elem.find('ul').eq(0), $document);
8692                     if (!isElement && document.activeElement.tagName.toLowerCase() !== 'input') {
8693                         scope.showListFlag = false;
8694                         scope.$apply();
8695                     }
8696                 };
8697                 $documentBind.click('showListFlag', outsideClick, scope);
8698             }
8699         };
8700     }])
8701     .directive('b2bSearchInput', [function() {
8702         return {
8703             restrict: 'A',
8704             require: ['ngModel', '^b2bSearchField'],
8705             link: function(scope, elem, attr, ctrl) {
8706                 var ngModelCtrl = ctrl[0];
8707                 var attSearchBarCtrl = ctrl[1];
8708                 var REGEX = ctrl[1].denyRegex();
8709                 var parser = function(viewValue) {
8710                     attSearchBarCtrl.triggerInput(viewValue);
8711                     return viewValue;
8712                 };
8713                 ngModelCtrl.$parsers.push(parser);
8714
8715                 if (REGEX !== undefined || REGEX !== '') {
8716                     elem.bind('input', function() {
8717                         var inputString = ngModelCtrl.$viewValue && ngModelCtrl.$viewValue.replace(REGEX, '');
8718                         if (inputString !== ngModelCtrl.$viewValue) {
8719                             ngModelCtrl.$setViewValue(inputString);
8720                             ngModelCtrl.$render();
8721                             scope.$apply();
8722                         }
8723                     });
8724                 }
8725             }
8726         };
8727     }]);
8728
8729 /**
8730  * @ngdoc directive
8731  * @name Buttons, links & UI controls.att:Seek bar
8732  *
8733  * @description
8734  *  <file src="src/seekBar/docs/readme.md" />
8735  *
8736  * @usage
8737  *  Horizontal Seek Bar
8738  *      <b2b-seek-bar min="0" max="400" step="1" skip-interval="1" data-ng-model="horizontalSeekBarVal" style="width:180px; margin: auto;" on-drag-end="onDragEnd()" on-drag-init="onDragStart()"></b2b-seek-bar>
8739
8740  *      Vertical Seek Bar
8741  *      <b2b-seek-bar min="0" max="1" step="0.01" skip-interval="0.1" vertical data-ng-model="verticalSeekBarVal" style=" width: 6px; height: 180px; margin: auto;"></b2b-seek-bar>
8742  *
8743  * @example
8744     <section id="code">   
8745         <b>HTML + AngularJS</b>
8746         <example module="b2b.att">
8747             <file src="src/seekBar/docs/demo.html" />
8748             <file src="src/seekBar/docs/demo.js" />
8749         </example>
8750     </section>
8751  */
8752
8753 angular.module('b2b.att.seekBar', ['b2b.att.utilities','b2b.att.position'])
8754         .constant('b2bSeekBarConfig', {
8755             'min': 0,
8756             'max': 100,
8757             'step': 1,
8758             'skipInterval': 1
8759         })
8760         .directive('b2bSeekBar', ['$documentBind', 'events', 'b2bSeekBarConfig', 'keymap', '$compile', function($documentBind, events, b2bSeekBarConfig, keymap, $compile) {
8761                 return {
8762                     restrict: 'AE',
8763                     replace: true,
8764                     require: 'ngModel',
8765                     templateUrl: 'b2bTemplate/seekBar/seekBar.html',
8766                     scope: {
8767                         onDragEnd: '&?',
8768                         onDragInit: '&?'
8769                     },
8770                     link: function(scope, elm, attr, ngModelCtrl) {
8771                         scope.isDragging = false;
8772                         scope.verticalSeekBar = false;
8773                         var min;
8774                         var max;
8775                         var step = b2bSeekBarConfig.step;
8776                         var skipInterval = b2bSeekBarConfig.skipInterval;
8777                         var knob = angular.element(elm[0].querySelector('.b2b-seek-bar-knob-container'));
8778                         var seekBarKnob = angular.element(knob[0].querySelector('.b2b-seek-bar-knob'));
8779                         var trackContainer = angular.element(elm[0].querySelector('.b2b-seek-bar-track-container'));
8780                         var trackFill = angular.element(elm[0].querySelector('.b2b-seek-bar-track-fill'));
8781                         var trackContainerRect = {};
8782                         var axisPosition;
8783                         var trackFillOrderPositioning;
8784
8785                         if (angular.isDefined(attr.vertical)) {
8786                             scope.verticalSeekBar = true;
8787                             axisPosition = "clientY";
8788                         }
8789                         else {
8790                             scope.verticalSeekBar = false;
8791                             axisPosition = "clientX";
8792                         }
8793                         var getValidStep = function(val) {
8794                             val = parseFloat(val);
8795                             // in case $modelValue came in string number
8796                             if (angular.isNumber(val)) {
8797                                 val = Math.round((val - min) / step) * step + min;
8798                                 return Math.round(val * 1000) / 1000;
8799                             }
8800                         };
8801
8802                         var getPositionToPercent = function(x) {
8803                             if (scope.verticalSeekBar) {
8804                                 return Math.max(0, Math.min(1, (trackContainerRect.bottom - x) / (trackFillOrderPositioning)));
8805                             }
8806                             else {
8807                                 return Math.max(0, Math.min(1, (x - trackContainerRect.left) / (trackFillOrderPositioning)));
8808                             }
8809                         };
8810
8811                         var getPercentToValue = function(percent) {
8812                             return (min + percent * (max - min));
8813                         };
8814
8815                         var getValueToPercent = function(val) {
8816                             return (val - min) / (max - min);
8817                         };
8818
8819                         var getValidMinMax = function(val) {
8820                             return Math.max(min, Math.min(max, val));
8821                         };
8822
8823                         var updateTrackContainerRect = function() {
8824                             trackContainerRect = trackContainer[0].getBoundingClientRect();
8825                             if (scope.verticalSeekBar) {
8826                                 if (!trackContainerRect.height) {
8827                                     trackFillOrderPositioning = trackContainer[0].scrollHeight;
8828                                 } else {
8829                                     trackFillOrderPositioning = trackContainerRect.height;
8830                                 }
8831                             }
8832                             else {
8833                                 if (!trackContainerRect.width) {
8834                                     trackFillOrderPositioning = trackContainer[0].scrollWidth;
8835                                 } else {
8836                                     trackFillOrderPositioning = trackContainerRect.width;
8837                                 }
8838
8839                             }
8840
8841                         };
8842
8843                         var updateKnobPosition = function(percent) {
8844                             var percentStr = (percent * 100) + '%';
8845                             if (scope.verticalSeekBar) {
8846                                 knob.css('bottom', percentStr);
8847                                 trackFill.css('height', percentStr);
8848                             }
8849                             else {
8850                                 knob.css('left', percentStr);
8851                                 trackFill.css('width', percentStr);
8852                             }
8853                         };
8854
8855                         var modelRenderer = function() {
8856                             if (isNaN(ngModelCtrl.$viewValue)) {
8857                                 ngModelCtrl.$viewValue = ngModelCtrl.$modelValue || min;
8858                             }
8859
8860                             var viewVal = ngModelCtrl.$viewValue;
8861                             scope.currentModelValue = viewVal;
8862
8863                             //wait for min, max and step to be set then only update UI to avoid NaN on percent calculation
8864                             if ((min || min === 0) && max && step) {
8865                                 updateKnobPosition(getValueToPercent(viewVal));
8866                             }
8867                         };
8868
8869                         var setModelValue = function(val) {
8870                             scope.currentModelValue = getValidMinMax(getValidStep(val));
8871                             ngModelCtrl.$setViewValue(scope.currentModelValue);
8872                         };
8873
8874                         var updateMin = function(val) {
8875                             min = parseFloat(val);
8876                             if(isNaN(min)){
8877                                min = b2bSeekBarConfig.min; 
8878                             }
8879                             modelRenderer();
8880                         };
8881
8882                         var updateMax = function(val) {
8883                             max = parseFloat(val);
8884                             if(isNaN(max)){
8885                                max = b2bSeekBarConfig.max; 
8886                             }
8887                             modelRenderer();
8888                         };
8889
8890                         var updateStep = function(val) {
8891                             step = parseFloat(val);
8892                             if (!attr['skipInterval']) {
8893                                 skipInterval = step;
8894                             }
8895                         };
8896
8897                         var updateSkipInterval = function(val) {
8898                             skipInterval = step * Math.ceil(val / (step!==0?step:1));
8899                         };
8900
8901                         angular.isDefined(attr.min) ? attr.$observe('min', updateMin) : updateMin(b2bSeekBarConfig.min);
8902                         angular.isDefined(attr.max) ? attr.$observe('max', updateMax) : updateMax(b2bSeekBarConfig.max);
8903                         if (angular.isDefined(attr.step)) {
8904                             attr.$observe('step', updateStep);
8905                         }
8906                         if (angular.isDefined(attr.skipInterval)) {
8907                             attr.$observe('skipInterval', updateSkipInterval);
8908                         }
8909                         scope.currentModelValue = getValidMinMax(getValidStep(min));
8910                         var onMouseDown = function(e) {
8911                             switch (e.which) {
8912                                 case 1:
8913                                     // left mouse button
8914                                     break;
8915                                 case 2:
8916                                 case 3:
8917                                     // right or middle mouse button
8918                                     return;
8919                             }
8920                             ;
8921
8922                             scope.isDragging = true;
8923                             seekBarKnob[0].focus();
8924                             updateTrackContainerRect();
8925                             if (attr['onDragInit']) {
8926                                 scope.onDragInit();
8927                             }
8928                             events.stopPropagation(e);
8929                             events.preventDefault(e);
8930                              scope.$apply(function() {
8931                                 setModelValue(getPercentToValue(getPositionToPercent(e[axisPosition])));
8932                             });
8933                         };
8934
8935                         var onMouseUp = function() {
8936
8937                             if (attr['onDragEnd']) {
8938                                 scope.onDragEnd();
8939                             }
8940                             scope.isDragging = false;
8941                             scope.$digest();
8942                         };
8943
8944                         var onMouseMove = function(e) {
8945                             if (scope.isDragging) {
8946                                 events.stopPropagation(e);
8947                                 events.preventDefault(e);
8948
8949                                 scope.$apply(function() {
8950                                     setModelValue(getPercentToValue(getPositionToPercent(e[axisPosition])));
8951                                 });
8952                             }
8953                         };
8954
8955                         function onKeyDown(e) {
8956                             if (!(e.keyCode)) {
8957                                 e.keyCode = e.which;
8958                             }
8959                             var updateStep;
8960                             switch (e.keyCode) {
8961                                 case keymap.KEY.LEFT:
8962                                     if (!scope.verticalSeekBar) {
8963                                         updateStep = -skipInterval;
8964                                     }
8965                                     break;
8966                                 case keymap.KEY.RIGHT:
8967                                     if (!scope.verticalSeekBar) {
8968                                         updateStep = skipInterval;
8969                                     }
8970                                     break;
8971                                 case keymap.KEY.UP:
8972                                     if (scope.verticalSeekBar) {
8973                                         updateStep = skipInterval;
8974                                     }
8975                                     break;
8976                                 case keymap.KEY.DOWN:
8977                                     if (scope.verticalSeekBar) {
8978                                         updateStep = -skipInterval;
8979                                     }
8980                                     break;
8981                                 default:
8982                                     return;
8983                             }
8984
8985                             if (updateStep) {
8986                                 events.stopPropagation(e);
8987                                 events.preventDefault(e);
8988                                 scope.$apply(function() {
8989                                     setModelValue(ngModelCtrl.$viewValue + updateStep);
8990                                 });
8991                                 if (attr['onDragEnd']) {
8992                                 scope.onDragEnd();
8993                             }
8994                             }
8995                         }
8996
8997                         elm.on('keydown', onKeyDown);
8998                         elm.on('mousedown', onMouseDown);
8999
9000                         $documentBind.event('mousemove', 'isDragging', onMouseMove, scope, true, 0);
9001                         $documentBind.event('mouseup', 'isDragging', onMouseUp, scope, true, 0);
9002
9003                         ngModelCtrl.$render = function() {
9004                             if (!scope.isDragging) {
9005                                 modelRenderer();
9006                             }
9007                         };
9008                         ngModelCtrl.$viewChangeListeners.push(modelRenderer);
9009                         ngModelCtrl.$formatters.push(getValidMinMax);
9010                         ngModelCtrl.$formatters.push(getValidStep);
9011                     }
9012                 };
9013             }]);
9014 /**
9015  * @ngdoc directive
9016  * @name Layouts.att:separators
9017  *
9018  * @description
9019  *  <file src="src/separators/docs/readme.md" />
9020  *
9021  * @usage
9022
9023  *
9024  * @example
9025  *  <section id="code">   
9026  <b>HTML + AngularJS</b>
9027  <example module="b2b.att">
9028  <file src="src/separators/docs/demo.html" />
9029  <file src="src/separators/docs/demo.js" />
9030  </example>
9031  </section>
9032  *
9033  */
9034
9035 angular.module('b2b.att.separators', []);
9036 /**
9037  * @ngdoc directive
9038  * @name Buttons, links & UI controls.att:slider
9039  *
9040  * @description
9041  *  <file src="src/slider/docs/readme.md" />
9042  *
9043  * @usage
9044  *  <b2b-slider min="0" max="400" step="1" no-aria-label skip-interval="1" ng-model="horizontalSliderVal" style="width:180px; margin: auto;" on-drag-end="onDragEnd()" on-drag-init="onDragStart()" label-id="slider-label" post-aria-label="postAriaLabel"></b2b-slider>
9045  *
9046  * @example
9047     <section id="code">   
9048         <b>HTML + AngularJS</b>
9049         <example module="b2b.att">
9050             <file src="src/slider/docs/demo.html" />
9051             <file src="src/slider/docs/demo.js" />
9052         </example>
9053     </section>
9054  */
9055
9056 angular.module('b2b.att.slider', ['b2b.att.utilities'])
9057         .constant('SliderConfig', {
9058             'min': 0,
9059             'max': 100,
9060             'step': 1,
9061             'skipInterval': 1
9062         })
9063         .directive('b2bSlider', ['$documentBind', 'SliderConfig', 'keymap', '$compile', '$log', function($documentBind, SliderConfig, keymap, $compile, $log) {
9064                 return {
9065                     restrict: 'AE',
9066                     replace: true,
9067                     require: 'ngModel',
9068                     templateUrl: 'b2bTemplate/slider/slider.html',
9069                     scope: {
9070                         onDragEnd: '&?',
9071                         onDragInit: '&?',
9072                         trackFillColor: '=?',
9073                         preAriaLabel: '=?',
9074                         postAriaLabel: '=?',
9075                         onRenderEnd: '&?',
9076                         sliderSnapPoints: '=?',
9077                         customAriaLabel: '=?',
9078                         labelId: '@?'
9079                     },
9080                     link: function(scope, elm, attr, ngModelCtrl) {
9081                         scope.isDragging = false;
9082                         scope.verticalSlider = false;
9083                         var min;
9084                         var max;
9085                         var step = SliderConfig.step;
9086                         var skipInterval = SliderConfig.skipInterval;
9087                         var knob = angular.element(elm[0].querySelector('.slider-knob-container'));
9088                         var sliderKnob = angular.element(knob[0].querySelector('.slider-knob'));
9089                         var trackContainer = angular.element(elm[0].querySelector('.slider-track-container'));
9090                         var trackFill = angular.element(elm[0].querySelector('.slider-track-fill'));
9091                         var trackContainerRect = {};
9092                         var axisPosition = "clientX";
9093                         var trackFillOrderPositioning;
9094
9095                         //Forcefully disabling the vertical Slider code.
9096                         if (angular.isDefined(attr.vertical)) {
9097                             scope.verticalSlider = true;
9098                             axisPosition = "clientY";
9099                         }
9100
9101                         if (angular.isDefined(scope.noAriaLabel) && scope.noAriaLabel !== '') {
9102                             $log.warn('no-aria-label has been deprecated. This will be removed in v0.6.0.');
9103                         }
9104                         if (angular.isDefined(scope.preAriaLabel) && scope.preAriaLabel !== '') {
9105                             $log.warn('pre-aria-label has been deprecated. Please use label-id instead. This will be removed in v0.6.0.');
9106                         }
9107                         if (angular.isDefined(scope.customAriaLabel) && scope.customAriaLabel !== '') {
9108                             $log.warn('custom-aria-label has been deprecated. Please use label-id and post-aria-label instead. This will be removed in v0.6.0.');
9109                         }
9110
9111                         var binarySearchNearest = function (num, arr) {
9112                             var mid;
9113                             var lo = 0;
9114                             var hi = arr.length - 1;
9115                             
9116                             while (hi - lo > 1) {
9117                                 mid = Math.floor((lo + hi) / 2);
9118                                 if (arr[mid] < num) {
9119                                     lo = mid;
9120                                 } else {
9121                                     hi = mid;
9122                                 }
9123                             }
9124                             if (num - arr[lo] < arr[hi] - num) {
9125                                 return arr[lo];
9126                             }
9127                             return arr[hi];
9128                         };
9129                         
9130                         var getValidStep = function(val) {
9131                             val = parseFloat(val);
9132                             // in case $modelValue came in string number
9133                             if (!isNaN(val)) {
9134                                 
9135                                 if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {
9136                                     val = binarySearchNearest(val, scope.sliderSnapPoints);
9137                                 }
9138                                 else {
9139                                     val = Math.round((val - min) / step) * step + min;
9140                                 }
9141                                 
9142                                 return Math.round(val * 1000) / 1000;
9143                             }
9144                         };
9145
9146                         var getPositionToPercent = function(x) {
9147                             if (scope.verticalSlider) {
9148                                 return Math.max(0, Math.min(1, (trackContainerRect.bottom - x) / (trackFillOrderPositioning)));
9149                             }
9150                             else {
9151                                 return Math.max(0, Math.min(1, (x - trackContainerRect.left) / (trackFillOrderPositioning)));
9152                             }
9153                         };
9154
9155                         var getPercentToValue = function(percent) {
9156                             return (min + percent * (max - min));
9157                         };
9158
9159                         var getValueToPercent = function(val) {
9160                             return (val - min) / (max - min);
9161                         };
9162
9163                         var getValidMinMax = function(val) {
9164                             return Math.max(min, Math.min(max, val));
9165                         };
9166
9167                         var updateTrackContainerRect = function() {
9168                             trackContainerRect = trackContainer[0].getBoundingClientRect();
9169                             if (scope.verticalSlider) {
9170                                 if (!trackContainerRect.height) {
9171                                     trackFillOrderPositioning = trackContainer[0].scrollHeight;
9172                                 } else {
9173                                     trackFillOrderPositioning = trackContainerRect.height;
9174                                 }
9175                             }
9176                             else {
9177                                 if (!trackContainerRect.width) {
9178                                     trackFillOrderPositioning = trackContainer[0].scrollWidth;
9179                                 } else {
9180                                     trackFillOrderPositioning = trackContainerRect.width;
9181                                 }
9182
9183                             }
9184
9185                         };
9186
9187                         var updateKnobPosition = function(percent) {
9188                             var percentStr = (percent * 100) + '%';
9189                             if (scope.verticalSlider) {
9190                                 knob.css('bottom', percentStr);
9191                                 trackFill.css('height', percentStr);
9192                             }
9193                             else {
9194                                 knob.css('left', percentStr);
9195                                 trackFill.css('width', percentStr);
9196                             }
9197                         };
9198
9199                         var modelRenderer = function() {
9200
9201                             if(attr['disabled']){
9202                                 return;
9203                             }
9204
9205                             if (isNaN(ngModelCtrl.$viewValue)) {
9206                                 ngModelCtrl.$viewValue = ngModelCtrl.$modelValue || min;
9207                             }
9208
9209                             var viewVal = ngModelCtrl.$viewValue;
9210                             scope.currentModelValue = viewVal;
9211
9212                             //wait for min, max and step to be set then only update UI to avoid NaN on percent calculation
9213                             if ((min || min === 0) && max && step) {
9214                                 updateKnobPosition(getValueToPercent(viewVal));
9215                             }
9216                         };
9217
9218                         var setModelValue = function(val) {
9219                             scope.currentModelValue = getValidMinMax(getValidStep(val));
9220                             ngModelCtrl.$setViewValue(scope.currentModelValue);
9221                         };
9222
9223                         var updateMin = function(val) {
9224                             min = parseFloat(val);
9225                             if(isNaN(min)){
9226                                min = SliderConfig.min; 
9227                             }
9228                             scope.min = min;
9229                             modelRenderer();
9230                         };
9231
9232                         var updateMax = function(val) {
9233                             max = parseFloat(val);
9234                             if(isNaN(max)){
9235                                max = SliderConfig.max; 
9236                             }
9237                             scope.max = max;
9238                             modelRenderer();
9239                         };
9240
9241                         var updateStep = function(val) {
9242                             step = parseFloat(val);
9243                             if (!attr['skipInterval']) {
9244                                 skipInterval = step;
9245                             }
9246                         };
9247
9248                         var updateSkipInterval = function(val) {
9249                             skipInterval = step * Math.ceil(val / (step!==0?step:1));
9250                         };
9251
9252                         angular.isDefined(attr.min) ? attr.$observe('min', updateMin) : updateMin(SliderConfig.min);
9253                         angular.isDefined(attr.max) ? attr.$observe('max', updateMax) : updateMax(SliderConfig.max);
9254                         if (angular.isDefined(attr.step)) {
9255                             attr.$observe('step', updateStep);
9256                         }
9257                         if (angular.isDefined(attr.skipInterval)) {
9258                             attr.$observe('skipInterval', updateSkipInterval);
9259                         }
9260                         scope.currentModelValue = getValidMinMax(getValidStep(min));
9261                         var onMouseDown = function(e) {
9262
9263                             if(attr['disabled']){
9264                                 return;
9265                             }
9266
9267                             switch (e.which) {
9268                                 case 1:
9269                                     // left mouse button
9270                                     break;
9271                                 case 2:
9272                                 case 3:
9273                                     // right or middle mouse button
9274                                     return;
9275                             }
9276
9277                             scope.isDragging = true;
9278                             sliderKnob[0].focus();
9279                             updateTrackContainerRect();
9280                             if (attr['onDragInit']) {
9281                                 scope.onDragInit();
9282                             }
9283                             e.stopPropagation();
9284                             e.preventDefault();
9285                              scope.$apply(function() {
9286                                 setModelValue(getPercentToValue(getPositionToPercent(e[axisPosition])));
9287                             });
9288                         };
9289
9290                         var onMouseUp = function() {
9291
9292                             if (attr['onDragEnd']) {
9293                                 scope.onDragEnd();
9294                             }
9295                             scope.isDragging = false;
9296                             scope.$digest();
9297                         };
9298
9299                         var onMouseMove = function(e) {
9300                             if (scope.isDragging) {
9301                                 e.stopPropagation();
9302                                 e.preventDefault();
9303
9304                                 scope.$apply(function() {
9305                                     setModelValue(getPercentToValue(getPositionToPercent(e[axisPosition])));
9306                                 });
9307                             }
9308                         };
9309
9310                         function onKeyDown(e) {
9311                             if (!(e.keyCode)) {
9312                                 e.keyCode = e.which;
9313                             }
9314                             var updateStep;
9315                             switch (e.keyCode) {
9316                                 case keymap.KEY.DOWN:
9317                                 case keymap.KEY.LEFT:
9318                                     if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {
9319                                         var currentIndex = scope.sliderSnapPoints.indexOf(ngModelCtrl.$viewValue);
9320                                         if (currentIndex > 0) {
9321                                             currentIndex--;
9322                                         }
9323                                         updateStep = scope.sliderSnapPoints[currentIndex];
9324                                     }
9325                                     else {
9326                                         updateStep = ngModelCtrl.$viewValue - skipInterval;
9327                                     }
9328                                     break;
9329                                 case keymap.KEY.UP:
9330                                 case keymap.KEY.RIGHT:
9331                                     if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {
9332                                         var currentIndex = scope.sliderSnapPoints.indexOf(ngModelCtrl.$viewValue);
9333                                         if (currentIndex < scope.sliderSnapPoints.length-1) {
9334                                             currentIndex++;
9335                                         }
9336                                         updateStep = scope.sliderSnapPoints[currentIndex];
9337                                     }
9338                                     else {
9339                                         updateStep = ngModelCtrl.$viewValue + skipInterval;
9340                                     }
9341                                     break;
9342                                 case keymap.KEY.END:
9343                                     if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {
9344                                         currentIndex = scope.sliderSnapPoints.length-1;
9345                                         updateStep = scope.sliderSnapPoints[currentIndex];
9346                                     } else {
9347                                         setModelValue(scope.max);
9348                                     }
9349                                     e.preventDefault();
9350                                     e.stopPropagation();
9351                                     break;
9352                                 case keymap.KEY.HOME:
9353                                     if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {
9354                                         currentIndex = 0;
9355                                         updateStep = scope.sliderSnapPoints[currentIndex];
9356                                     } else {
9357                                         setModelValue(scope.min);
9358                                     }
9359                                     e.preventDefault();
9360                                     e.stopPropagation();
9361                                     break;
9362                                 default:
9363                                     return;
9364                             }
9365
9366                             if (angular.isNumber(updateStep) && !attr['disabled']) {
9367                                 e.stopPropagation();
9368                                 e.preventDefault();
9369                                 scope.$apply(function() {
9370                                     setModelValue(updateStep);
9371                                 });
9372                                 if (attr['onDragEnd']) {
9373                                     scope.onDragEnd();
9374                                 }
9375                             }
9376                         }
9377
9378                         elm.on('keydown', onKeyDown);
9379                         elm.on('mousedown', onMouseDown);
9380
9381                         $documentBind.event('mousemove', 'isDragging', onMouseMove, scope, true, 0);
9382                         $documentBind.event('mouseup', 'isDragging', onMouseUp, scope, true, 0);
9383
9384                         attr.$observe('disabled', function (disabled) {
9385                             if (disabled) {
9386                                 sliderKnob.removeAttr('tabindex');
9387                             } else {
9388                                 sliderKnob.attr('tabindex', '0');
9389                                 disabled = false;
9390                             }
9391
9392                             elm.toggleClass("slider-disabled", disabled);
9393
9394                             if (angular.isDefined(attr.hideDisabledKnob)) {
9395                                 scope.hideKnob = disabled;
9396                             }
9397                         });
9398
9399                         ngModelCtrl.$render = function() {
9400                             if (!scope.isDragging) {
9401                                 modelRenderer();
9402                                 if (attr['onRenderEnd'] && !attr['disabled']) {
9403                                     scope.onRenderEnd({currentModelValue: scope.currentModelValue});
9404                                 }
9405                             }
9406                         };
9407                         ngModelCtrl.$viewChangeListeners.push(modelRenderer);
9408                         ngModelCtrl.$formatters.push(getValidMinMax);
9409                         ngModelCtrl.$formatters.push(getValidStep);
9410                     }
9411                 };
9412             }]);
9413 /**
9414  * @ngdoc directive
9415  * @name Forms.att:spinButton
9416  *
9417  * @param {String} spin-button-id - An ID for the input field
9418  * @param {Integer} min - Minimum value for the input
9419  * @param {Integer} max - Maximum value for the input
9420  * @param {Integer} step - Value by which input field increments or decrements on up/down arrow keys
9421  * @param {Integer} page-step - Value by which input field increments or decrements on page up/down keys
9422  * @param {boolean} input-model-key - Default value for input field
9423  * @param {boolean} disabled-flag - A boolean that triggers directive once the min or max value has reached
9424  *
9425  * @description
9426  *  <file src="src/spinButton/docs/readme.md" />
9427  *
9428  * @example
9429  *      <section id="code">
9430             <example module="b2b.att">
9431             <file src="src/spinButton/docs/demo.html" />
9432             <file src="src/spinButton/docs/demo.js" />
9433        </example>
9434         </section>
9435  * 
9436  */
9437 angular.module('b2b.att.spinButton', ['b2b.att.utilities'])
9438     .constant('b2bSpinButtonConfig', {
9439         min: 1,
9440         max: 10,
9441         step: 1,
9442         pageStep: 10,
9443         inputModelKey: 'value',
9444         disabledFlag: false
9445     })
9446     .directive('b2bSpinButton', ['keymap', 'b2bSpinButtonConfig', 'b2bUserAgent', function (keymap, b2bSpinButtonConfig, userAgent) {
9447         return {
9448             restrict: 'EA',
9449             require: '?ngModel',
9450             transclude: false,
9451             replace: true,
9452             scope: {
9453                 min: '=min',
9454                 max: '=max',
9455                 step: '=step',
9456                 pageStep: '=pageStep',
9457                 spinButtonId: '@',
9458                 inputValue: '=ngModel',
9459                 inputModelKey: '@',
9460                 disabledFlag: "=?"
9461             },
9462             templateUrl: 'b2bTemplate/spinButton/spinButton.html',
9463             controller: ['$scope', '$element', '$attrs', function (scope, element, attrs) {
9464
9465                 scope.isMobile = userAgent.isMobile();
9466                 scope.notMobile = userAgent.notMobile();
9467
9468                 scope.min = attrs.min ? scope.min : b2bSpinButtonConfig.min;
9469                 scope.max = attrs.max ? scope.max : b2bSpinButtonConfig.max;
9470                 scope.step = attrs.step ? scope.step : b2bSpinButtonConfig.step;
9471                 scope.pageStep = attrs.pageStep ? scope.pageStep : b2bSpinButtonConfig.pageStep;
9472                 scope.inputModelKey = attrs.inputModelKey ? scope.inputModelKey : b2bSpinButtonConfig.inputModelKey;
9473                 scope.disabledFlag = attrs.disabledFlag ? scope.disabledFlag : b2bSpinButtonConfig.disabledFlag;
9474                 
9475                 if (scope.min < 0) {
9476                     scope.min = 0;
9477                 }
9478                 if (scope.max > 999) {
9479                     scope.max = 999;
9480                 }
9481
9482                 scope.isPlusDisabled = function () {
9483                     return (scope.disabledFlag || scope.inputValue[scope.inputModelKey] >= scope.max);
9484                 };
9485                 scope.isMinusDisabled = function () {
9486                     return (scope.disabledFlag || scope.inputValue[scope.inputModelKey] <= scope.min);
9487                 };
9488
9489                 scope.getValidateInputValue = function (value) {
9490                     if (value <= scope.min) {
9491                         return scope.min;
9492                     } else if (value >= scope.max) {
9493                         return scope.max;
9494                     } else {
9495                         return value;
9496                     }
9497                 };
9498
9499                 scope.plus = function () {
9500                     scope.inputValue[scope.inputModelKey] = scope.getValidateInputValue(parseInt(scope.inputValue[scope.inputModelKey], 10) + scope.step);
9501                 };
9502                 scope.minus = function () {
9503                     scope.inputValue[scope.inputModelKey] = scope.getValidateInputValue(parseInt(scope.inputValue[scope.inputModelKey], 10) - scope.step);
9504                 };
9505                 scope.pagePlus = function () {
9506                     scope.inputValue[scope.inputModelKey] = scope.getValidateInputValue(parseInt(scope.inputValue[scope.inputModelKey], 10) + scope.pageStep);
9507                 };
9508                 scope.pageMinus = function () {
9509                     scope.inputValue[scope.inputModelKey] = scope.getValidateInputValue(parseInt(scope.inputValue[scope.inputModelKey], 10) - scope.pageStep);
9510                 };
9511
9512             }],
9513             link: function (scope, elem) {
9514
9515                 if (scope.notMobile) {
9516                     angular.element(elem).find('input').attr('aria-live', 'off');
9517                     angular.element(elem).find('input').attr('role', 'spinbutton');
9518                 }
9519
9520                 elem.find('input').bind('keydown', function (e) {
9521                     if (e.keyCode === keymap.KEY.UP) {
9522                         scope.plus();
9523                     } else if (e.keyCode === keymap.KEY.DOWN){
9524                         scope.minus();
9525                     } else if (e.keyCode === keymap.KEY.HOME) {
9526                         scope.inputValue[scope.inputModelKey] = parseInt(scope.min);
9527                     } else if (e.keyCode === keymap.KEY.END) {
9528                         scope.inputValue[scope.inputModelKey] = parseInt(scope.max);
9529                     } else if (e.keyCode === keymap.KEY.PAGE_UP) {
9530                         scope.pagePlus();
9531                     } else if (e.keyCode === keymap.KEY.PAGE_DOWN) {
9532                         scope.pageMinus();
9533                     }
9534                     scope.$apply();
9535                 });
9536
9537                 elem.find('input').bind('keyup', function () {
9538                     if (scope.inputValue[scope.inputModelKey] === null ||
9539                         scope.inputValue[scope.inputModelKey] === '' ||
9540                         scope.inputValue[scope.inputModelKey] < scope.min) {
9541                         scope.inputValue[scope.inputModelKey] = scope.min;
9542                         scope.$apply();
9543                     } else if (angular.isUndefined(scope.inputValue[scope.inputModelKey]) || 
9544                                scope.inputValue[scope.inputModelKey] > scope.max) {
9545                         scope.inputValue[scope.inputModelKey] = scope.max;
9546                         scope.$apply();
9547                     }
9548                 });
9549
9550                 scope.focusInputSpinButton = function (evt) {
9551                     evt.preventDefault();
9552                     if (scope.notMobile) {
9553                         elem[0].querySelector('input').focus();
9554                     }
9555                 };
9556
9557             }
9558         };  
9559     }]);
9560 /** 
9561  * @ngdoc directive 
9562  * @name Template.att:Static Route
9563  * 
9564  * @description 
9565  *  <file src="src/staticRouteTemplate/docs/readme.md" /> 
9566  * 
9567  * @example 
9568  *  <section id="code"> 
9569         <example module="b2b.att"> 
9570             <file src="src/staticRouteTemplate/docs/demo.html" /> 
9571             <file src="src/staticRouteTemplate/docs/demo.js" /> 
9572        </example> 
9573     </section>    
9574  * 
9575  */
9576 angular.module('b2b.att.staticRouteTemplate', ['b2b.att.utilities'])
9577   
9578 /**
9579  * @ngdoc directive
9580  * @name Progress & usage indicators.att:statusTracker
9581  *
9582  * @scope
9583  * @param {array} statusObject - An array of status objects that accept heading, estimate, description and state
9584  * @description
9585  * <file src="src/statusTracker/docs/readme.md" />
9586  *
9587  * @usage
9588  *
9589 <div ng-controller="statusTrackerController">
9590     <b2b-status-tracker statuses="statusObject"></b2b-status-tracker>
9591 </div>
9592
9593  * @example
9594     <section id="code">   
9595         <example module="b2b.att">
9596             <file src="src/statusTracker/docs/demo.html" />
9597             <file src="src/statusTracker/docs/demo.js" />
9598         </example>
9599     </section>
9600  */
9601
9602 angular.module('b2b.att.statusTracker', ['b2b.att.utilities'])
9603 .constant('b2bStatusTrackerConfig', {
9604     'maxViewItems': 3,
9605     'icons': {
9606         'complete': 'icoControls-approval',
9607         'current': 'icon-misc-time',
9608         'pending': 'icoControls-statusokay',
9609         'actionRequired': 'icon-primary-securityalerts-alert',
9610         'notAvailable': 'icoControls-restricted'
9611     }
9612 })
9613 .directive('b2bStatusTracker', ['b2bStatusTrackerConfig', function(b2bStatusTrackerConfig) {
9614         return {
9615             restrict: 'EA',
9616             transclude: false,
9617             replace: true,
9618             scope:{
9619                 statuses: '='
9620             },
9621             templateUrl: function(scope) {
9622                 return 'b2bTemplate/statusTracker/statusTracker.html';
9623             },
9624             link: function(scope, element, attr) {
9625                 scope.currentViewIndex = 0;
9626                 scope.b2bStatusTrackerConfig = b2bStatusTrackerConfig;
9627
9628                 scope.nextStatus = function() {
9629                     if (scope.currentViewIndex+1 <= scope.statuses.length) {
9630                         scope.currentViewIndex++;
9631                     }
9632                 };
9633                 scope.previousStatus = function() {
9634                     if (scope.currentViewIndex-1 >= 0) {
9635                         scope.currentViewIndex--;
9636                     }
9637                 };
9638                 scope.isInViewport = function(index) {
9639                     return (index < scope.currentViewIndex+3 && index >= scope.currentViewIndex);  // && index > scope.currentViewIndex-2
9640                 };
9641
9642                 scope.removeCamelCase = function(str) {
9643                     return str.replace(/([a-z])([A-Z])/g, '$1 $2').toLowerCase();
9644                 }
9645             }
9646         };
9647     }]);
9648 /**
9649  * @ngdoc directive
9650  * @name Progress & usage indicators.att:stepTracker
9651  *
9652  * @scope
9653  * @param {array} stepsItemsObject - An array of step objects
9654  * @param {Integer} currenIindex - This indicates the current running step
9655  * @param {Integer} viewportIndex - This is optional. This can used to start the view port rather than 1 item.
9656  * @description
9657  * <file src="src/stepTracker/docs/readme.md" />
9658  *
9659  * @usage
9660  *
9661  *      <b2b-step-tracker steps-items-object="stepsObject" current-index="currentStepIndex" step-indicator-heading="stepHeading"></b2b-step-tracker>
9662  *
9663
9664  * @example
9665     <section id="code">   
9666         <b>HTML + AngularJS</b>
9667         <example module="b2b.att">
9668             <file src="src/stepTracker/docs/demo.html" />
9669             <file src="src/stepTracker/docs/demo.js" />
9670         </example>
9671     </section>
9672  */
9673 angular.module('b2b.att.stepTracker', ['b2b.att.utilities'])
9674         .constant('b2bStepTrackerConfig', {
9675                 'maxViewItems': 5
9676         })
9677         .directive('b2bStepTracker', ['b2bStepTrackerConfig', function(b2bStepTrackerConfig) {
9678                 return {
9679                         restrict: 'EA',
9680                         transclude: true,
9681                         scope:{
9682                                 stepsItemsObject:"=",
9683                                 currentIndex:"=",
9684                 viewportIndex:"=?"
9685                         },
9686                         templateUrl: 'b2bTemplate/stepTracker/stepTracker.html',
9687                         link: function(scope, ele, attr) {
9688                 if (angular.isDefined(scope.viewportIndex)) {
9689                     scope.currentViewIndex = scope.viewportIndex - 1;   
9690                 }else{
9691                     scope.currentViewIndex = 0;
9692                 }
9693                            
9694                            scope.b2bStepTrackerConfig = b2bStepTrackerConfig;
9695                            scope.nextStatus = function() {
9696                                         if (scope.currentViewIndex+1 <= scope.stepsItemsObject.length) {
9697                                                 scope.currentViewIndex++;
9698                                         }
9699                                 };
9700                                 scope.previousStatus = function() {
9701                                         if (scope.currentViewIndex-1 >= 0) {
9702                                                 scope.currentViewIndex--;
9703                                         }
9704                                 };
9705                                 scope.isInViewport = function(index) {
9706                                         return (index < scope.currentViewIndex+b2bStepTrackerConfig.maxViewItems && index >= scope.currentViewIndex);
9707                                 };
9708                         }
9709                 };
9710         }]);
9711      
9712 /**
9713  * @ngdoc directive
9714  * @name Buttons, links & UI controls.att:switches
9715  *
9716  * @description
9717  *  <file src="src/switches/docs/readme.md" />
9718  *
9719  * @usage
9720  *  
9721  *  <!-- On / Off Toggle switch -->
9722  *  <label for="switch1" class="controlled-text-wrap"> This is ON
9723  *      <input type="checkbox" role="checkbox" b2b-switches id="switch1" ng-model="switch1.value">
9724  *  </label>
9725  *
9726  *  <!-- On / Off Toggle switch and DISABLED -->
9727  *  <label for="switch2" class="controlled-text-wrap"> This is ON (disabled)
9728  *      <input type="checkbox" role="checkbox" b2b-switches id="switch2" ng-model="switch1.value" ng-disabled="true" >
9729  *  </label> 
9730  *
9731  *
9732  * @example
9733  *  <section id="code">
9734         <b>HTML + AngularJS</b>
9735         <example module="b2b.att">
9736             <file src="src/switches/docs/demo.js" />
9737             <file src="src/switches/docs/demo.html" />
9738         </example>
9739     </section>
9740  */
9741 angular.module('b2b.att.switches', ['b2b.att.utilities'])
9742     .directive('b2bSwitches', ['$compile', '$templateCache', 'keymap', 'events', function ($compile, $templateCache, keymap, events) {
9743         return {
9744             restrict: 'EA',
9745             require: ['ngModel'],
9746             link: function (scope, element, attrs, ctrl) {
9747                 var ngModelController = ctrl[0];
9748         
9749                 element.parent().bind("keydown", function (e) {
9750                     if (!attrs.disabled && (e.keyCode === keymap.KEY.ENTER || e.keyCode === keymap.KEY.SPACE)) {
9751                         events.preventDefault(e);
9752                         ngModelController.$setViewValue(!ngModelController.$viewValue);
9753                         element.prop("checked", ngModelController.$viewValue);
9754                     }
9755                 });
9756
9757                 element.wrap('<div class="btn-switch">');
9758                 //element.attr("tabindex", -1);
9759                 if (navigator.userAgent.match(/iphone/i)){
9760                     element.attr("aria-live", "polite");
9761                 }
9762                 else {
9763                     element.removeAttr('aria-live');
9764                 }
9765
9766                 var templateSwitch = angular.element($templateCache.get("b2bTemplate/switches/switches.html"));
9767                 if (angular.isDefined(attrs.typeSpanish)) {
9768                     templateSwitch = angular.element($templateCache.get("b2bTemplate/switches/switches-spanish.html"));
9769                 }
9770
9771                 templateSwitch = $compile(templateSwitch)(scope);
9772                 element.parent().append(templateSwitch);
9773
9774                 element.bind("focus", function (e) {
9775                     element.parent().addClass('focused');
9776                 });
9777
9778                 element.bind("blur", function (e) {
9779                     element.parent().removeClass('focused');
9780                 });
9781             }
9782         };
9783     }]);
9784 /** 
9785  * @ngdoc directive 
9786  * @name Template.att:Table with Drag and Drop
9787  * 
9788  * @description 
9789  *  <file src="src/tableDragAndDrop/docs/readme.md" /> 
9790  * 
9791  * @example 
9792  *  <section id="code"> 
9793         <example module="b2b.att"> 
9794             <file src="src/tableDragAndDrop/docs/demo.html" /> 
9795             <file src="src/tableDragAndDrop/docs/demo.js" /> 
9796        </example> 
9797     </section>    
9798  * 
9799  */
9800 angular.module('b2b.att.tableDragAndDrop', ['b2b.att.utilities','b2b.att.tables'])
9801   
9802 /**
9803  * @ngdoc directive
9804  * @name Messages, modals & alerts.att:tableMessages
9805  *
9806  * @description
9807  *  <file src="src/tableMessages/docs/readme.md" />
9808  *
9809  * @usage
9810     <!-- no matching results -->
9811     <b2b-table-message msg-type="'noMatchingResults'">
9812        <p>No Matching Results</p>
9813     </b2b-table-message>
9814   
9815     <!-- info could not load -->
9816     <b2b-table-message msg-type="'infoCouldNotLoad'" on-refresh-click="refreshClicked()">
9817     </b2b-table-message>
9818    
9819     <!-- magnify search -->
9820     <b2b-table-message msg-type="'magnifySearch'">
9821     </b2b-table-message>
9822    
9823     <!-- loading data -->
9824     <b2b-table-message msg-type="'loadingTable'">
9825           <!-- custom html -->
9826           <p>The data is currently loading...</p>
9827     </b2b-table-message>
9828
9829  * @example
9830     <section id="code">   
9831         <b>HTML + AngularJS</b>
9832         <example module="b2b.att">
9833             <file src="src/tableMessages/docs/demo.html" />
9834             <file src="src/tableMessages/docs/demo.js" />
9835         </example>
9836     </section>
9837  */
9838 angular.module('b2b.att.tableMessages', [])
9839     .directive('b2bTableMessage', [function() {
9840         return {
9841             restrict: 'AE',
9842             replace: true,
9843             transclude: true,
9844             scope: {
9845                 msgType: '=',
9846                 onRefreshClick: '&'
9847             },
9848             templateUrl: 'b2bTemplate/tableMessages/tableMessage.html',
9849             link: function(scope) {
9850                 scope.refreshAction = function(evt) {
9851                     scope.onRefreshClick(evt);
9852                 };
9853             }
9854         };
9855     }]);
9856
9857 /**
9858  * @ngdoc directive
9859  * @name Tabs, tables & accordions.att:tableScrollbar
9860  *
9861  * @description
9862  *  <file src="src/tableScrollbar/docs/readme.md" />
9863  *
9864  * @usage
9865  * 
9866 <b2b-table-scrollbar>
9867     <table>
9868         <thead type="header">
9869             <tr>
9870                 <th role="columnheader" scope="col" key="Id" id="col1">Id</th>
9871                 .....
9872             </tr>
9873         </thead>
9874         <tbody type="body">
9875             <tr>
9876                 <td id="rowheader0" headers="col1">1002</td>
9877                 .....
9878             </tr>
9879         </tbody>
9880     </table>
9881 </b2b-table-scrollbar>
9882  *
9883  * @example
9884  *  <section id="code">
9885         <example module="b2b.att">
9886             <file src="src/tableScrollbar/docs/demo.html" />
9887             <file src="src/tableScrollbar/docs/demo.js" />
9888        </example>
9889     </section>
9890  *
9891  */
9892 angular.module('b2b.att.tableScrollbar', [])
9893     .directive('b2bTableScrollbar', ['$timeout', function ($timeout) {
9894         return {
9895             restrict: 'E',
9896             scope: true,
9897             transclude: true,
9898             templateUrl: 'b2bTemplate/tableScrollbar/tableScrollbar.html',
9899             link: function (scope, element, attrs, ctrl) {
9900                 var firstThWidth, firstTdWidth, firstColumnWidth, firstColumnHeight, trHeight = 0;
9901                 var pxToScroll = '';
9902                 var tableElement = element.find('table');
9903                 var thElements = element.find('th');
9904                 var tdElements = element.find('td');
9905                 var innerContainer = angular.element(element[0].querySelector('.b2b-table-inner-container'));
9906                 var outerContainer = angular.element(element[0].querySelector('.b2b-table-scrollbar'));
9907
9908                 scope.disableLeft = true;
9909                 scope.disableRight = false;
9910
9911                 if (angular.isDefined(thElements[0])) {
9912                     firstThWidth = thElements[0].offsetWidth;
9913                 }
9914                 if (angular.isDefined(tdElements[0])) {
9915                     firstTdWidth = tdElements[0].offsetWidth;
9916                 }
9917                 firstColumnWidth = (firstThWidth > firstTdWidth) ? firstThWidth : firstTdWidth;
9918
9919                 innerContainer.css({
9920                     'padding-left': (firstColumnWidth + 2) + 'px'
9921                 });
9922
9923                 angular.forEach(element.find('tr'), function (eachTr, index) {
9924                     trObject = angular.element(eachTr);
9925                     firstColumn = angular.element(trObject.children()[0]);
9926
9927                     angular.element(firstColumn).css({
9928                         'left': '0px',
9929                         'width': (firstColumnWidth + 2) + 'px',
9930                         'position': 'absolute'
9931                     });
9932
9933                     trHeight = trObject[0].offsetHeight;
9934                     firstColumnHeight = firstColumn[0].offsetHeight;
9935                     if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
9936                         firstColumnHeight += 1;
9937                     }
9938
9939                     if (trHeight !== firstColumnHeight - 1) {
9940                         if (trHeight > firstColumnHeight) {
9941                             if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
9942                                 trHeight -= 1;
9943                             }
9944                             angular.element(firstColumn).css({
9945                                 'height': (trHeight + 1) + 'px'
9946                             });
9947                         } else {
9948                             angular.element(trObject).css({
9949                                 'height': (firstColumnHeight - 1) + 'px'
9950                             });
9951                         }
9952                     }
9953
9954                 });
9955
9956                 pxToScroll = outerContainer[0].offsetWidth - firstColumnWidth;
9957
9958                 scope.scrollLeft = function () {
9959                     innerContainer[0].scrollLeft = innerContainer[0].scrollLeft + 20 - pxToScroll;
9960                 };
9961
9962                 scope.scrollRight = function () {
9963                     innerContainer[0].scrollLeft = innerContainer[0].scrollLeft + pxToScroll - 20;
9964                 };
9965
9966                 scope.checkScrollArrows = function () {
9967                     if (innerContainer[0].scrollLeft == 0) {
9968                         scope.disableLeft = true;
9969                     } else {
9970                         scope.disableLeft = false;
9971                     }
9972
9973                     if (((innerContainer[0].offsetWidth - firstColumnWidth) + innerContainer[0].scrollLeft) >= tableElement[0].offsetWidth) {
9974                         scope.disableRight = true;
9975                     } else {
9976                         scope.disableRight = false;
9977                     }
9978                 };
9979
9980
9981                 innerContainer.bind('scroll', function () {
9982                     $timeout(function () {
9983                         scope.checkScrollArrows();
9984                     }, 1);
9985                 });
9986
9987             }
9988         };
9989     }]);
9990 /**
9991  * @ngdoc directive
9992  * @name Tabs, tables & accordions.att:tables
9993  *
9994  * @description
9995  *  <file src="src/tables/docs/readme.md" />
9996  *
9997  * @usage
9998  *   
9999  Table
10000  <table b2b-table table-data="tableData" search-string="searchString">
10001     <thead b2b-table-row type="header">
10002         <tr>
10003             <th b2b-table-header key="requestId" default-sort="a" id="col1">Header 1</th>
10004             <th b2b-table-header key="requestType" sortable="false" id="col2">Header 2</th>
10005         </tr>
10006     </thead>
10007     <tbody b2b-table-row type="body" row-repeat="rowData in tableData">
10008         <tr>
10009             <td b2b-table-body id="rowheader{{$index}}" headers="col1" ng-bind="rowData['requestId']"> </td>
10010             <td b2b-table-body ng-bind="rowData['requestType']"></td>
10011         </tr>
10012     </tbody>
10013  </table>
10014  *
10015  * @example
10016  *  <section id="code">
10017         <example module="b2b.att">
10018             <file src="src/tables/docs/demo.html" />
10019             <file src="src/tables/docs/demo.js" />
10020        </example>
10021     </section>
10022  *
10023  */
10024 angular.module('b2b.att.tables', ['b2b.att.utilities'])
10025     .constant('b2bTableConfig', {
10026         defaultSortPattern: false, // true for descending & false for ascending
10027         highlightSearchStringClass: 'tablesorter-search-highlight',
10028         zebraStripCutOff: 6, // > zebraStripCutOff
10029         tableBreakpoints: [ // breakpoints are >= min and < max
10030             {
10031                 min: 0,
10032                 max: 480,
10033                 columns: 2
10034             },
10035             {
10036                 min: 480,
10037                 max: 768,
10038                 columns: 3
10039             },
10040             {
10041                 min: 768,
10042                 max: 1025,
10043                 columns: 5
10044             },
10045             {
10046                 min: 1025,
10047                 max: 1920,
10048                 columns: 7
10049             }
10050         ]
10051     })
10052     .directive('b2bTable', ['$filter', '$window', 'b2bTableConfig', '$timeout', function ($filter, $window, b2bTableConfig, $timeout) {
10053         return {
10054             restrict: 'EA',
10055             replace: true,
10056             transclude: true,
10057             scope: {
10058                 tableData: "=",
10059                 viewPerPage: "=",
10060                 currentPage: "=",
10061                 totalPage: "=",
10062                 searchCategory: "=",
10063                 searchString: "=",
10064                 nextSort: '='
10065             },
10066             require: 'b2bTable',
10067             templateUrl: 'b2bTemplate/tables/b2bTable.html',
10068             controller: ['$scope', '$attrs', function ($scope, $attrs) {
10069                 this.headers = [];
10070                 this.currentSortIndex = null;
10071                 this.responsive = $scope.responsive = $attrs.responsive;
10072                 this.maxTableColumns = -1;
10073                 this.totalTableColums = 0;
10074                 this.active = $scope.active = false;
10075                 this.responsiveRowScopes = [];
10076                 this.hideColumnPriority = [];
10077                 this.hiddenColumn = [];
10078                 this.setIndex = function (headerScope, priority) {
10079                     this.headers.push(headerScope);
10080                     if (this.responsive) {
10081                         this.totalTableColums++;
10082                         if (!isNaN(priority)) {
10083                             this.hideColumnPriority[priority] = this.totalTableColums - 1;
10084                         } else {
10085                             this.hideColumnPriority[this.totalTableColums - 1] = this.totalTableColums - 1;
10086                         }
10087                     }
10088                     return this.totalTableColums - 1;
10089                 };
10090                 this.getIndex = function (headerName) {
10091                     for (var i = 0; i < this.headers.length; i++) {
10092                         if (this.headers[i].headerName === headerName) {
10093                             return this.headers[i].index;
10094                         }
10095                     }
10096                     return null;
10097                 };
10098                 this.setResponsiveRow = function (responsiveRowScope) {
10099                     this.responsiveRowScopes.push(responsiveRowScope);
10100                 }
10101                 $scope.nextSort = '';
10102                 this.sortData = function (columnIndex, reverse, externalSort) {
10103                     if ($scope.$parent && $scope.$parent !== undefined) {
10104                         $scope.$parent.columnIndex = columnIndex;
10105                         $scope.$parent.reverse = reverse;
10106                     }
10107                     this.currentSortIndex = columnIndex;
10108                     if (externalSort === true) {
10109                         if (!reverse) {
10110                             $scope.nextSort = 'd'
10111                         } else {
10112                             $scope.nextSort = 'a'
10113                         }
10114                     }
10115                     $scope.currentPage = 1;
10116                     this.resetSortPattern();
10117                 };
10118                 this.getSearchString = function () {
10119                     return $scope.searchString;
10120                 };
10121                 this.resetSortPattern = function () {
10122                     for (var i = 0; i < this.headers.length; i++) {
10123                         var currentScope = this.headers[i];
10124                         if (currentScope.index !== this.currentSortIndex) {
10125                             currentScope.resetSortPattern();
10126                         }
10127                     }
10128                 };
10129
10130                 $scope.$watch('nextSort', function (val) {
10131                     if ($scope.$parent && $scope.$parent !== undefined) {
10132                         $scope.$parent.nextSort = val;
10133                     }
10134
10135                 });
10136             }],
10137             link: function (scope, elem, attr, ctrl) {
10138                 scope.searchCriteria = {};
10139                 scope.tableBreakpoints = attr.tableConfig ? scope.$parent.$eval(attr.tableConfig) : angular.copy(b2bTableConfig.tableBreakpoints);
10140                 scope.$watchCollection('tableData', function (value) {
10141                     if (value && !isNaN(value.length)) {
10142                         scope.totalRows = value.length;
10143                     }
10144                 });
10145                 scope.$watch('currentPage', function (val) {
10146                     if (scope.$parent && scope.$parent !== undefined) {
10147                         scope.$parent.currentPage = val;
10148                     }
10149
10150                 });
10151                 scope.$watch('viewPerPage', function (val) {
10152                     if (scope.$parent && scope.$parent !== undefined) {
10153                         scope.$parent.viewPerPage = val;
10154                     }
10155                 });
10156                 scope.$watch('totalRows', function (val) {
10157                     if (scope.$parent && scope.$parent !== undefined) {
10158                         if (val > b2bTableConfig.zebraStripCutOff) {
10159                             scope.$parent.zebraStripFlag = true;
10160                         } else {
10161                             scope.$parent.zebraStripFlag = false;
10162                         }
10163                     }
10164                 });
10165                 scope.$watch(function () {
10166                     return scope.totalRows / scope.viewPerPage;
10167                 }, function (value) {
10168                     if (!isNaN(value)) {
10169                         scope.totalPage = Math.ceil(value);
10170                         scope.currentPage = 1;
10171                     }
10172                 });
10173                 var searchValCheck = function (val) {
10174                     if (angular.isDefined(val) && val !== null && val !== "") {
10175                         return true;
10176                     }
10177                 };
10178                 var setSearchCriteria = function (v1, v2) {
10179                     if (searchValCheck(v1) && searchValCheck(v2)) {
10180                         var index = ctrl.getIndex(v2);
10181                         scope.searchCriteria = {};
10182                         if (index !== null) {
10183                             scope.searchCriteria[index] = v1;
10184                         }
10185                     } else if (searchValCheck(v1) && (!angular.isDefined(v2) || v2 === null || v2 === "")) {
10186                         scope.searchCriteria = {
10187                             $: v1
10188                         };
10189                     } else {
10190                         scope.searchCriteria = {};
10191                     }
10192                 };
10193                 scope.$watch('searchCategory', function (newVal, oldVal) {
10194                     if (newVal !== oldVal) {
10195                         setSearchCriteria(scope.searchString, newVal);
10196                     }
10197                 });
10198                 scope.$watch('searchString', function (newVal, oldVal) {
10199                     if (newVal !== oldVal) {
10200                         setSearchCriteria(newVal, scope.searchCategory);
10201                     }
10202                 });
10203                 scope.$watchCollection('searchCriteria', function (val) {
10204                     if (scope.$parent && scope.$parent !== undefined) {
10205                         scope.$parent.searchCriteria = val;
10206                     }
10207                     scope.totalRows = scope.tableData && ($filter('filter')(scope.tableData, val, false)).length || 0;
10208                     scope.currentPage = 1;
10209                 });
10210                 var window = angular.element($window);
10211                 var findMaxTableColumns = function () {
10212                     var windowWidth;
10213                     windowWidth = $window.innerWidth;
10214                     ctrl.maxTableColumns = -1;
10215                     for (var i in scope.tableBreakpoints) {
10216                         if (windowWidth >= scope.tableBreakpoints[i].min && windowWidth < scope.tableBreakpoints[i].max) {
10217                             ctrl.maxTableColumns = scope.tableBreakpoints[i].columns;
10218                             break;
10219                         }
10220                     }
10221                     if (ctrl.maxTableColumns > -1 && ctrl.totalTableColums > ctrl.maxTableColumns) {
10222                         ctrl.active = true;
10223                     } else {
10224                         ctrl.active = false;
10225                     }
10226                     for (var i in ctrl.responsiveRowScopes) {
10227                         ctrl.responsiveRowScopes[i].setActive(ctrl.active);
10228                     }
10229                 };
10230                 var findHiddenColumn = function () {
10231                     var columnDiffenence = ctrl.maxTableColumns > -1 ? ctrl.totalTableColums - ctrl.maxTableColumns : 0;
10232                     ctrl.hiddenColumn = [];
10233                     if (columnDiffenence > 0) {
10234                         var tempHideColumnPriority = angular.copy(ctrl.hideColumnPriority);
10235                         for (var i = 0; i < columnDiffenence; i++) {
10236                             ctrl.hiddenColumn.push(tempHideColumnPriority.pop());
10237                         }
10238                     }
10239                 };
10240                 var resizeListener = function () {
10241                     findMaxTableColumns();
10242                     findHiddenColumn();
10243                 };
10244                 if (ctrl.responsive) {
10245                     window.bind('resize', function () {
10246                         resizeListener();
10247                         scope.$apply();
10248                     });
10249                     $timeout(function () {
10250                         resizeListener();
10251                     }, 100);
10252                 }
10253             }
10254         };
10255     }])
10256     .directive('b2bTableRow', [function () {
10257         return {
10258             restrict: 'EA',
10259             compile: function (elem, attr) {
10260                 if (attr.type === 'header') {
10261                     angular.noop();
10262                 } else if (attr.type === 'body') {
10263                     var html = elem.children();
10264                     if (attr.rowRepeat) {
10265                         html.attr('ng-repeat', attr.rowRepeat.concat(" | orderBy : (reverse?'-':'')+ columnIndex  | filter : searchCriteria : false "));
10266                     }
10267                     html.attr('ng-class', "{'odd': $odd && zebraStripFlag}");
10268                     html.attr('class', 'data-row');
10269                     html.attr('b2b-responsive-row', '{{$index}}');
10270                     elem.append(html);
10271                 }
10272             }
10273         };
10274     }])
10275     .directive('b2bTableHeader', ['b2bTableConfig', function (b2bTableConfig) {
10276         return {
10277             restrict: 'EA',
10278             replace: true,
10279             transclude: true,
10280             scope: {
10281                 sortable: '@',
10282                 defaultSort: '@',
10283                 index: '@key'
10284             },
10285             require: '^b2bTable',
10286             templateUrl: function (elem, attr) {
10287                 if (attr.sortable === 'false') {
10288                     return 'b2bTemplate/tables/b2bTableHeaderUnsortable.html';
10289                 } else {
10290                     return 'b2bTemplate/tables/b2bTableHeaderSortable.html';
10291                 }
10292             },
10293             link: function (scope, elem, attr, ctrl) {
10294                 var reverse = b2bTableConfig.defaultSortPattern;
10295                 scope.headerName = elem.text();
10296                 scope.headerId = elem.attr('id');
10297                 scope.sortPattern = null;
10298                 var priority = parseInt(attr.priority, 10);
10299                 scope.columnIndex = ctrl.setIndex(scope, priority);
10300
10301                 scope.isHidden = function () {
10302                     return (ctrl.hiddenColumn.indexOf(scope.columnIndex) > -1);
10303                 };
10304
10305                 scope.$watch(function () {
10306                     return elem.text();
10307                 }, function (value) {
10308                     scope.headerName = value;
10309                 });
10310                 scope.sort = function (sortType) {
10311                     if (typeof sortType === 'boolean') {
10312                         reverse = sortType;
10313                     }
10314                     ctrl.sortData(scope.index, reverse, false);
10315                     scope.sortPattern = reverse ? 'descending' : 'ascending';
10316                     reverse = !reverse;
10317                 };
10318                 scope.$watch(function () {
10319                     return ctrl.currentSortIndex;
10320                 }, function (value) {
10321                     if (value !== scope.index) {
10322                         scope.sortPattern = null;
10323                     }
10324                 });
10325
10326                 if (scope.sortable === undefined || scope.sortable === 'true' || scope.sortable === true) {
10327                     scope.sortable = 'true';
10328                 } else if (scope.sortable === false || scope.sortable === 'false') {
10329                     scope.sortable = 'false';
10330                 }
10331
10332                 if (scope.sortable !== 'false') {
10333                     if (scope.defaultSort === 'A' || scope.defaultSort === 'a') {
10334                         scope.sort(false);
10335                     } else if (scope.defaultSort === 'D' || scope.defaultSort === 'd') {
10336                         scope.sort(true);
10337                     }
10338                 }
10339                 scope.resetSortPattern = function () {
10340                     reverse = b2bTableConfig.defaultSortPattern;
10341                 };
10342             }
10343         };
10344     }])
10345     .directive('b2bResponsiveRow', ['$templateCache', '$timeout', '$compile', function ($templateCache, $timeout, $compile) {
10346         return {
10347             restrict: 'EA',
10348             require: '^b2bTable',
10349             controller: ['$scope', function ($scope) {
10350                 this.rowValues = $scope.rowValues = [];
10351                 this.setRowValues = function (rowValue) {
10352                     this.rowValues.push(rowValue);
10353                 };
10354                 var columnIndexCounter = -1;
10355                 this.getIndex = function () {
10356                     columnIndexCounter++;
10357                     return columnIndexCounter;
10358                 };
10359             }],
10360             link: function (scope, elem, attr, ctrl) {
10361                 if (ctrl.responsive) {
10362                     scope.rowIndex = attr.b2bResponsiveRow;
10363                     scope.active = false;
10364                     scope.expandFlag = false;
10365                     scope.headerValues = ctrl.headers;
10366                     ctrl.setResponsiveRow(scope);
10367                     var firstTd = elem.find('td').eq(0);
10368                     scope.setActive = function (activeFlag) {
10369                         scope.active = activeFlag;
10370                         if (scope.active) {
10371                             elem.addClass('has-button');
10372                             firstTd.attr('role', 'rowheader');
10373                             firstTd.parent().attr('role', 'row');
10374                         } else {
10375                             elem.removeClass('has-button');
10376                             firstTd.removeAttr('role');
10377                             firstTd.parent().removeAttr('role');
10378                         }
10379                     };
10380                     scope.toggleExpandFlag = function (expandFlag) {
10381                         if (angular.isDefined(expandFlag)) {
10382                             scope.expandFlag = expandFlag;
10383                         } else {
10384                             scope.expandFlag = !scope.expandFlag;
10385                         }
10386                         if (scope.expandFlag) {
10387                             elem.addClass('opened');
10388                         } else {
10389                             elem.removeClass('opened');
10390                         }
10391                     };
10392
10393                     firstTd.attr('scope', 'row');
10394                     firstTd.addClass('col-1');
10395                     scope.$on('$destroy', function () {
10396                         elem.next().remove();
10397                     });
10398                     $timeout(function () {
10399                         scope.firstTdId = firstTd.attr('id');
10400                         var firstTdContent = firstTd.html();
10401                         var toggleButtonTemplate = '<span ng-show="!active">' + firstTdContent + '</span><button type="button" aria-describedby="sup-actNum{{$id}}" aria-expanded="{{expandFlag}}" ng-show="active" ng-click="toggleExpandFlag()"><i ng-class="{\'icon-primary-accordion-plus\': !expandFlag, \'icon-primary-accordion-minus\': expandFlag}" aria-hidden="true"></i>' + firstTdContent + '</button><span id="sup-actNum{{$id}}" style="display:none">{{expandFlag && "Hide row below." || "Show row below."}}</span>';
10402                         toggleButtonTemplate = $compile(toggleButtonTemplate)(scope);
10403                         firstTd.html('');
10404                         firstTd.prepend(toggleButtonTemplate);
10405
10406                         var template = $templateCache.get('b2bTemplate/tables/b2bResponsiveRow.html');
10407                         template = $compile(template)(scope);
10408                         elem.after(template);
10409                     }, 100);
10410                 }
10411             }
10412         };
10413     }])
10414     .directive('b2bResponsiveList', ['$templateCache', '$timeout', '$compile', function ($templateCache, $timeout, $compile) {
10415         return {
10416             restrict: 'EA',
10417             require: '^b2bTable',
10418             link: function (scope, elem, attr, ctrl) {
10419                 scope.columnIndex = parseInt(attr.b2bResponsiveList, 10);
10420                 scope.isVisible = function () {
10421                     return (ctrl.hiddenColumn.indexOf(scope.columnIndex) > -1);
10422                 };
10423             }
10424         };
10425     }])
10426     .directive('b2bTableBody', ['$filter', '$timeout', 'b2bTableConfig', function ($filter, $timeout, b2bTableConfig) {
10427         return {
10428             restrict: 'EA',
10429             require: ['^b2bTable', '?^b2bResponsiveRow'],
10430             scope: true,
10431             replace: true,
10432             transclude: true,
10433             templateUrl: 'b2bTemplate/tables/b2bTableBody.html',
10434             link: function (scope, elem, attr, ctrl) {
10435                 var b2bTableCtrl = ctrl[0];
10436                 var b2bResponsiveRowCtrl = ctrl[1];
10437                 var highlightSearchStringClass = b2bTableConfig.highlightSearchStringClass;
10438                 var searchString = "";
10439                 var wrapElement = function (elem) {
10440                     var text = elem.text();
10441                     elem.html($filter('b2bHighlight')(text, searchString, highlightSearchStringClass));
10442                 };
10443                 var traverse = function (elem) {
10444                     var innerHtml = elem.children();
10445                     if (innerHtml.length > 0) {
10446                         for (var i = 0; i < innerHtml.length; i++) {
10447                             traverse(innerHtml.eq(i));
10448                         }
10449                     } else {
10450                         wrapElement(elem);
10451                         return;
10452                     }
10453                 };
10454                 var clearWrap = function (elem) {
10455                     var elems = elem.find('*');
10456                     for (var i = 0; i < elems.length; i++) {
10457                         if (elems.eq(i).attr('class') && elems.eq(i).attr('class').indexOf(highlightSearchStringClass) !== -1) {
10458                             var text = elems.eq(i).text();
10459                             elems.eq(i).replaceWith(text);
10460                         }
10461                     }
10462                 };
10463                 if (b2bResponsiveRowCtrl) {
10464                     scope.columnIndex = b2bResponsiveRowCtrl.getIndex();
10465                     scope.isHidden = function () {
10466                         return (b2bTableCtrl.hiddenColumn.indexOf(scope.columnIndex) > -1);
10467                     };
10468                 }
10469                 $timeout(function () {
10470                     var actualHtml = elem.children();
10471                     scope.$watch(function () {
10472                         return b2bTableCtrl.getSearchString();
10473                     }, function (val) {
10474                         searchString = val;
10475                         clearWrap(elem);
10476                         if (actualHtml.length > 0) {
10477                             traverse(elem);
10478                         } else {
10479                             wrapElement(elem);
10480                         }
10481                     });
10482                     if (b2bResponsiveRowCtrl) {
10483                         b2bResponsiveRowCtrl.setRowValues(elem.html());
10484                     }
10485                 }, 50);
10486             }
10487         };
10488     }])
10489     .directive('b2bTableSort', ['b2bTableConfig','$timeout', function (b2bTableConfig,$timeout) {
10490         return {
10491             restrict: 'EA',
10492             replace: true,
10493             require: '^b2bTable',
10494             link: function (scope, elem, attr, ctrl) {
10495                 var initialSort = '',
10496                     nextSort = '',
10497                     tempsort = '';
10498                 initialSort = attr.initialSort;
10499
10500                 scope.sortTable = function (msg,trigger) {
10501                     if(trigger == 'dropdown'){
10502                         if (nextSort === 'd' || nextSort === 'D') {                        
10503                          ctrl.sortData(msg, false, false);
10504                         }else{
10505                          ctrl.sortData(msg, true, false);
10506                         }
10507                         return;                        
10508                     }
10509                     $timeout(function(){
10510                         if (nextSort.length > 0) {
10511
10512                         if (nextSort === 'd' || nextSort === 'D') {
10513                             tempsort = nextSort
10514                             ctrl.sortData(msg, true, true);
10515                             nextSort = 'a';
10516                              $timeout(function(){
10517                                 if(!angular.isUndefined(elem[0].querySelector('.sortButton')) || elem[0].querySelector('.sortButton') !== null ){
10518                                     angular.element(elem[0].querySelector('.sortButton'))[0].focus();
10519                                 }   
10520                             },100);
10521                             
10522                         } else {
10523                             tempsort = nextSort
10524                             ctrl.sortData(msg, false, true);
10525                             nextSort = 'd';
10526                              $timeout(function(){
10527                                 if(!angular.isUndefined(elem[0].querySelector('.sortButton')) || elem[0].querySelector('.sortButton') !== null ){
10528                                     angular.element(elem[0].querySelector('.sortButton'))[0].focus();
10529                                 }   
10530                             },100);
10531                         }
10532                     } else if (initialSort.length > 0) {
10533
10534                         if (initialSort === 'd' || initialSort === 'D') {
10535                             tempsort = nextSort
10536                             ctrl.sortData(msg, true, true);
10537                             nextSort = 'a';
10538                             $timeout(function(){
10539                                 if(!angular.isUndefined(elem[0].querySelector('.sortButton')) || elem[0].querySelector('.sortButton') !== null ){
10540                                     angular.element(elem[0].querySelector('.sortButton'))[0].focus();
10541                                 }   
10542                             },100);
10543                              
10544                         } else {
10545                             tempsort = nextSort
10546                             ctrl.sortData(msg, false, true);
10547                             nextSort = 'd';
10548                              $timeout(function(){
10549                                 if(!angular.isUndefined(elem[0].querySelector('.sortButton')) || elem[0].querySelector('.sortButton') !== null ){
10550                                     angular.element(elem[0].querySelector('.sortButton'))[0].focus();
10551                                 }   
10552                             },100);
10553
10554                              
10555                         }
10556                     }
10557                     },10)
10558
10559                 };
10560
10561                 scope.sortDropdown = function(msg) {
10562
10563                     if(tempsort==='') {
10564
10565                         tempsort='a'
10566                     }
10567                     if(tempsort === 'd' || tempsort === 'D' ) {
10568                         ctrl.sortData(msg, true, false);       
10569                     } else {
10570                        ctrl.sortData(msg, false, false);
10571                     }
10572
10573                 };
10574             }
10575         };
10576     }]);
10577 /**
10578  * @ngdoc directive
10579  * @name Tabs, tables & accordions.att:tabs
10580  *
10581  * @description
10582  *  <file src="src/tabs/docs/readme.md" />
10583  *
10584  * @usage
10585  *  <b2b-tabset tab-id-selected="activeTabsId">
10586         <b2b-tab ng-repeat="tab in gTabs" tab-item="tab" 
10587                  id="{{tab.uniqueId}}" aria-controls="{{tab.tabPanelId}}"
10588                  ng-disabled="tab.disabled">
10589             {{tab.title}}
10590         </b2b-tab>
10591     </b2b-tabset>
10592  *
10593  * @example
10594  *  <section id="code">
10595         <example module="b2b.att">
10596             <file src="src/tabs/docs/demo.html" />
10597             <file src="src/tabs/docs/demo.js" />
10598         </example>
10599     </section>
10600  *
10601  */
10602
10603 angular.module('b2b.att.tabs', ['b2b.att.utilities'])
10604     .directive('b2bTabset', function () {
10605         return {
10606             restrict: 'EA',
10607             transclude: true,
10608             replace: true,
10609             scope: {
10610                 tabIdSelected: '='
10611             },
10612             templateUrl: 'b2bTemplate/tabs/b2bTabset.html',
10613             controller: ['$scope', function ($scope) {
10614
10615                 this.setTabIdSelected = function (tab) {
10616                     $scope.tabIdSelected = tab.id;
10617                 };
10618
10619                 this.getTabIdSelected = function () {
10620                     return $scope.tabIdSelected;
10621                 };
10622             }]
10623         };
10624     })
10625     .directive('b2bTab', ['keymap', function (keymap) {
10626         return {
10627             restrict: 'EA',
10628             transclude: true,
10629             replace: true,
10630             require: '^b2bTabset',
10631             scope: {
10632                 tabItem: "="
10633             },
10634             templateUrl: 'b2bTemplate/tabs/b2bTab.html',
10635             controller: [function(){}],
10636             link: function (scope, element, attr, b2bTabsetCtrl) {
10637
10638                 if (scope.tabItem && !scope.tabItem.disabled) {
10639                     scope.tabItem.disabled = false;
10640                 }
10641
10642                 scope.isTabActive = function () {
10643                     return (scope.tabItem.id === b2bTabsetCtrl.getTabIdSelected());
10644                 };
10645
10646                 scope.clickTab = function () {
10647                     if (attr.disabled) {
10648                         return;
10649                     }
10650                     b2bTabsetCtrl.setTabIdSelected(scope.tabItem);
10651                 };
10652
10653                 scope.nextKey = function () {
10654                     var el = angular.element(element[0])[0];
10655                     var elementToFocus = null;
10656                     while (el && el.nextElementSibling) {
10657                         el = el.nextElementSibling;
10658                         if (!el.querySelector('a').disabled) {
10659                             elementToFocus = el.querySelector('a');
10660                             break;
10661                         }
10662                     }
10663
10664                     if (!elementToFocus) {
10665                         var childTabs = element.parent().children();
10666                         for (var i = 0; i < childTabs.length; i++) {
10667                             if (!childTabs[i].querySelector('a').disabled) {
10668                                 elementToFocus = childTabs[i].querySelector('a');
10669                                 break;
10670                             }
10671                         }
10672                     }
10673
10674                     if (elementToFocus) {
10675                         elementToFocus.focus();
10676                     }
10677                 };
10678
10679                 scope.previousKey = function () {
10680                     var el = angular.element(element[0])[0];
10681                     var elementToFocus = null;
10682
10683                     while (el && el.previousElementSibling) {
10684                         el = el.previousElementSibling;
10685                         if (!el.querySelector('a').disabled) {
10686                             elementToFocus = el.querySelector('a');
10687                             break;
10688                         }
10689                     }
10690
10691                     if (!elementToFocus) {
10692                         var childTabs = element.parent().children();
10693                         for (var i = childTabs.length - 1; i > 0; i--) {
10694                             if (!childTabs[i].querySelector('a').disabled) {
10695                                 elementToFocus = childTabs[i].querySelector('a');
10696                                 break;
10697                             }
10698                         }
10699                     }
10700
10701                     if (elementToFocus) {
10702                         elementToFocus.focus();
10703                     }
10704                 };
10705
10706                 angular.element(element[0].querySelector('a')).bind('keydown', function (evt) {
10707
10708                     if (!(evt.keyCode)) {
10709                         evt.keyCode = evt.which;
10710                     }
10711
10712                     switch (evt.keyCode) {
10713                         case keymap.KEY.RIGHT:
10714                             evt.preventDefault();
10715                             scope.nextKey();
10716                             break;
10717
10718                         case keymap.KEY.LEFT:
10719                             evt.preventDefault();
10720                             scope.previousKey();
10721                             break;
10722
10723                         default:;
10724                     }
10725                 });
10726             }
10727         };
10728     }]);
10729 /**
10730  * @ngdoc directive
10731  * @name Messages, modals & alerts.att:tagBadges
10732  *
10733  * @description
10734  *  <file src="src/tagBadges/docs/readme.md" />
10735  *
10736  * @example
10737  *  <section id="code">
10738         <example module="b2b.att">
10739             <file src="src/tagBadges/docs/demo.html" />
10740             <file src="src/tagBadges/docs/demo.js" />
10741         </example>
10742     </section>
10743  *
10744  */
10745 angular.module('b2b.att.tagBadges', ['b2b.att.utilities'])
10746         .directive('b2bTagBadge',['$timeout',function($timeout){
10747             return{
10748                 restrict: 'EA',
10749                 link: function(scope,elem,attr,ctrl){
10750                     elem.addClass('b2b-tags');
10751                     if(angular.element(elem[0].querySelector('.icon-primary-close')).length>0) {
10752                         var item = angular.element(elem[0].querySelector('.icon-primary-close'));
10753                         item.bind('click',function(){
10754                         elem.css({'height':'0','width':'0','padding':'0','border':'0'});
10755                         elem.attr('tabindex','0');
10756                         elem[0].focus();
10757                         item.parent().remove();
10758                         elem[0].bind('blur',function(){
10759                             elem[0].remove();
10760                         });
10761                     });  
10762                     }
10763                   
10764
10765
10766
10767                 }
10768             };   
10769 }]);
10770 /**
10771  * @ngdoc directive
10772  * @name Forms.att:textArea
10773  *
10774  * @description
10775  *  <file src="src/textArea/docs/readme.md" />
10776  *
10777  * @usage
10778  *  <textarea b2b-reset b2b-reset-textarea ng-model="textAreaModel" ng-disabled="disabled" ng-trim="false" placeholder="{{placeholderText}}" rows="{{textAreaRows}}" maxlength="{{textAreaMaxlength}}" role="textarea"></textarea>
10779  *
10780  * @example
10781     <section id="code">
10782         <b>HTML + AngularJS</b>
10783         <example module="b2b.att">
10784             <file src="src/textArea/docs/demo.html" />
10785             <file src="src/textArea/docs/demo.js" />
10786         </example>
10787     </section>
10788  */
10789 angular.module('b2b.att.textArea', ['b2b.att.utilities'])
10790
10791 .directive('b2bResetTextarea', [ function () {
10792     return {
10793         restrict: 'A',
10794         require: 'b2bReset',
10795         link: function (scope, element, attrs, ctrl) {
10796
10797             var resetButton = ctrl.getResetButton();
10798             
10799             var computeScrollbarAndAddClass = function () {
10800                 if (element.prop('scrollHeight') > element[0].clientHeight) {
10801                     element.addClass('hasScrollbar');
10802                 } else {
10803                     element.removeClass('hasScrollbar');
10804                 }
10805             };
10806             
10807             computeScrollbarAndAddClass();
10808
10809             element.on('focus keyup', function(){
10810                 computeScrollbarAndAddClass();
10811             });
10812         }
10813     };
10814 }]);
10815
10816 /**
10817  * @ngdoc directive
10818  * @name Forms.att:timeInputField
10819  *
10820  * @description
10821  *  <file src="src/timeInputField/docs/readme.md" />
10822  *
10823  
10824  * @example
10825  *  <section id="code">
10826         <example module="b2b.att">
10827             <file src="src/timeInputField/docs/demo.html" />
10828             <file src="src/timeInputField/docs/demo.js" />
10829        </example>
10830     </section>
10831  *
10832  */
10833 angular.module('b2b.att.timeInputField',['ngMessages', 'b2b.att.utilities']).directive('b2bTimeFormat',function(){
10834     return{
10835         restrict : 'A',
10836         require : '^ngModel',
10837         link : function(scope,elem,attr,ctrl){
10838             elem.on('keyup',function(evt){
10839                 var modelValue = ctrl.$modelValue;
10840                 var format = attr.b2bTimeFormat;
10841                  modelValue = modelValue.split(':');
10842                 if(format == "12"){
10843                     if(!(modelValue[0] <= 12 && modelValue[0] > 0 ) || !(modelValue[1] <= 59)){
10844                         ctrl.$setValidity('inValidTime',false);   
10845                     }else{
10846                         ctrl.$setValidity('inValidTime',true);
10847                     }
10848                 }else if(format =="24"){
10849                     if(!(modelValue[0] <= 23) || !(modelValue[1] <= 59)){
10850                         ctrl.$setValidity('inValidTime',false);
10851                     }else{
10852                         ctrl.$setValidity('inValidTime',true);
10853                     }
10854                 }                
10855                scope.$apply();
10856             });
10857         }
10858     }
10859 });
10860
10861 /**
10862  * @ngdoc directive
10863  * @name Forms.att:tooltipsForForms
10864  *
10865  * @description
10866  *  <file src="src/tooltipsForForms/docs/readme.md" />
10867  *
10868  * @example
10869  <example module="b2b.att">
10870  <file src="src/tooltipsForForms/docs/demo.html" />
10871  <file src="src/tooltipsForForms/docs/demo.js" />
10872  </example>
10873  */
10874 angular.module('b2b.att.tooltipsForForms', ['b2b.att.utilities'])
10875         .directive('b2bTooltip', ['$document', '$window', '$isElement', function ($document, $window, $isElement) {
10876                 return  {
10877                     restrict: 'A',
10878                     link: function (scope, elem, attr, ctrl) {
10879                         var icon = elem[0].querySelector('a.tooltip-element');
10880                         var btnIcon = elem[0].querySelector('.btn.tooltip-element');
10881                         var tooltipText = elem[0].querySelector('.helpertext');
10882                         var tooltipWrapper = elem[0].querySelector('.tooltip-size-control');
10883                         if (elem.hasClass('tooltip-onfocus')) {
10884                             var inputElm = angular.element(elem[0].querySelector("input"));
10885                             var textAreaElm = angular.element(elem[0].querySelector("textarea"));
10886                         }
10887                         angular.element(icon).attr({'aria-expanded': false});
10888                         angular.element(btnIcon).attr({'aria-expanded': false});
10889                         var calcTooltip = function () {
10890                             if (!elem.hasClass('tooltip active')) {
10891                                 if (elem.hasClass('tooltip-onfocus')) {
10892                                     angular.element(elem[0].querySelector("input")).triggerHandler('focusout');
10893                                 }
10894                                 if (elem.hasClass('tooltip-onclick')) {
10895                                     return false;
10896                                 }
10897                                 angular.element(icon).removeClass('active');
10898                                 angular.element(icon).attr({'aria-expanded': true});
10899                                 angular.element(icon).attr({'aria-describedby': angular.element(tooltipText).attr('id')});
10900                                 angular.element(tooltipText).attr({'aria-hidden': false});
10901                                 elem.addClass('active');
10902
10903                                 var tooltipIconPos = angular.element(icon).prop('offsetLeft'),
10904                                         tooltipPosition = angular.element(tooltipText).prop('offsetWidth') / 2,
10905                                         tipOffset = (tooltipIconPos - 30) - tooltipPosition,
10906                                         maxRightPos = (($window.innerWidth - 72) - (tooltipPosition * 2)) - 14.5;
10907
10908                                 if ($window.innerWidth >= '768') {
10909                                     if (tipOffset < 0) {// if icon on far left side of page
10910                                         tipOffset = 15;
10911                                     }
10912                                     else if (tooltipIconPos > maxRightPos) {// if icon is far right side of page
10913                                         tipOffset = maxRightPos;
10914                                     }
10915                                     else {// if tooltip in the middle somewhere
10916                                         tipOffset = tipOffset;
10917                                     }
10918                                     angular.element(tooltipWrapper).css({left: tipOffset + 'px'});
10919                                 }
10920                             }
10921                         };
10922                         
10923                         // TOOLTIP LINK ONCLICK AND FOCUS
10924                         angular.element(icon).on('click mouseover mouseout focus blur', function (e) {
10925                             if (e.type == 'mouseover') {
10926                                 calcTooltip();
10927                             }
10928                             else if (e.type == 'mouseout' && elem.hasClass('active')) {
10929                                 if (!elem.hasClass('activeClick')) {
10930                                     angular.element(tooltipText).attr({
10931                                         'aria-hidden': true,
10932                                         'tabindex': '-1'
10933                                     });
10934                                     elem.removeClass('active');
10935                                 } else if (elem.hasClass('activeClick') && navigator.userAgent.match(/iphone/i)) {
10936                                     elem.removeClass('active activeClick');
10937                                 }
10938                             }
10939
10940                             else {
10941                                 if (elem.hasClass('activeClick')) {
10942                                     angular.element(icon).attr({'aria-expanded': false});
10943                                     angular.element(tooltipText).attr({'aria-hidden': true});
10944                                     angular.element(icon).removeAttr('aria-describedby');
10945                                     elem.removeClass('activeClick active');
10946                                     e.preventDefault();
10947                                 }
10948                                 else if (e.type == 'click') {
10949                                     elem.addClass('activeClick');
10950                                     calcTooltip();
10951                                     e.preventDefault();
10952                                 }
10953                                 else {
10954                                     angular.element(icon).on('keydown', function (e) {
10955                                         if (e.keyCode == '32') {
10956                                             (elem.hasClass('active')) ? elem.removeClass('active') : elem.addClass('value');
10957                                             angular.element(icon).triggerHandler('click');
10958                                             e.preventDefault();
10959                                         } else if (e.keyCode == '27') {
10960                                             (elem.hasClass('active')) ? elem.removeClass('active activeClick') : elem.addClass('value');
10961                                         }
10962                                     });
10963                                     e.preventDefault();
10964                                 }
10965                             }
10966                             e.preventDefault();
10967                         });
10968
10969                         // TOOLTIP BUTTON INSIDE A TEXT FIELD
10970                         angular.element(btnIcon).on('click', function (e) {
10971                             var $this = angular.element(this);
10972                             if ($this.hasClass('active') && elem.hasClass('tooltip-onclick')) {
10973                                 elem.removeClass('active');
10974                                 $this.removeClass('active');
10975                                 angular.element(tooltipText).removeAttr('aria-live');
10976                                 $this.attr({'aria-expanded': 'false'});
10977                                 $this.removeAttr('aria-describedby');
10978                             } else {
10979                                 elem.addClass('active');
10980                                 $this.addClass('active');
10981                                 $this.attr({'aria-expanded': 'true', 'aria-describedby': angular.element(tooltipText).attr('id')});
10982                                 angular.element(tooltipText).attr({'aria-live': 'polite'});
10983                             }
10984                         });
10985
10986                         angular.element(btnIcon).on('blur', function (e) {
10987                             var $this = angular.element(this);
10988                             if ($this.hasClass('active') && elem.hasClass('tooltip-onclick')) {
10989                                 elem.removeClass('active');
10990                                 $this.removeClass('active');
10991                                 angular.element(tooltipText).removeAttr('aria-live');
10992                                 $this.attr({'aria-expanded': 'false'});
10993                                 $this.removeAttr('aria-describedby');
10994                             }
10995                         });  
10996
10997                         angular.element(btnIcon).on('keydown', function (e) {
10998                             var $this = angular.element(this);
10999                             if (e.keyCode == '27') {
11000                                 var $this = angular.element(this);
11001                                 if ($this.hasClass('active') && elem.hasClass('tooltip-onclick')) {
11002                                     elem.removeClass('active');
11003                                     $this.removeClass('active');
11004                                     angular.element(tooltipText).removeAttr('aria-live');
11005                                     $this.attr({'aria-expanded': 'false'});
11006                                     $this.removeAttr('aria-describedby');
11007                                 }
11008                             }
11009                         });
11010
11011                         // close all tooltips if clicking something else
11012                         $document.bind('click', function (e) {
11013                             var isElement = $isElement(angular.element(e.target), elem, $document);
11014                             if (!isElement) {
11015                                 elem.removeClass('active');
11016                                 angular.element(elem[0].querySelector('.tooltip-element')).removeClass('active');
11017                                 angular.element(tooltipText).removeAttr('aria-live');
11018                                 angular.element(elem[0].querySelector('.tooltip-element')).attr({'aria-expanded': 'false'});
11019                                 angular.element(elem[0].querySelector('.tooltip-element')).removeAttr('aria-describedby');
11020                             };
11021                         });
11022
11023                         angular.element(inputElm).on('keydown', function (e) {
11024                             if (e.keyCode == '27'){
11025                                 elem.removeClass('active');
11026                                 angular.element(tooltipText).css('display', 'none');
11027                                 angular.element(tooltipText).removeAttr('aria-live');
11028
11029                                 if (angular.element(this).attr('aria-describedby') === undefined){
11030
11031                                 }
11032
11033                                 else if ((spaceIndex = angular.element(this).attr('aria-describedby').lastIndexOf(' ')) >= 0){
11034
11035                                     var describedByValue = angular.element(this).attr('aria-describedby').slice(0, spaceIndex);
11036
11037                                     angular.element(this).attr('aria-describedby', describedByValue);
11038
11039                                 }
11040                                 else {
11041                                     angular.element(this).removeAttr('aria-describedby');
11042                                 }
11043                             }
11044                         });
11045
11046                         angular.element(textAreaElm).on('keydown', function (e) {
11047                             if (e.keyCode == '27'){
11048                                 elem.removeClass('active');
11049                                 angular.element(tooltipText).css('display', 'none');
11050                                 angular.element(tooltipText).removeAttr('aria-live');
11051                                 if (angular.element(this).attr('aria-describedby') === undefined){
11052
11053                                 }
11054
11055                                 else if ((spaceIndex = angular.element(this).attr('aria-describedby').lastIndexOf(' ')) >= 0){
11056
11057                                     var describedByValue = angular.element(this).attr('aria-describedby').slice(0, spaceIndex);
11058
11059                                     angular.element(this).attr('aria-describedby', describedByValue);
11060
11061                                 }
11062                                 else {
11063                                     angular.element(this).removeAttr('aria-describedby');
11064                                 }
11065                             }
11066                         });
11067
11068                         // TOOLTIP TRIGGERED AUTOMATICALLY INSIDE A TEXT FIELD
11069                         angular.element(inputElm).on('focus', function (e) {
11070                             var allTooltip = $document[0].querySelectorAll('[class*="tooltip"]');
11071                             for (var i = 0; i < allTooltip.length; i++) {
11072                                 if (angular.element(allTooltip[i]).hasClass('active')) {
11073                                     angular.element(allTooltip[i]).triggerHandler('click');
11074                                 }
11075                             };
11076                             angular.element(this).attr({'aria-describedby': angular.element(tooltipText).attr('id')});
11077                             angular.element(tooltipText).css('display', 'block');
11078                             angular.element(tooltipText).attr({'aria-live': 'polite'});
11079                             elem.addClass('active');
11080                         });
11081                         angular.element(inputElm).on('blur', function (e) {
11082                             elem.removeClass('active');
11083                             angular.element(tooltipText).css('display', 'none');
11084                             angular.element(tooltipText).removeAttr('aria-live');
11085                             angular.element(this).removeAttr('aria-describedby');
11086                         });
11087
11088                         // TOOLTIP TRIGGERED AUTOMATICALLY INSIDE A TEXTAREA
11089                         angular.element(textAreaElm).on('focus', function (e) {
11090                             var allTooltip = $document[0].querySelectorAll('[class*="tooltip"]');
11091                             for (var i = 0; i < allTooltip.length; i++) {
11092                                 if (angular.element(allTooltip[i]).hasClass('active')) {
11093                                     angular.element(allTooltip[i]).triggerHandler('click');
11094                                 }
11095                             };
11096                             elem.addClass('active');
11097                             angular.element(tooltipText).css('display', 'block');
11098                             angular.element(tooltipText).attr({'aria-live': 'polite'});
11099                             angular.element(this).attr({'aria-describedby': angular.element(tooltipText).attr('id')});
11100                         });
11101                         angular.element(textAreaElm).on('blur', function (e) {
11102                             elem.removeClass('active');
11103                             angular.element(tooltipText).css('display', 'none');
11104                             angular.element(tooltipText).removeAttr('aria-live');
11105                             angular.element(this).removeAttr('aria-describedby');
11106                         });
11107                     }
11108                 };
11109             }]); 
11110 /**
11111  * @ngdoc directive
11112  * @name Navigation.att:TreeNavigation
11113  *
11114  *
11115  * @scope
11116  * @param {String} setRole - This value needs to be "tree". This is required to incorporate CATO requirements.
11117  * @param {Boolean} groupIt - This value needs to be "false" for top-level tree rendered.
11118  *
11119  * @description
11120  *  <file src="src/treeNav/docs/readme.md" />
11121  *
11122  * @usage
11123  *      <div class="b2b-tree">
11124  *                <b2b-tree-nav collection="treeStructure" set-role="tree" group-it="false"></b2b-tree-nav>
11125  *            </div>
11126  * @example
11127  *  <section id="code">
11128         <example module="b2b.att">
11129             <file src="src/treeNav/docs/demo.html" />
11130             <file src="src/treeNav/docs/demo.js" />
11131        </example>
11132     </section>
11133  *
11134  */
11135 angular.module('b2b.att.treeNav', ['b2b.att.utilities'])
11136     .directive('b2bTreeNav', function () {
11137         return {
11138             restrict: "E",
11139             replace: true,
11140             scope: {
11141                 collection: '=',
11142                 groupIt: '=',
11143                 setRole: '@'
11144             },
11145             templateUrl: function (element, attrs) {
11146                 if (attrs.groupIt === 'true') {
11147                     return "b2bTemplate/treeNav/groupedTree.html";
11148                 } else {
11149                     return "b2bTemplate/treeNav/ungroupedTree.html";
11150                 }
11151             },
11152             link: function (scope) {               
11153                 if (!(scope.setRole === 'tree')) {
11154                     scope.setRole = 'group';
11155                 }             
11156             }
11157         }
11158     })
11159     .directive('b2bMember', ['$compile', '$timeout', 'keymap', function ($compile, $timeout, keymap) {
11160         return {
11161             restrict: "E",
11162             replace: true,
11163             scope: {
11164                 member: '=',
11165                 groupIt: '='
11166             },
11167             templateUrl: 'b2bTemplate/treeNav/treeMember.html',
11168             link: function (scope, element, attrs) {
11169                 scope.elemArr = [];
11170                 var removeRootTabIndex = function (elem) {
11171                     if (elem.parent().parent().eq(0).hasClass('b2b-tree')) {
11172                         elem.attr('tabindex', -1);                        
11173                         return;
11174                     }
11175                     removeRootTabIndex(elem.parent());
11176                 };
11177                                 scope.$watch('member.child', function(newVal, oldVal){                                  
11178                                         if(newVal !== oldVal){
11179                                                 scope.showChild();
11180                                         };
11181                                 });
11182                 scope.showChild = function () {
11183                         if (!element.hasClass('grouped')) {
11184                             if (angular.isArray(scope.member.child) && scope.member.child.length > 0 && (scope.member.divide === undefined || scope.member.child.length < scope.member.divide)) {
11185                                 scope.groupIt = false;
11186                                 element.addClass('grouped');
11187                                 element.append("<b2b-tree-nav collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-nav>");
11188                                 $compile(element.contents())(scope);
11189                                 if(scope.member.active && scope.member.active === true){
11190                                     element.find('i').eq(0).removeClass('icon-primary-collapsed');
11191                                 };
11192                                 if(scope.member.selected && scope.member.selected === true){
11193                                     element.attr('aria-selected', true);
11194                                     element.attr('tabindex', 0);
11195                                     removeRootTabIndex(element);
11196                                 };
11197                                 if(scope.member.active && scope.member.active == undefined){
11198                                     element.find('i').eq(0).addClass('icon-primary-collapsed');
11199                                 };
11200                             } else if (scope.member.child && scope.member.divide && scope.member.child.length > scope.member.divide) {
11201                                 element.addClass('grouped');
11202                                 scope.groupIt = true;
11203                                 // FILTER - GROUPBY - APPROACH 
11204                                 var j = 0;
11205                                 var grpName = '';
11206                                 if(scope.member.child[0].groupName !== undefined){
11207                                     grpName = scope.member.child[0].groupName;
11208                                 }
11209                                 else{
11210                                     var toSlice = scope.member.child[0].name.search(' ');
11211                                     grpName = scope.member.child[0].name.slice(0, toSlice);
11212                                 }
11213
11214                                 for (i = 0; i < scope.member.child.length; i += scope.member.divide) {
11215                                     j = 0;
11216                                     for (j = j + i; j < (i + scope.member.divide); j++) {                                        
11217                                         if (j === scope.member.child.length) {
11218                                             scope.member.child[j - 1].grpChild = grpName + ' ' + (i + 1) + ' - ' + (scope.member.child.length);
11219                                             break;
11220                                             
11221                                             if(scope.member.child[j-1].active && scope.member.child[j-1].active===true){
11222                                                 scope.member.child[j-1].activeGrp = true;
11223                                             };
11224                                             
11225                                         }
11226                                         if (i + scope.member.divide > scope.member.child.length) {
11227                                             scope.member.child[j].grpChild = grpName + ' ' + (i + 1) + ' - ' + (scope.member.child.length);
11228                                             if(scope.member.child[j].active && scope.member.child[j].active===true){
11229                                                 scope.member.child[j].activeGrp = true;
11230                                             };
11231
11232                                         } else {
11233                                             scope.member.child[j].grpChild = grpName + ' ' + (i + 1) + ' - ' + (i + scope.member.divide);
11234                                             if(scope.member.child[j].active && scope.member.child[j].active===true){
11235                                                 scope.member.child[j].activeGrp = true;
11236                                             };
11237                                         }
11238                                     }
11239                                 }
11240                                                                 if(scope.member.divide){
11241                                                                         element.append("<b2b-tree-nav collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-nav>");
11242                                                                 } else {
11243                                                                         element.append("<b2b-tree-nav collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-nav>");
11244                                                                 }
11245                                 $compile(element.contents())(scope);
11246                                 if(scope.member.active && scope.member.active === true){
11247                                     element.find('i').eq(0).removeClass('icon-primary-collapsed');
11248                                 };
11249                                 if(scope.member.selected && scope.member.selected === true){
11250                                     element.attr('aria-selected', true);
11251                                 };
11252                                 if( scope.member.active && scope.member.active == undefined){
11253                                     element.find('i').eq(0).addClass('icon-primary-collapsed');
11254                                 };
11255                             }
11256                         }
11257                 };
11258                                 //Below condition opens node for opening on json load.
11259                 if(scope.member.active && scope.member.active == true){
11260                     scope.showChild();
11261                 };
11262                 if(scope.member.active == undefined && !element.find('a').eq(0).hasClass('active') && scope.member.child !== undefined){
11263                     element.find('i').eq(0).addClass('icon-primary-collapsed');
11264                 }
11265                 else if(scope.member.child == undefined){
11266                     element.find('i').eq(0).addClass('icon-primary-circle');
11267                 };
11268                 element.bind('keydown', function (evt) {
11269                     switch (evt.keyCode) {
11270                         case keymap.KEY.ENTER:
11271                             if (element.hasClass('bg') && scope.member.onSelect !== undefined) {
11272                                 scope.member.onSelect(scope.member);
11273                             }
11274                             evt.stopPropagation();
11275                             break;
11276                         default: 
11277                             break;                            
11278                     }
11279                     
11280                 });
11281                 //else getting true in every case .. so better use switch case .. that makes more sense you dumb.
11282                 element.bind('click', function (evt) {
11283                                         scope.showChild();
11284                                         var expandFunc = scope.member.onExpand;
11285                                         
11286                     //onSelect
11287                         if (element.hasClass('bg') && scope.member.onSelect !== undefined) {
11288                                     scope.member.onSelect(scope.member);
11289                                 }
11290                         if (element.find('a').eq(0).hasClass('active') && scope.member.onExpand !== undefined) {
11291                            var eValue = scope.member.onExpand(scope.member);
11292                         }
11293                         if (!element.find('a').eq(0).hasClass('active') && scope.member.onCollapse !== undefined) {
11294                             scope.member.onCollapse(scope.member);
11295                         }
11296                 });
11297             }
11298         }
11299 }])
11300     .directive('b2bTreeLink', ['keymap', '$timeout', function (keymap, $timeout) {
11301         return {
11302             restrict: 'A',
11303             link: function (scope, element, attr, ctrl) {
11304                 var rootE, parentE, upE, downE;
11305                 var closeOthersUp = function (elem,isKeyPress,passiveClose) {
11306                     //For accordion functionality on sibling nodes
11307                     if (elem.find('a').eq(0).hasClass('active')) {
11308                         activeToggle(elem,isKeyPress,passiveClose);
11309                         return;
11310                     }
11311                     if (elem.hasClass('bg') && !isKeyPress) {
11312                         elem.removeClass('bg');
11313                         if (elem.attr('aria-selected')) {
11314                             elem.attr('aria-selected', 'false');
11315                         }                        
11316                     }
11317                     if (elem[0].previousElementSibling !== null) {
11318                         closeOthersUp(angular.element(elem[0].previousElementSibling),isKeyPress);
11319                     }
11320                 };
11321                 var closeOthersDown = function (elem,isKeyPress,passiveClose) {
11322                     //For accordion functionality on sibling nodes
11323                     if (elem.find('a').eq(0).hasClass('active')) {
11324                         activeToggle(elem,isKeyPress,passiveClose);
11325                         return;
11326                     }
11327                     if (elem.hasClass('bg') && !isKeyPress) {
11328                         elem.removeClass('bg');
11329                         if (elem.attr('aria-selected')) {
11330                             elem.attr('aria-selected', 'false');
11331                         }                        
11332                     }
11333                     if (elem[0].nextElementSibling !== null) {
11334                         closeOthersDown(angular.element(elem[0].nextElementSibling),isKeyPress);
11335                     }
11336                 };
11337
11338                
11339                 var removeBackground = function(elem){
11340
11341                     if(elem.hasClass('b2b-tree')){
11342                         angular.element(elem[0].getElementsByClassName('bg')).removeClass('bg');
11343                         return;
11344                     }else{
11345                         removeBackground(elem.parent().parent());
11346                     }
11347
11348                 };
11349
11350 /**
11351 * These two functions used for setting heights on parent nodes as the child node closes
11352 * Retaining this code for future reference
11353
11354                 var addParentHeight = function(e, h) {
11355                     var parentLi = e.parent().parent();
11356                     var parentUl = e.parent();
11357                     if(!parentLi.hasClass('b2b-tree')) {
11358                         var addHeight = parentUl[0].offsetHeight + h;
11359                         parentLi.find('ul').eq(0).css({
11360                             height: addHeight+'px'
11361                         })
11362                         addParentHeight(parentLi, h);
11363                     }                    
11364                 };
11365
11366                 var removeParentHeight = function(e, h) {
11367                     var parentLi = e.parent().parent();
11368                     var parentUl = e.parent();
11369                     if(!parentLi.hasClass('b2b-tree')) {
11370                         var addHeight = parentUl[0].offsetHeight - h;
11371                         parentLi.find('ul').eq(0).css({
11372                             height: addHeight+'px'
11373                         })
11374                         removeParentHeight(parentLi, h);
11375                     }
11376                 };
11377 */          
11378
11379             // isKeyPress - to notify that the function is called by Right Key press
11380             // passiveClose -  prevents firing of oncollapse events during the action
11381             // of expand function(check the function definition)
11382
11383                 var activeToggle = function (elem,isKeyPress,passiveClose) {
11384                     var element = elem.find('a').eq(0);
11385                     if (element.hasClass('active')) {
11386                         if(!isKeyPress){
11387                             elem.removeClass('bg');
11388                         }
11389                         
11390                         if (elem.attr('aria-selected') && !isKeyPress) {
11391                             elem.attr('aria-selected', 'false');
11392                         }
11393                         if (!element.find('i').eq(0).hasClass('icon-primary-circle')) {
11394                             if(isKeyPress && scope.member){
11395                                 if (scope.member.onCollapse !== undefined && !passiveClose) {
11396                                     scope.member.onCollapse(scope.member);
11397                                 }
11398                             }
11399                             element.removeClass('active');
11400                             elem.attr('aria-expanded', 'false');
11401                             element.find('i').eq(0).removeClass('icon-primary-expanded');
11402                             element.find('i').eq(0).addClass('icon-primary-collapsed');
11403                             //For Animation: below commented code is used to manually set height of UL to zero 
11404                             //retaining code for future reference
11405                             /*
11406                             var totalHeight = elem.find('ul')[0].scrollHeight;
11407                             removeParentHeight(elem, totalHeight);
11408                             elem.find('ul').eq(0).css({
11409                                 height: null
11410                             });*/
11411                         }
11412                     } else {
11413                         if(!isKeyPress){
11414                             elem.addClass('bg');
11415                             elem.attr('aria-selected', 'true');
11416                         }
11417                         
11418                         if (!element.find('i').eq(0).hasClass('icon-primary-circle')) {
11419                             if(isKeyPress){
11420                                 if(typeof scope.showChild === 'function' ){
11421                                 scope.showChild();
11422                                 }
11423                                 if(scope.member){
11424                                     if (scope.member.onExpand !== undefined) {
11425                                         scope.member.onExpand(scope.member);
11426                                     }
11427                                 }
11428                             }
11429                             element.addClass('active');
11430                             elem.attr('aria-expanded', 'true');
11431                             element.find('i').eq(0).removeClass('icon-primary-collapsed');
11432                             element.find('i').eq(0).addClass('icon-primary-expanded');
11433                             //For Animation: below commented code is used to manually set height of the ul generatedon the click of parent LI.
11434                             //retaining code for future reference
11435                             /*                            
11436                             var totalHeight = elem.find('ul')[0].scrollHeight;
11437                             addParentHeight(elem, totalHeight);
11438                             elem.find('ul').eq(0).css({
11439                                 height: totalHeight+'px'
11440                             });*/
11441                             
11442                         }
11443                     }
11444                 };
11445                 element.bind('click', function (evt) {
11446                     //first we close others and then we open the clicked element
11447                                         if (element[0].previousElementSibling) {
11448                                                 closeOthersUp(angular.element(element[0].previousElementSibling));
11449                                         }
11450                                         if (element[0].nextElementSibling) {
11451                                                 closeOthersDown(angular.element(element[0].nextElementSibling));
11452                                         }
11453                     removeBackground(element);
11454                                         activeToggle(element);                    
11455                     
11456                     evt.stopPropagation();                    
11457                 });
11458                 //default root tree element tabindex set zero
11459                 if (element.parent().parent().hasClass('b2b-tree') && (element.parent()[0].previousElementSibling === null)) {
11460                     element.attr('tabindex', 0);
11461                 }
11462                 //check root via class
11463                 var isRoot = function (elem) {
11464                     if (elem.parent().parent().eq(0).hasClass('b2b-tree')) {
11465                         return true;
11466                     } else {
11467                         return false;
11468                     }
11469                 };
11470                 var findRoot = function (elem) {
11471                     if (isRoot(elem)) {
11472                         rootE = elem;
11473                         return;
11474                     }
11475                     findRoot(elem.parent());
11476                 };
11477
11478                 var findPreActive = function (elem) {
11479
11480                     if (!(elem.hasClass("active"))) {
11481                         return;
11482                     } else {
11483                         var childElems = angular.element(elem[0].nextElementSibling.children);
11484                         lastE = angular.element(childElems[childElems.length - 1]);
11485                         if (lastE.find('a').eq(0).hasClass('active')) {
11486                             findPreActive(lastE.find('a').eq(0));
11487                         }
11488                         upE = lastE;
11489                     }
11490                 };
11491
11492                 var findUp = function (elem) {
11493                     if (isRoot(elem)) {
11494                         upE = elem;
11495                         return;
11496                     }
11497                     if (elem[0].previousElementSibling !== null && !angular.element(elem[0].previousElementSibling).hasClass('tree-hide')) {
11498                         upE = angular.element(elem[0].previousElementSibling);
11499                         if (upE.find('a').eq(0).hasClass('active')) {
11500                             findPreActive(upE.find('a').eq(0));
11501                         }
11502                     } else {
11503                         upE = elem.parent().parent();
11504                     }
11505                 };
11506
11507                 var downElement = function (elem) {
11508                     if (elem.next().hasClass('tree-hide')) {
11509                         downElement(elem.next());
11510                     } else {
11511                         downE = elem.next();
11512                     }
11513                 }
11514                 var isBottomElem = false;
11515                 var downParent = function(liElem){
11516                     if(liElem.eq(0).parent().parent().eq(0).hasClass('b2b-tree')){
11517                         isBottomElem = true;
11518                         return;
11519                     }
11520                     if(liElem.next().length !== 0){
11521                         downE = liElem.next().eq(0);
11522                         return;
11523                     }
11524                     else {
11525                         downParent(liElem.parent().parent());
11526                     }
11527                 }
11528                 
11529                 var findDown = function (elem) {
11530                     if (isRoot(elem.parent()) && !elem.hasClass('active')) {
11531                         downE = elem.parent();
11532                         return;
11533                     }
11534                     if (elem.hasClass('active')) {
11535                         downE = elem.next().find('li').eq(0);
11536                         if (downE.hasClass('tree-hide')) {
11537                             downElement(downE);
11538                         }
11539
11540                     } else {
11541                         downParent(elem.parent());
11542                         if(isBottomElem === true){
11543                             downE = elem.parent();
11544                             isBottomElem = false;
11545                         }
11546                     }
11547                 };
11548
11549
11550                 var resetTabPosition = function(element){
11551                     findRoot(element);
11552                     angular.element(rootE.parent().parent()[0].querySelector("li[tabindex='0']")).attr('tabindex','-1');
11553                     var elemToFocus =  rootE.parent().parent()[0].querySelector(".bg")|| rootE;
11554
11555                     angular.element(elemToFocus).attr('tabindex','0');
11556                 };
11557                 // Function to control the expansion of nodes when the user tabs into the tree and
11558                 // the slected node is not visible
11559                 var expand = function(elemArr){
11560                     var elem= elemArr.pop();
11561                     var element = elem.find('a').eq(0);                    
11562                     var selectedNode = elem.parent().parent()[0].querySelector(".bg");
11563                     if(selectedNode != null){
11564                         while(elem){
11565                              element = elem.find('a').eq(0);
11566                     if(!element.hasClass('active') ){
11567
11568
11569                     if (elem[0].previousElementSibling) {
11570                         closeOthersUp(angular.element(elem[0].previousElementSibling),true,true);
11571                         }
11572                         if (elem[0].nextElementSibling) {
11573                             closeOthersDown(angular.element(elem[0].nextElementSibling),true,true);
11574                         }
11575
11576                          if (!element.find('i').eq(0).hasClass('icon-primary-circle')) {
11577                             if(typeof scope.showChild === 'function' ){
11578                                 scope.showChild();
11579                             }
11580                             element.addClass('active');
11581                             elem.attr('aria-expanded', 'true');
11582                             element.find('i').eq(0).removeClass('icon-primary-collapsed');
11583                             element.find('i').eq(0).addClass('icon-primary-expanded');
11584                             }
11585                           
11586                           }   
11587                           elem = elemArr.pop();
11588                         }                      
11589                         
11590                     }else{
11591                         return;
11592                     }                   
11593                 };
11594
11595                 element.find('a').eq(0).bind('mouseenter', function (evt) {
11596                     angular.forEach(document.querySelectorAll('.activeTooltip'), function(value, key) {
11597                         angular.element(value).removeClass('activeTooltip') 
11598                     });
11599                     element.addClass('activeTooltip');
11600                 });
11601                 element.find('a').eq(0).bind('mouseleave', function (evt) {
11602                     element.removeClass('activeTooltip');
11603                 });
11604                 element.bind('focus', function (evt) {
11605                     angular.forEach(document.querySelectorAll('.activeTooltip'), function(value, key) {
11606                         angular.element(value).removeClass('activeTooltip') 
11607                     });
11608                     element.addClass('activeTooltip');
11609                 });
11610                 element.bind('blur', function (evt) {
11611                     element.removeClass('activeTooltip');
11612                 });
11613                 element.bind('keydown', function (evt) {
11614                     switch (evt.keyCode) {
11615                     case keymap.KEY.HOME:
11616                         evt.preventDefault();
11617                         evt.stopPropagation();
11618                         element.attr('tabindex', -1);
11619                         findRoot(element);
11620                         rootE.eq(0).attr('tabindex', 0);
11621                         rootE[0].focus();
11622                         break;
11623                     case keymap.KEY.LEFT:
11624                         evt.preventDefault();
11625                         evt.stopPropagation(); 
11626                       
11627                         if(element.find('a').eq(0).hasClass('active')){
11628                             if (element[0].previousElementSibling) {
11629                                 closeOthersUp(angular.element(element[0].previousElementSibling),true);
11630                             }
11631                             if (element[0].nextElementSibling) {
11632                                 closeOthersDown(angular.element(element[0].nextElementSibling),true);
11633                              }
11634                              activeToggle(element,true);
11635                                 return;
11636                         }
11637                             element.attr('tabindex', -1);
11638                             parentE = element.parent().parent();
11639                             parentE.attr('tabindex', 0);
11640                             parentE[0].focus();
11641                         break;
11642                     case keymap.KEY.UP:
11643                         evt.preventDefault();
11644                         evt.stopPropagation();
11645                         element.attr('tabindex', -1);
11646                         findUp(element);
11647                         upE.eq(0).attr('tabindex', 0);
11648                         upE[0].focus();
11649                         break;
11650                     case keymap.KEY.RIGHT:
11651                         evt.preventDefault();
11652                         evt.stopPropagation();
11653                         if(element.find('i').eq(0).hasClass('icon-primary-circle')){
11654                             break;
11655                         }    
11656                         if (!element.find('a').eq(0).hasClass('active')) {
11657                             if (element[0].previousElementSibling) {
11658                         closeOthersUp(angular.element(element[0].previousElementSibling),true);
11659                         }
11660                         if (element[0].nextElementSibling) {
11661                             closeOthersDown(angular.element(element[0].nextElementSibling),true);
11662                         }
11663                         activeToggle(element,true);
11664                     
11665                         }
11666                         else {
11667                             element.attr('tabindex', -1);
11668                             findDown(element.find('a').eq(0));
11669                             downE.eq(0).attr('tabindex', 0);
11670                             downE[0].focus();                            
11671                         }                        
11672                         break;
11673                     case keymap.KEY.DOWN:
11674                         evt.preventDefault();
11675                         element.attr('tabindex', -1);
11676                         findDown(element.find('a').eq(0));
11677                         downE.eq(0).attr('tabindex', 0);
11678                         downE[0].focus();
11679                         evt.stopPropagation();
11680                         break;
11681                     case keymap.KEY.ENTER:
11682                         var isSelectedElem = element.hasClass('bg');
11683                         var enterFunc = function(element){
11684                             if (isSelectedElem) {
11685                                 element.removeClass('bg');
11686                                 if (element.attr('aria-selected')) {
11687                                     element.attr('aria-selected', 'false');
11688                                 }                        
11689                             }
11690                             else {
11691                                 element.addClass('bg');
11692                                 element.attr('aria-selected', 'true');                                   
11693                             }  
11694                         };                            
11695                         if (element[0].previousElementSibling) {
11696                             closeOthersUp(angular.element(element[0].previousElementSibling));
11697                         }
11698                         if (element[0].nextElementSibling) {
11699                             closeOthersDown(angular.element(element[0].nextElementSibling));
11700                         }                   
11701                         
11702                         removeBackground(element);
11703                         enterFunc(element);
11704                         evt.stopPropagation();                                                      
11705                         break;
11706                     case keymap.KEY.TAB:
11707                         $timeout(function(){
11708                             resetTabPosition(element);
11709                         },0);
11710                          evt.stopPropagation(); 
11711                         
11712                         break;
11713                     default:
11714                         break;
11715                     }
11716                 });
11717             element.bind('keyup',function(evt){
11718                 if(evt.keyCode === keymap.KEY.TAB){
11719                   
11720                         var tempElem = element;
11721                         var elemArr = [];
11722                         while(!tempElem.hasClass('b2b-tree')){
11723                             elemArr.push(tempElem);
11724                             tempElem = tempElem.parent().parent();
11725                         }
11726                         elemArr.push(tempElem);
11727                       
11728                         expand(elemArr);                    
11729                 }
11730                  evt.stopPropagation(); 
11731             });
11732             }
11733         };
11734     }]);
11735 /**
11736  * @ngdoc directive
11737  * @name Navigation.att:Tree nodes with checkboxes
11738  *
11739  * @param {String} setRole - The value needs to be "tree". This is required to incorporate CATO requirements.
11740  * @param {boolean} groupIt - The value needs to be "false" for top-level tree rendered. 
11741  * @param {Object} collection -  The JSON object of tree to be rendered.
11742  * @description
11743  *  <file src="src/treeNodeCheckbox/docs/readme.md" />
11744  *
11745  * @usage
11746  *      <div class="b2b-tree-checkbox">
11747  *                <b2b-tree-node-checkbox collection="treeStructure" set-role="tree" group-it="false"></b2b-tree-node-checkbox>
11748  *            </div>
11749  * @example
11750  *  <section id="code">
11751         <example module="b2b.att">
11752             <file src="src/treeNodeCheckbox/docs/demo.html" />
11753             <file src="src/treeNodeCheckbox/docs/demo.js" />
11754        </example>
11755     </section>
11756  *
11757  */
11758 angular.module('b2b.att.treeNodeCheckbox', ['b2b.att.utilities'])
11759     .directive('b2bTreeNodeCheckbox', function () {
11760         return {
11761             restrict: "E",
11762             replace: true,
11763             scope: {
11764                 collection: '=',
11765                 groupIt: '=',
11766                 setRole: '@'
11767             },
11768             templateUrl: function (element, attrs) {
11769                 if (attrs.groupIt === 'true') {
11770                     return "b2bTemplate/treeNodeCheckbox/groupedTree.html";
11771                 } else {
11772                     return "b2bTemplate/treeNodeCheckbox/ungroupedTree.html";
11773                 }
11774             },
11775             link: function (scope) {
11776                 if (!(scope.setRole === 'tree')) {
11777                     scope.setRole = 'group';
11778                 }
11779             }
11780         }
11781     })
11782     .directive('b2bTreeMember', ['$compile', '$timeout', 'keymap', function ($compile, $timeout, keymap) {
11783         return {
11784             restrict: "E",
11785             replace: true,
11786             scope: {
11787                 member: '=',
11788                 groupIt: '='
11789             },
11790             templateUrl: 'b2bTemplate/treeNodeCheckbox/treeMember.html',
11791             link: function (scope, element, attrs) {
11792                 scope.elemArr = [];
11793                 var removeRootTabIndex = function (elem) {
11794                     if (elem.parent().parent().eq(0).hasClass('b2b-tree-checkbox')) {
11795                         elem.attr('tabindex', -1);                        
11796                         return;
11797                     }
11798                     removeRootTabIndex(elem.parent());
11799                 };
11800                 scope.$watch('member.child', function(newVal, oldVal){                  
11801                     if(newVal !== oldVal){
11802                         scope.showChild();
11803                     };
11804                 });
11805
11806                 var checkedCount = 0;
11807                 var nonCheckedCount = 0;
11808                 var checkBoxesCount = 0;
11809
11810                 if(element.find('a').eq(0).find('input')){
11811                     if(scope.member.indeterminate){
11812                         element.find('a').eq(0).find('input').prop('indeterminate', true);
11813                         element.attr('aria-checked',"mixed");
11814                     }
11815                     element.attr('aria-checked',scope.member.isSelected);
11816                 }
11817
11818                 element.find('a').eq(0).find('input').bind('change',function(){
11819                     scope.member.indeterminate = false;
11820                     downwardModalUpdate(scope.member);
11821                     downwardSelection(element);
11822                     upwardSelection(element);
11823                     element.attr('aria-checked',scope.member.isSelected);
11824                      if (scope.member.onSelect !== undefined) {
11825                         scope.member.onSelect(scope.member);
11826                     }
11827                 });
11828
11829                 element.find('a').eq(0).find('input').bind('click',function(){
11830                     var elem = angular.element(this);
11831                     if(scope.member.indeterminate){
11832                         scope.member.indeterminate = false;
11833                         scope.member.isSelected = true;
11834                         elem.prop('indeterminate', false);
11835                         elem.prop('checked', true);
11836                         elem.triggerHandler('change');
11837                     }
11838                 });
11839
11840                 var groupNode = false;
11841                 var checkedTreeNode = false;
11842
11843                 var isCheckboxSelected = function(elem){
11844                     checkedTreeNode = false;
11845                     checkedTreeNode = angular.element(angular.element(elem).find('a').eq(0))[0].querySelector('input.treeCheckBox').checked;
11846                 }
11847
11848                 var findCheckbox = function(elem){
11849                     return angular.element(angular.element(elem).find('a').eq(0))[0].querySelector('input.treeCheckBox');
11850                 }
11851
11852                 var updateGrpNodeCheckboxes = function(elem, checked){
11853                     angular.element(angular.element(elem).find('a').eq(0))[0].querySelector('input.treeCheckBox').checked = checked;
11854                 }
11855
11856                 
11857                 var isGroupNode = function(elem){
11858                     groupNode = false;
11859                     if(angular.element(angular.element(elem).find('a').eq(0))[0].querySelector('input.grpTreeCheckbox')){
11860                         groupNode = true;
11861                     }
11862                 }
11863
11864                 var downwardModalUpdate = function(curMember){
11865                     angular.forEach(curMember.child, function(childMember, key) {
11866                         childMember.isSelected = curMember.isSelected;
11867                         childMember.indeterminate = false;
11868                         if(angular.isArray(childMember.child) && scope.member.child.length > 0){
11869                             downwardModalUpdate(childMember);
11870                         }
11871                     });
11872                 }
11873
11874                 var downwardSelection = function(elem){
11875                     if(findCheckbox(elem)){
11876                         isCheckboxSelected(elem)
11877                     } 
11878                     if(angular.element(elem).find('ul').length > 0){
11879                         var childNodes = angular.element(elem).find('ul').eq(0).children('li');
11880                         for(var i=0; i<childNodes.length; i++){
11881                             if(findCheckbox(childNodes[i])){
11882                                 isGroupNode(childNodes[i]);
11883                                 angular.element(findCheckbox(childNodes[i])).prop('indeterminate', false);
11884                                 angular.element(childNodes[i]).attr('aria-checked',checkedTreeNode);
11885                                 if(groupNode){
11886                                     updateGrpNodeCheckboxes(childNodes[i],checkedTreeNode);
11887                                 }else{
11888                                     angular.element(childNodes[i]).scope().member.isSelected = checkedTreeNode;
11889                                     angular.element(childNodes[i]).scope().member.indeterminate = false
11890                                     angular.element(childNodes[i]).scope().$apply();
11891                                 }
11892                                 downwardSelection(childNodes[i]);
11893                             }
11894                         }
11895
11896                     }
11897                 }
11898                 var upwardSelection = function(elem){
11899                                         if(!elem.parent().parent().eq(0).hasClass('b2b-tree-checkbox')){
11900                                                 var childNodes = elem.parent().parent().find('ul').eq(0).children('li');
11901                                                 checkedCount = 0;
11902                                                 nonCheckedCount = 0;
11903                                                 checkBoxesCount = 0;    
11904                                                 for(i=0; i<childNodes.length; i++){
11905                                                         if(findCheckbox(childNodes[i])){
11906                                                                 isGroupNode(childNodes[i]);
11907                                                                 isCheckboxSelected(childNodes[i]);
11908                                                                 checkBoxesCount++;
11909                                                                 if(checkedTreeNode){
11910                                                                         checkedCount++;
11911                                                                 }else if(!angular.element(angular.element(angular.element(childNodes[i]).find('a').eq(0))[0].querySelector('input.treeCheckBox')).prop('indeterminate')){
11912                                                                         nonCheckedCount++;
11913                                                                 }
11914                                                         }
11915                                                 }
11916                                                 var parentNodeScope;
11917                                                 parentNodeScope = angular.element(elem.parent().parent()).scope();
11918                                                 if(findCheckbox(elem.parent().parent())){
11919                                                         if(nonCheckedCount == checkBoxesCount){
11920                                                                 angular.element(findCheckbox(elem.parent().parent())).prop('indeterminate', false);
11921                                                                 if(parentNodeScope &&  parentNodeScope.member){
11922                                                                         parentNodeScope.member.isSelected = false;
11923                                                                         parentNodeScope.member.indeterminate = false;
11924                                                                 }else{
11925                                                                         updateGrpNodeCheckboxes(elem.parent().parent(),false);
11926                                                                 }
11927                                                                 angular.element(elem.parent().parent()).attr('aria-checked',false);
11928                                                         }else if(checkedCount == checkBoxesCount){
11929                                                                 angular.element(findCheckbox(elem.parent().parent())).prop('indeterminate', false);
11930                                                                 if(parentNodeScope &&  parentNodeScope.member){
11931                                                                         parentNodeScope.member.isSelected = true;
11932                                                                         parentNodeScope.member.indeterminate = false;
11933                                                                 }else{
11934                                                                         updateGrpNodeCheckboxes(elem.parent().parent(),true);
11935                                                                 }
11936                                                                 angular.element(elem.parent().parent()).attr('aria-checked',true);
11937                                                         }else{
11938                                                                 angular.element(findCheckbox(elem.parent().parent())).prop('indeterminate', true);
11939                                                                 if(parentNodeScope &&  parentNodeScope.member){
11940                                                                         parentNodeScope.member.isSelected = false;
11941                                                                         parentNodeScope.member.indeterminate = true;
11942                                                                 }else{
11943                                                                         updateGrpNodeCheckboxes(elem.parent().parent(),false);
11944                                                                 }
11945                                                                 angular.element(elem.parent().parent()).attr('aria-checked',"mixed");
11946                                                         }
11947                                                         if(parentNodeScope &&  parentNodeScope.member){
11948                                                                 parentNodeScope.$apply();
11949                                                         }        
11950                                                 }
11951                                                 
11952                                                 
11953                                                 
11954                                                 if(elem.parent().parent().attr('role') == "treeitem"){
11955                                                         upwardSelection(elem.parent().parent());
11956                                                 }
11957                                         }
11958                 }
11959
11960                 scope.showChild = function () {
11961                         if (!element.hasClass('grouped')) {
11962                             if (angular.isArray(scope.member.child) && scope.member.child.length > 0 && (scope.member.divide === undefined || scope.member.child.length < scope.member.divide)) {
11963                                 scope.groupIt = false;
11964                                 element.addClass('grouped');
11965                                 element.append("<b2b-tree-node-checkbox collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-node-checkbox>");
11966                                 $compile(element.contents())(scope);
11967                                 if(scope.member.active && scope.member.active === true){
11968                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-collapsed');
11969                                 };
11970                                 if(scope.member.selected && scope.member.selected === true){
11971                                     element.attr('tabindex', 0);
11972                                     removeRootTabIndex(element);
11973                                 };
11974                                 if(scope.member.active && scope.member.active == undefined){
11975                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');
11976                                 };
11977                             } else if (scope.member.child && scope.member.divide && scope.member.child.length > scope.member.divide) {
11978                                 element.addClass('grouped');
11979                                 scope.groupIt = true;
11980                                 var j = 0;
11981                                 var grpName = '';
11982                                 if(scope.member.child[0].groupName !== undefined){
11983                                     grpName = scope.member.child[0].groupName;
11984                                 }
11985                                 else{
11986                                     var toSlice = scope.member.child[0].name.search(' ');
11987                                     grpName = scope.member.child[0].name.slice(0, toSlice);
11988                                 }
11989
11990                                 for (i = 0; i < scope.member.child.length; i += scope.member.divide) {
11991                                     j = 0;
11992                                     for (j = j + i; j < (i + scope.member.divide); j++) {                                        
11993                                         if (j === scope.member.child.length) {
11994                                             scope.member.child[j - 1].grpChild = grpName + ' ' + (i + 1) + ' - ' + (scope.member.child.length);
11995                                             break;
11996                                             
11997                                             if(scope.member.child[j-1].active && scope.member.child[j-1].active===true){
11998                                                 scope.member.child[j-1].activeGrp = true;
11999                                             };
12000                                             
12001                                         }
12002                                         if (i + scope.member.divide > scope.member.child.length) {
12003                                             scope.member.child[j].grpChild = grpName + ' ' + (i + 1) + ' - ' + (scope.member.child.length);
12004                                             if(scope.member.child[j].active && scope.member.child[j].active===true){
12005                                                 scope.member.child[j].activeGrp = true;
12006                                             };
12007
12008                                         } else {
12009                                             scope.member.child[j].grpChild = grpName + ' ' + (i + 1) + ' - ' + (i + scope.member.divide);
12010                                             if(scope.member.child[j].active && scope.member.child[j].active===true){
12011                                                 scope.member.child[j].activeGrp = true;
12012                                             };
12013                                         }
12014                                     }
12015                                 }
12016                                 if(scope.member.divide){
12017                                     element.append("<b2b-tree-node-checkbox collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-node-checkbox>");
12018                                 } else {
12019                                     element.append("<b2b-tree-node-checkbox collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-node-checkbox>");
12020                                 }
12021                                 $compile(element.contents())(scope);
12022                                 if(scope.member.active && scope.member.active === true){
12023                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-collapsed');
12024                                 };
12025                                 
12026                                 if( scope.member.active && scope.member.active == undefined){
12027                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');
12028                                 };
12029                             }
12030                         }
12031                         $timeout(function () {
12032                             if(!scope.member.indeterminate){
12033                                 downwardSelection(element);
12034                             }    
12035                         });  
12036
12037                 };
12038                 
12039                 if(scope.member.active && scope.member.active == true){
12040                     scope.showChild();
12041                 };
12042                 if(scope.member.active == undefined && !element.find('a').eq(0).hasClass('active') && scope.member.child !== undefined){
12043                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');
12044                 }
12045                 else if(scope.member.child == undefined){
12046                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-circle');
12047                     if(scope.$parent.$index === 0) {
12048                         element.find('a').eq(0).append('<span class="first-link"></span>');
12049                     };
12050                 };
12051                 
12052                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).bind('click', function (evt) {
12053                     scope.showChild();
12054                     var expandFunc = scope.member.onExpand;
12055                     if (element.find('a').eq(0).hasClass('active') && scope.member.onExpand !== undefined) {
12056                        var eValue = scope.member.onExpand(scope.member);
12057                     }
12058                     if (!element.find('a').eq(0).hasClass('active') && scope.member.onCollapse !== undefined) {
12059                         scope.member.onCollapse(scope.member);
12060                     }
12061                 });
12062
12063                 angular.element(element[0].querySelectorAll('.treeNodeName')).eq(0).bind('click', function (evt) {
12064
12065                 });
12066                 
12067             }
12068         }
12069 }])
12070     .directive('b2bTreeNodeLink', ['keymap', '$timeout', function (keymap, $timeout) {
12071         return {
12072             restrict: 'A',
12073             link: function (scope, element, attr, ctrl) {
12074                 var rootE, parentE, upE, downE;
12075                 var closeOthersUp = function (elem) {
12076                     
12077                     if (elem.find('a').eq(0).hasClass('active')) {
12078                         activeToggle(elem);
12079                         return;
12080                     }
12081                     if (elem.hasClass('bg')) {
12082                         elem.removeClass('bg');
12083                     }
12084                     if (elem[0].previousElementSibling !== null) {
12085                         closeOthersUp(angular.element(elem[0].previousElementSibling));
12086                     }
12087                 };
12088                 var closeOthersDown = function (elem) {
12089                     
12090                     if (elem.find('a').eq(0).hasClass('active')) {
12091                         activeToggle(elem);
12092                         return;
12093                     }
12094                     if (elem.hasClass('bg')) {
12095                         elem.removeClass('bg');
12096                     }
12097                     if (elem[0].nextElementSibling !== null) {
12098                         closeOthersDown(angular.element(elem[0].nextElementSibling));
12099                     }
12100                 };
12101
12102                 var removeBackgroundUp = function (elem) {
12103                     
12104                     if (elem.hasClass('b2b-tree-checkbox')) {
12105                         return;
12106                     } else {
12107                         elem.parent().parent().removeClass('bg');
12108                         removeBackgroundUp(elem.parent().parent());
12109                     }
12110                 };
12111
12112                 var removeBackgroundDown = function (elem) {
12113                     
12114                     angular.element(elem[0].querySelector('.bg')).removeClass('bg');
12115                 };
12116
12117
12118
12119                 var activeToggle = function (elem) {
12120                     var element = elem.find('a').eq(0);
12121                     if (element.hasClass('active')) {
12122                         elem.removeClass('bg');
12123                         if (!angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).hasClass('icon-primary-circle')) {
12124                             element.removeClass('active');
12125                             elem.attr('aria-expanded', 'false');
12126                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-expanded');
12127                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');
12128                         }
12129                     } else {
12130                         elem.addClass('bg');
12131                         if (!angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).hasClass('icon-primary-circle')) {
12132                             element.addClass('active');
12133                             elem.attr('aria-expanded', 'true');
12134                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-collapsed');
12135                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-expanded');
12136                         }
12137                     }
12138                 };
12139                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).bind('click', function (evt) {
12140                     
12141                         if (element[0].previousElementSibling) {
12142                             closeOthersUp(angular.element(element[0].previousElementSibling));
12143                         }
12144                         if (element[0].nextElementSibling) {
12145                             closeOthersDown(angular.element(element[0].nextElementSibling));
12146                         }
12147
12148                         activeToggle(element);
12149
12150                     removeBackgroundDown(element);
12151                     removeBackgroundUp(element);
12152                     evt.stopPropagation();                    
12153                 });
12154                 
12155                 if (element.parent().parent().hasClass('b2b-tree-checkbox') && (element.parent()[0].previousElementSibling === null)) {
12156                     element.attr('tabindex', 0);
12157                 }
12158                 
12159                 var isRoot = function (elem) {
12160                     if (elem.parent().parent().eq(0).hasClass('b2b-tree-checkbox')) {
12161                         return true;
12162                     } else {
12163                         return false;
12164                     }
12165                 };
12166                 var findRoot = function (elem) {
12167                     if (isRoot(elem)) {
12168                         rootE = elem;
12169                         return;
12170                     }
12171                     findRoot(elem.parent());
12172                 };
12173
12174                 var findPreActive = function (elem) {
12175
12176                     if (!(elem.hasClass("active"))) {
12177                         return;
12178                     } else {
12179                         var childElems = angular.element(elem[0].nextElementSibling.children);
12180                         lastE = angular.element(childElems[childElems.length - 1]);
12181                         if (lastE.find('a').eq(0).hasClass('active')) {
12182                             findPreActive(lastE.find('a').eq(0));
12183                         }
12184                         upE = lastE;
12185                     }
12186                 };
12187
12188                 var findUp = function (elem) {
12189                     if (isRoot(elem)) {
12190                         upE = elem;
12191                         return;
12192                     }
12193                     if (elem[0].previousElementSibling !== null && !angular.element(elem[0].previousElementSibling).hasClass('tree-hide')) {
12194                         upE = angular.element(elem[0].previousElementSibling);
12195                         if (upE.find('a').eq(0).hasClass('active')) {
12196                             findPreActive(upE.find('a').eq(0));
12197                         }
12198                     } else {
12199                         upE = elem.parent().parent();
12200                     }
12201                 };
12202
12203                 var downElement = function (elem) {
12204                     if (elem.next().hasClass('tree-hide')) {
12205                         downElement(elem.next());
12206                     } else {
12207                         downE = elem.next();
12208                     }
12209                 }
12210                 var isBottomElem = false;
12211                 var downParent = function(liElem){
12212                     if(liElem.eq(0).parent().parent().eq(0).hasClass('b2b-tree-checkbox')){
12213                         isBottomElem = true;
12214                         return;
12215                     }
12216                     if(liElem.next().length !== 0){
12217                         downE = liElem.next().eq(0);
12218                         return;
12219                     }
12220                     else {
12221                         downParent(liElem.parent().parent());
12222                     }
12223                 }
12224                 
12225                 var findDown = function (elem) {
12226                     if (isRoot(elem.parent()) && !elem.hasClass('active')) {
12227                         downE = elem.parent();
12228                         return;
12229                     }
12230                     if (elem.hasClass('active')) {
12231                         downE = elem.next().find('li').eq(0);
12232                         if (downE.hasClass('tree-hide')) {
12233                             downElement(downE);
12234                         }
12235
12236                     } else {
12237                         downParent(elem.parent());
12238                         if(isBottomElem === true){
12239                             downE = elem.parent();
12240                             isBottomElem = false;
12241                         }
12242                     }
12243                 };
12244                 element.bind('keydown', function (evt) {
12245                     switch (evt.keyCode) {
12246                     case keymap.KEY.HOME:
12247                         evt.preventDefault();
12248                         evt.stopPropagation();
12249                         element.attr('tabindex', -1);
12250                         findRoot(element);
12251                         rootE.eq(0).attr('tabindex', 0);
12252                         rootE[0].focus();
12253                         break;
12254                     case keymap.KEY.LEFT:
12255                         evt.preventDefault();
12256                         evt.stopPropagation();
12257                         if (!isRoot(element)) {
12258                             if(element.find('a').eq(0).hasClass('active')){
12259                                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).triggerHandler('click');
12260                                 return;
12261                             }
12262                             element.attr('tabindex', -1);
12263                             parentE = element.parent().parent();
12264                             parentE.attr('tabindex', 0);
12265                             parentE[0].focus();
12266                         } else {
12267                             if (element.find('a').eq(0).hasClass('active')) {
12268                                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).triggerHandler('click');
12269                             }
12270                         };
12271                         break;
12272                     case keymap.KEY.UP:
12273                         evt.preventDefault();
12274                         evt.stopPropagation();
12275                         element.attr('tabindex', -1);
12276                         findUp(element);
12277                         upE.eq(0).attr('tabindex', 0);
12278                         upE[0].focus();
12279                         break;
12280                     case keymap.KEY.RIGHT:
12281                         evt.preventDefault();
12282                         evt.stopPropagation();
12283                         if(angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).hasClass('icon-primary-circle')){
12284                             break;
12285                         }    
12286                         if (!element.find('a').eq(0).hasClass('active')) {
12287                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).triggerHandler('click');
12288                         }
12289                         else {
12290                             element.attr('tabindex', -1);
12291                             findDown(element.find('a').eq(0));
12292                             downE.eq(0).attr('tabindex', 0);
12293                             downE[0].focus();                            
12294                         }                        
12295                         break;
12296                     case keymap.KEY.DOWN:
12297                         evt.preventDefault();
12298                         element.attr('tabindex', -1);
12299                         findDown(element.find('a').eq(0));
12300                         downE.eq(0).attr('tabindex', 0);
12301                         downE[0].focus();
12302                         evt.stopPropagation();
12303                         break;
12304                     case keymap.KEY.SPACE:
12305                     case keymap.KEY.ENTER:
12306                         evt.preventDefault();
12307                         evt.stopPropagation();
12308                         if(angular.isDefined(element.scope().member.isSelected)){
12309                             element.scope().member.isSelected = !element.scope().member.isSelected;
12310                             element.scope().member.indeterminate = false;
12311                             element.scope().$apply();
12312                             element.find('a').eq(0).find('input').prop('indeterminate', false);
12313                             element.find('a').eq(0).find('input').triggerHandler('change');
12314                         }
12315                         break;    
12316                     default:
12317                         break;
12318                     }
12319                 });
12320             }
12321         };
12322     }]);
12323 /*!
12324  * VERSION: 1.7.3
12325  * DATE: 2014-01-14
12326  * UPDATES AND DOCS AT: http://www.greensock.com
12327  *
12328  * @license Copyright (c) 2008-2014, GreenSock. All rights reserved.
12329  * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
12330  * Club GreenSock members, the software agreement that was issued with your membership.
12331  * 
12332  * @author: Jack Doyle, jack@greensock.com
12333  **/
12334 (window._gsQueue || (window._gsQueue = [])).push( function() {
12335
12336         "use strict";
12337
12338         var _doc = document.documentElement,
12339                 _window = window,
12340                 _max = function(element, axis) {
12341                         var dim = (axis === "x") ? "Width" : "Height",
12342                                 scroll = "scroll" + dim,
12343                                 client = "client" + dim,
12344                                 body = document.body;
12345                         return (element === _window || element === _doc || element === body) ? Math.max(_doc[scroll], body[scroll]) - (_window["inner" + dim] || Math.max(_doc[client], body[client])) : element[scroll] - element["offset" + dim];
12346                 },
12347
12348                 ScrollToPlugin = window._gsDefine.plugin({
12349                         propName: "scrollTo",
12350                         API: 2,
12351                         version:"1.7.3",
12352
12353                         //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
12354                         init: function(target, value, tween) {
12355                                 this._wdw = (target === _window);
12356                                 this._target = target;
12357                                 this._tween = tween;
12358                                 if (typeof(value) !== "object") {
12359                                         value = {y:value}; //if we don't receive an object as the parameter, assume the user intends "y".
12360                                 }
12361                                 this._autoKill = (value.autoKill !== false);
12362                                 this.x = this.xPrev = this.getX();
12363                                 this.y = this.yPrev = this.getY();
12364                                 if (value.x != null) {
12365                                         this._addTween(this, "x", this.x, (value.x === "max") ? _max(target, "x") : value.x, "scrollTo_x", true);
12366                                         this._overwriteProps.push("scrollTo_x");
12367                                 } else {
12368                                         this.skipX = true;
12369                                 }
12370                                 if (value.y != null) {
12371                                         this._addTween(this, "y", this.y, (value.y === "max") ? _max(target, "y") : value.y, "scrollTo_y", true);
12372                                         this._overwriteProps.push("scrollTo_y");
12373                                 } else {
12374                                         this.skipY = true;
12375                                 }
12376                                 return true;
12377                         },
12378
12379                         //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
12380                         set: function(v) {
12381                                 this._super.setRatio.call(this, v);
12382
12383                                 var x = (this._wdw || !this.skipX) ? this.getX() : this.xPrev,
12384                                         y = (this._wdw || !this.skipY) ? this.getY() : this.yPrev,
12385                                         yDif = y - this.yPrev,
12386                                         xDif = x - this.xPrev;
12387
12388                                 if (this._autoKill) {
12389                                         //note: iOS has a bug that throws off the scroll by several pixels, so we need to check if it's within 7 pixels of the previous one that we set instead of just looking for an exact match.
12390                                         if (!this.skipX && (xDif > 7 || xDif < -7) && x < _max(this._target, "x")) {
12391                                                 this.skipX = true; //if the user scrolls separately, we should stop tweening!
12392                                         }
12393                                         if (!this.skipY && (yDif > 7 || yDif < -7) && y < _max(this._target, "y")) {
12394                                                 this.skipY = true; //if the user scrolls separately, we should stop tweening!
12395                                         }
12396                                         if (this.skipX && this.skipY) {
12397                                                 this._tween.kill();
12398                                         }
12399                                 }
12400                                 if (this._wdw) {
12401                                         _window.scrollTo((!this.skipX) ? this.x : x, (!this.skipY) ? this.y : y);
12402                                 } else {
12403                                         if (!this.skipY) {
12404                                                 this._target.scrollTop = this.y;
12405                                         }
12406                                         if (!this.skipX) {
12407                                                 this._target.scrollLeft = this.x;
12408                                         }
12409                                 }
12410                                 this.xPrev = this.x;
12411                                 this.yPrev = this.y;
12412                         }
12413
12414                 }),
12415                 p = ScrollToPlugin.prototype;
12416
12417         ScrollToPlugin.max = _max;
12418
12419         p.getX = function() {
12420                 return (!this._wdw) ? this._target.scrollLeft : (_window.pageXOffset != null) ? _window.pageXOffset : (_doc.scrollLeft != null) ? _doc.scrollLeft : document.body.scrollLeft;
12421         };
12422
12423         p.getY = function() {
12424                 return (!this._wdw) ? this._target.scrollTop : (_window.pageYOffset != null) ? _window.pageYOffset : (_doc.scrollTop != null) ? _doc.scrollTop : document.body.scrollTop;
12425         };
12426
12427         p._kill = function(lookup) {
12428                 if (lookup.scrollTo_x) {
12429                         this.skipX = true;
12430                 }
12431                 if (lookup.scrollTo_y) {
12432                         this.skipY = true;
12433                 }
12434                 return this._super._kill.call(this, lookup);
12435         };
12436
12437 }); if (window._gsDefine) { window._gsQueue.pop()(); }
12438 /*!
12439  * VERSION: 1.12.1
12440  * DATE: 2014-06-26
12441  * UPDATES AND DOCS AT: http://www.greensock.com
12442  * 
12443  * Includes all of the following: TweenLite, TweenMax, TimelineLite, TimelineMax, EasePack, CSSPlugin, RoundPropsPlugin, BezierPlugin, AttrPlugin, DirectionalRotationPlugin
12444  *
12445  * @license Copyright (c) 2008-2014, GreenSock. All rights reserved.
12446  * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
12447  * Club GreenSock members, the software agreement that was issued with your membership.
12448  * 
12449  * @author: Jack Doyle, jack@greensock.com
12450  **/
12451
12452 (window._gsQueue || (window._gsQueue = [])).push( function() {
12453
12454         "use strict";
12455
12456         window._gsDefine("TweenMax", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {
12457
12458                 var _slice = [].slice,
12459                         TweenMax = function(target, duration, vars) {
12460                                 TweenLite.call(this, target, duration, vars);
12461                                 this._cycle = 0;
12462                                 this._yoyo = (this.vars.yoyo === true);
12463                                 this._repeat = this.vars.repeat || 0;
12464                                 this._repeatDelay = this.vars.repeatDelay || 0;
12465                                 this._dirty = true; //ensures that if there is any repeat, the totalDuration will get recalculated to accurately report it.
12466                                 this.render = TweenMax.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method)
12467                         },
12468                         _tinyNum = 0.0000000001,
12469                         TweenLiteInternals = TweenLite._internals,
12470                         _isSelector = TweenLiteInternals.isSelector,
12471                         _isArray = TweenLiteInternals.isArray,
12472                         p = TweenMax.prototype = TweenLite.to({}, 0.1, {}),
12473                         _blankArray = [];
12474
12475                 TweenMax.version = "1.12.1";
12476                 p.constructor = TweenMax;
12477                 p.kill()._gc = false;
12478                 TweenMax.killTweensOf = TweenMax.killDelayedCallsTo = TweenLite.killTweensOf;
12479                 TweenMax.getTweensOf = TweenLite.getTweensOf;
12480                 TweenMax.lagSmoothing = TweenLite.lagSmoothing;
12481                 TweenMax.ticker = TweenLite.ticker;
12482                 TweenMax.render = TweenLite.render;
12483
12484                 p.invalidate = function() {
12485                         this._yoyo = (this.vars.yoyo === true);
12486                         this._repeat = this.vars.repeat || 0;
12487                         this._repeatDelay = this.vars.repeatDelay || 0;
12488                         this._uncache(true);
12489                         return TweenLite.prototype.invalidate.call(this);
12490                 };
12491                 
12492                 p.updateTo = function(vars, resetDuration) {
12493                         var curRatio = this.ratio, p;
12494                         if (resetDuration && this._startTime < this._timeline._time) {
12495                                 this._startTime = this._timeline._time;
12496                                 this._uncache(false);
12497                                 if (this._gc) {
12498                                         this._enabled(true, false);
12499                                 } else {
12500                                         this._timeline.insert(this, this._startTime - this._delay); //ensures that any necessary re-sequencing of Animations in the timeline occurs to make sure the rendering order is correct.
12501                                 }
12502                         }
12503                         for (p in vars) {
12504                                 this.vars[p] = vars[p];
12505                         }
12506                         if (this._initted) {
12507                                 if (resetDuration) {
12508                                         this._initted = false;
12509                                 } else {
12510                                         if (this._gc) {
12511                                                 this._enabled(true, false);
12512                                         }
12513                                         if (this._notifyPluginsOfEnabled && this._firstPT) {
12514                                                 TweenLite._onPluginEvent("_onDisable", this); //in case a plugin like MotionBlur must perform some cleanup tasks
12515                                         }
12516                                         if (this._time / this._duration > 0.998) { //if the tween has finished (or come extremely close to finishing), we just need to rewind it to 0 and then render it again at the end which forces it to re-initialize (parsing the new vars). We allow tweens that are close to finishing (but haven't quite finished) to work this way too because otherwise, the values are so small when determining where to project the starting values that binary math issues creep in and can make the tween appear to render incorrectly when run backwards. 
12517                                                 var prevTime = this._time;
12518                                                 this.render(0, true, false);
12519                                                 this._initted = false;
12520                                                 this.render(prevTime, true, false);
12521                                         } else if (this._time > 0) {
12522                                                 this._initted = false;
12523                                                 this._init();
12524                                                 var inv = 1 / (1 - curRatio),
12525                                                         pt = this._firstPT, endValue;
12526                                                 while (pt) {
12527                                                         endValue = pt.s + pt.c; 
12528                                                         pt.c *= inv;
12529                                                         pt.s = endValue - pt.c;
12530                                                         pt = pt._next;
12531                                                 }
12532                                         }
12533                                 }
12534                         }
12535                         return this;
12536                 };
12537                                 
12538                 p.render = function(time, suppressEvents, force) {
12539                         if (!this._initted) if (this._duration === 0 && this.vars.repeat) { //zero duration tweens that render immediately have render() called from TweenLite's constructor, before TweenMax's constructor has finished setting _repeat, _repeatDelay, and _yoyo which are critical in determining totalDuration() so we need to call invalidate() which is a low-kb way to get those set properly.
12540                                 this.invalidate();
12541                         }
12542                         var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
12543                                 prevTime = this._time,
12544                                 prevTotalTime = this._totalTime, 
12545                                 prevCycle = this._cycle,
12546                                 duration = this._duration,
12547                                 prevRawPrevTime = this._rawPrevTime,
12548                                 isComplete, callback, pt, cycleDuration, r, type, pow, rawPrevTime, i;
12549                         if (time >= totalDur) {
12550                                 this._totalTime = totalDur;
12551                                 this._cycle = this._repeat;
12552                                 if (this._yoyo && (this._cycle & 1) !== 0) {
12553                                         this._time = 0;
12554                                         this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
12555                                 } else {
12556                                         this._time = duration;
12557                                         this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1;
12558                                 }
12559                                 if (!this._reversed) {
12560                                         isComplete = true;
12561                                         callback = "onComplete";
12562                                 }
12563                                 if (duration === 0) if (this._initted || !this.vars.lazy || force) { //zero-duration tweens are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
12564                                         if (this._startTime === this._timeline._duration) { //if a zero-duration tween is at the VERY end of a timeline and that timeline renders at its end, it will typically add a tiny bit of cushion to the render time to prevent rounding errors from getting in the way of tweens rendering their VERY end. If we then reverse() that timeline, the zero-duration tween will trigger its onReverseComplete even though technically the playhead didn't pass over it again. It's a very specific edge case we must accommodate.
12565                                                 time = 0;
12566                                         }
12567                                         if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time) {
12568                                                 force = true;
12569                                                 if (prevRawPrevTime > _tinyNum) {
12570                                                         callback = "onReverseComplete";
12571                                                 }
12572                                         }
12573                                         this._rawPrevTime = rawPrevTime = (!suppressEvents || time || prevRawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient.
12574                                 }
12575                                 
12576                         } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
12577                                 this._totalTime = this._time = this._cycle = 0;
12578                                 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
12579                                 if (prevTotalTime !== 0 || (duration === 0 && prevRawPrevTime > 0 && prevRawPrevTime !== _tinyNum)) {
12580                                         callback = "onReverseComplete";
12581                                         isComplete = this._reversed;
12582                                 }
12583                                 if (time < 0) {
12584                                         this._active = false;
12585                                         if (duration === 0) if (this._initted || !this.vars.lazy || force) { //zero-duration tweens are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
12586                                                 if (prevRawPrevTime >= 0) {
12587                                                         force = true;
12588                                                 }
12589                                                 this._rawPrevTime = rawPrevTime = (!suppressEvents || time || prevRawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient.
12590                                         }
12591                                 } else if (!this._initted) { //if we render the very beginning (time == 0) of a fromTo(), we must force the render (normal tweens wouldn't need to render at a time of 0 when the prevTime was also 0). This is also mandatory to make sure overwriting kicks in immediately.
12592                                         force = true;
12593                                 }
12594                         } else {
12595                                 this._totalTime = this._time = time;
12596                                 
12597                                 if (this._repeat !== 0) {
12598                                         cycleDuration = duration + this._repeatDelay;
12599                                         this._cycle = (this._totalTime / cycleDuration) >> 0; //originally _totalTime % cycleDuration but floating point errors caused problems, so I normalized it. (4 % 0.8 should be 0 but Flash reports it as 0.79999999!)
12600                                         if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) {
12601                                                 this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning)
12602                                         }
12603                                         this._time = this._totalTime - (this._cycle * cycleDuration);
12604                                         if (this._yoyo) if ((this._cycle & 1) !== 0) {
12605                                                 this._time = duration - this._time;
12606                                         }
12607                                         if (this._time > duration) {
12608                                                 this._time = duration;
12609                                         } else if (this._time < 0) {
12610                                                 this._time = 0;
12611                                         }
12612                                 }
12613
12614                                 if (this._easeType) {
12615                                         r = this._time / duration;
12616                                         type = this._easeType;
12617                                         pow = this._easePower;
12618                                         if (type === 1 || (type === 3 && r >= 0.5)) {
12619                                                 r = 1 - r;
12620                                         }
12621                                         if (type === 3) {
12622                                                 r *= 2;
12623                                         }
12624                                         if (pow === 1) {
12625                                                 r *= r;
12626                                         } else if (pow === 2) {
12627                                                 r *= r * r;
12628                                         } else if (pow === 3) {
12629                                                 r *= r * r * r;
12630                                         } else if (pow === 4) {
12631                                                 r *= r * r * r * r;
12632                                         }
12633
12634                                         if (type === 1) {
12635                                                 this.ratio = 1 - r;
12636                                         } else if (type === 2) {
12637                                                 this.ratio = r;
12638                                         } else if (this._time / duration < 0.5) {
12639                                                 this.ratio = r / 2;
12640                                         } else {
12641                                                 this.ratio = 1 - (r / 2);
12642                                         }
12643
12644                                 } else {
12645                                         this.ratio = this._ease.getRatio(this._time / duration);
12646                                 }
12647                                 
12648                         }
12649                                 
12650                         if (prevTime === this._time && !force && prevCycle === this._cycle) {
12651                                 if (prevTotalTime !== this._totalTime) if (this._onUpdate) if (!suppressEvents) { //so that onUpdate fires even during the repeatDelay - as long as the totalTime changed, we should trigger onUpdate.
12652                                         this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
12653                                 }
12654                                 return;
12655                         } else if (!this._initted) {
12656                                 this._init();
12657                                 if (!this._initted || this._gc) { //immediateRender tweens typically won't initialize until the playhead advances (_time is greater than 0) in order to ensure that overwriting occurs properly. Also, if all of the tweening properties have been overwritten (which would cause _gc to be true, as set in _init()), we shouldn't continue otherwise an onStart callback could be called for example.
12658                                         return;
12659                                 } else if (!force && this._firstPT && ((this.vars.lazy !== false && this._duration) || (this.vars.lazy && !this._duration))) { //we stick it in the queue for rendering at the very end of the tick - this is a performance optimization because browsers invalidate styles and force a recalculation if you read, write, and then read style data (so it's better to read/read/read/write/write/write than read/write/read/write/read/write). The down side, of course, is that usually you WANT things to render immediately because you may have code running right after that which depends on the change. Like imagine running TweenLite.set(...) and then immediately after that, creating a nother tween that animates the same property to another value; the starting values of that 2nd tween wouldn't be accurate if lazy is true.
12660                                         this._time = prevTime;
12661                                         this._totalTime = prevTotalTime;
12662                                         this._rawPrevTime = prevRawPrevTime;
12663                                         this._cycle = prevCycle;
12664                                         TweenLiteInternals.lazyTweens.push(this);
12665                                         this._lazy = time;
12666                                         return;
12667                                 }
12668                                 //_ease is initially set to defaultEase, so now that init() has run, _ease is set properly and we need to recalculate the ratio. Overall this is faster than using conditional logic earlier in the method to avoid having to set ratio twice because we only init() once but renderTime() gets called VERY frequently.
12669                                 if (this._time && !isComplete) {
12670                                         this.ratio = this._ease.getRatio(this._time / duration);
12671                                 } else if (isComplete && this._ease._calcEnd) {
12672                                         this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1);
12673                                 }
12674                         }
12675                         if (this._lazy !== false) {
12676                                 this._lazy = false;
12677                         }
12678
12679                         if (!this._active) if (!this._paused && this._time !== prevTime && time >= 0) {
12680                                 this._active = true; //so that if the user renders a tween (as opposed to the timeline rendering it), the timeline is forced to re-render and align it with the proper time/frame on the next rendering cycle. Maybe the tween already finished but the user manually re-renders it as halfway done.
12681                         }
12682                         if (prevTotalTime === 0) {
12683                                 if (this._initted === 2 && time > 0) {
12684                                         //this.invalidate();
12685                                         this._init(); //will just apply overwriting since _initted of (2) means it was a from() tween that had immediateRender:true
12686                                 }
12687                                 if (this._startAt) {
12688                                         if (time >= 0) {
12689                                                 this._startAt.render(time, suppressEvents, force);
12690                                         } else if (!callback) {
12691                                                 callback = "_dummyGS"; //if no callback is defined, use a dummy value just so that the condition at the end evaluates as true because _startAt should render AFTER the normal render loop when the time is negative. We could handle this in a more intuitive way, of course, but the render loop is the MOST important thing to optimize, so this technique allows us to avoid adding extra conditional logic in a high-frequency area.
12692                                         }
12693                                 }
12694                                 if (this.vars.onStart) if (this._totalTime !== 0 || duration === 0) if (!suppressEvents) {
12695                                         this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
12696                                 }
12697                         }
12698                         
12699                         pt = this._firstPT;
12700                         while (pt) {
12701                                 if (pt.f) {
12702                                         pt.t[pt.p](pt.c * this.ratio + pt.s);
12703                                 } else {
12704                                         pt.t[pt.p] = pt.c * this.ratio + pt.s;
12705                                 }
12706                                 pt = pt._next;
12707                         }
12708                         
12709                         if (this._onUpdate) {
12710                                 if (time < 0) if (this._startAt && this._startTime) { //if the tween is positioned at the VERY beginning (_startTime 0) of its parent timeline, it's illegal for the playhead to go back further, so we should not render the recorded startAt values.
12711                                         this._startAt.render(time, suppressEvents, force); //note: for performance reasons, we tuck this conditional logic inside less traveled areas (most tweens don't have an onUpdate). We'd just have it at the end before the onComplete, but the values should be updated before any onUpdate is called, so we ALSO put it here and then if it's not called, we do so later near the onComplete.
12712                                 }
12713                                 if (!suppressEvents) if (this._totalTime !== prevTotalTime || isComplete) {
12714                                         this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
12715                                 }
12716                         }
12717                         if (this._cycle !== prevCycle) if (!suppressEvents) if (!this._gc) if (this.vars.onRepeat) {
12718                                 this.vars.onRepeat.apply(this.vars.onRepeatScope || this, this.vars.onRepeatParams || _blankArray);
12719                         }
12720                         if (callback) if (!this._gc) { //check gc because there's a chance that kill() could be called in an onUpdate
12721                                 if (time < 0 && this._startAt && !this._onUpdate && this._startTime) { //if the tween is positioned at the VERY beginning (_startTime 0) of its parent timeline, it's illegal for the playhead to go back further, so we should not render the recorded startAt values.
12722                                         this._startAt.render(time, suppressEvents, force);
12723                                 }
12724                                 if (isComplete) {
12725                                         if (this._timeline.autoRemoveChildren) {
12726                                                 this._enabled(false, false);
12727                                         }
12728                                         this._active = false;
12729                                 }
12730                                 if (!suppressEvents && this.vars[callback]) {
12731                                         this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
12732                                 }
12733                                 if (duration === 0 && this._rawPrevTime === _tinyNum && rawPrevTime !== _tinyNum) { //the onComplete or onReverseComplete could trigger movement of the playhead and for zero-duration tweens (which must discern direction) that land directly back on their start time, we don't want to fire again on the next render. Think of several addPause()'s in a timeline that forces the playhead to a certain spot, but what if it's already paused and another tween is tweening the "time" of the timeline? Each time it moves [forward] past that spot, it would move back, and since suppressEvents is true, it'd reset _rawPrevTime to _tinyNum so that when it begins again, the callback would fire (so ultimately it could bounce back and forth during that tween). Again, this is a very uncommon scenario, but possible nonetheless.
12734                                         this._rawPrevTime = 0;
12735                                 }
12736                         }
12737                 };
12738                 
12739 //---- STATIC FUNCTIONS -----------------------------------------------------------------------------------------------------------
12740                 
12741                 TweenMax.to = function(target, duration, vars) {
12742                         return new TweenMax(target, duration, vars);
12743                 };
12744                 
12745                 TweenMax.from = function(target, duration, vars) {
12746                         vars.runBackwards = true;
12747                         vars.immediateRender = (vars.immediateRender != false);
12748                         return new TweenMax(target, duration, vars);
12749                 };
12750                 
12751                 TweenMax.fromTo = function(target, duration, fromVars, toVars) {
12752                         toVars.startAt = fromVars;
12753                         toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
12754                         return new TweenMax(target, duration, toVars);
12755                 };
12756                 
12757                 TweenMax.staggerTo = TweenMax.allTo = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
12758                         stagger = stagger || 0;
12759                         var delay = vars.delay || 0,
12760                                 a = [],
12761                                 finalComplete = function() {
12762                                         if (vars.onComplete) {
12763                                                 vars.onComplete.apply(vars.onCompleteScope || this, arguments);
12764                                         }
12765                                         onCompleteAll.apply(onCompleteAllScope || this, onCompleteAllParams || _blankArray);
12766                                 },
12767                                 l, copy, i, p;
12768                         if (!_isArray(targets)) {
12769                                 if (typeof(targets) === "string") {
12770                                         targets = TweenLite.selector(targets) || targets;
12771                                 }
12772                                 if (_isSelector(targets)) {
12773                                         targets = _slice.call(targets, 0);
12774                                 }
12775                         }
12776                         l = targets.length;
12777                         for (i = 0; i < l; i++) {
12778                                 copy = {};
12779                                 for (p in vars) {
12780                                         copy[p] = vars[p];
12781                                 }
12782                                 copy.delay = delay;
12783                                 if (i === l - 1 && onCompleteAll) {
12784                                         copy.onComplete = finalComplete;
12785                                 }
12786                                 a[i] = new TweenMax(targets[i], duration, copy);
12787                                 delay += stagger;
12788                         }
12789                         return a;
12790                 };
12791                 
12792                 TweenMax.staggerFrom = TweenMax.allFrom = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
12793                         vars.runBackwards = true;
12794                         vars.immediateRender = (vars.immediateRender != false);
12795                         return TweenMax.staggerTo(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
12796                 };
12797                 
12798                 TweenMax.staggerFromTo = TweenMax.allFromTo = function(targets, duration, fromVars, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
12799                         toVars.startAt = fromVars;
12800                         toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
12801                         return TweenMax.staggerTo(targets, duration, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
12802                 };
12803                                 
12804                 TweenMax.delayedCall = function(delay, callback, params, scope, useFrames) {
12805                         return new TweenMax(callback, 0, {delay:delay, onComplete:callback, onCompleteParams:params, onCompleteScope:scope, onReverseComplete:callback, onReverseCompleteParams:params, onReverseCompleteScope:scope, immediateRender:false, useFrames:useFrames, overwrite:0});
12806                 };
12807                 
12808                 TweenMax.set = function(target, vars) {
12809                         return new TweenMax(target, 0, vars);
12810                 };
12811                 
12812                 TweenMax.isTweening = function(target) {
12813                         return (TweenLite.getTweensOf(target, true).length > 0);
12814                 };
12815                 
12816                 var _getChildrenOf = function(timeline, includeTimelines) {
12817                                 var a = [],
12818                                         cnt = 0,
12819                                         tween = timeline._first;
12820                                 while (tween) {
12821                                         if (tween instanceof TweenLite) {
12822                                                 a[cnt++] = tween;
12823                                         } else {
12824                                                 if (includeTimelines) {
12825                                                         a[cnt++] = tween;
12826                                                 }
12827                                                 a = a.concat(_getChildrenOf(tween, includeTimelines));
12828                                                 cnt = a.length;
12829                                         }
12830                                         tween = tween._next;
12831                                 }
12832                                 return a;
12833                         }, 
12834                         getAllTweens = TweenMax.getAllTweens = function(includeTimelines) {
12835                                 return _getChildrenOf(Animation._rootTimeline, includeTimelines).concat( _getChildrenOf(Animation._rootFramesTimeline, includeTimelines) );
12836                         };
12837                 
12838                 TweenMax.killAll = function(complete, tweens, delayedCalls, timelines) {
12839                         if (tweens == null) {
12840                                 tweens = true;
12841                         }
12842                         if (delayedCalls == null) {
12843                                 delayedCalls = true;
12844                         }
12845                         var a = getAllTweens((timelines != false)),
12846                                 l = a.length,
12847                                 allTrue = (tweens && delayedCalls && timelines),
12848                                 isDC, tween, i;
12849                         for (i = 0; i < l; i++) {
12850                                 tween = a[i];
12851                                 if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) {
12852                                         if (complete) {
12853                                                 tween.totalTime(tween._reversed ? 0 : tween.totalDuration());
12854                                         } else {
12855                                                 tween._enabled(false, false);
12856                                         }
12857                                 }
12858                         }
12859                 };
12860                 
12861                 TweenMax.killChildTweensOf = function(parent, complete) {
12862                         if (parent == null) {
12863                                 return;
12864                         }
12865                         var tl = TweenLiteInternals.tweenLookup,
12866                                 a, curParent, p, i, l;
12867                         if (typeof(parent) === "string") {
12868                                 parent = TweenLite.selector(parent) || parent;
12869                         }
12870                         if (_isSelector(parent)) {
12871                                 parent = _slice.call(parent, 0);
12872                         }
12873                         if (_isArray(parent)) {
12874                                 i = parent.length;
12875                                 while (--i > -1) {
12876                                         TweenMax.killChildTweensOf(parent[i], complete);
12877                                 }
12878                                 return;
12879                         }
12880                         a = [];
12881                         for (p in tl) {
12882                                 curParent = tl[p].target.parentNode;
12883                                 while (curParent) {
12884                                         if (curParent === parent) {
12885                                                 a = a.concat(tl[p].tweens);
12886                                         }
12887                                         curParent = curParent.parentNode;
12888                                 }
12889                         }
12890                         l = a.length;
12891                         for (i = 0; i < l; i++) {
12892                                 if (complete) {
12893                                         a[i].totalTime(a[i].totalDuration());
12894                                 }
12895                                 a[i]._enabled(false, false);
12896                         }
12897                 };
12898
12899                 var _changePause = function(pause, tweens, delayedCalls, timelines) {
12900                         tweens = (tweens !== false);
12901                         delayedCalls = (delayedCalls !== false);
12902                         timelines = (timelines !== false);
12903                         var a = getAllTweens(timelines),
12904                                 allTrue = (tweens && delayedCalls && timelines),
12905                                 i = a.length,
12906                                 isDC, tween;
12907                         while (--i > -1) {
12908                                 tween = a[i];
12909                                 if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) {
12910                                         tween.paused(pause);
12911                                 }
12912                         }
12913                 };
12914                 
12915                 TweenMax.pauseAll = function(tweens, delayedCalls, timelines) {
12916                         _changePause(true, tweens, delayedCalls, timelines);
12917                 };
12918                 
12919                 TweenMax.resumeAll = function(tweens, delayedCalls, timelines) {
12920                         _changePause(false, tweens, delayedCalls, timelines);
12921                 };
12922
12923                 TweenMax.globalTimeScale = function(value) {
12924                         var tl = Animation._rootTimeline,
12925                                 t = TweenLite.ticker.time;
12926                         if (!arguments.length) {
12927                                 return tl._timeScale;
12928                         }
12929                         value = value || _tinyNum; //can't allow zero because it'll throw the math off
12930                         tl._startTime = t - ((t - tl._startTime) * tl._timeScale / value);
12931                         tl = Animation._rootFramesTimeline;
12932                         t = TweenLite.ticker.frame;
12933                         tl._startTime = t - ((t - tl._startTime) * tl._timeScale / value);
12934                         tl._timeScale = Animation._rootTimeline._timeScale = value;
12935                         return value;
12936                 };
12937                 
12938         
12939 //---- GETTERS / SETTERS ----------------------------------------------------------------------------------------------------------
12940                 
12941                 p.progress = function(value) {
12942                         return (!arguments.length) ? this._time / this.duration() : this.totalTime( this.duration() * ((this._yoyo && (this._cycle & 1) !== 0) ? 1 - value : value) + (this._cycle * (this._duration + this._repeatDelay)), false);
12943                 };
12944                 
12945                 p.totalProgress = function(value) {
12946                         return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, false);
12947                 };
12948                 
12949                 p.time = function(value, suppressEvents) {
12950                         if (!arguments.length) {
12951                                 return this._time;
12952                         }
12953                         if (this._dirty) {
12954                                 this.totalDuration();
12955                         }
12956                         if (value > this._duration) {
12957                                 value = this._duration;
12958                         }
12959                         if (this._yoyo && (this._cycle & 1) !== 0) {
12960                                 value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay));
12961                         } else if (this._repeat !== 0) {
12962                                 value += this._cycle * (this._duration + this._repeatDelay);
12963                         }
12964                         return this.totalTime(value, suppressEvents);
12965                 };
12966
12967                 p.duration = function(value) {
12968                         if (!arguments.length) {
12969                                 return this._duration; //don't set _dirty = false because there could be repeats that haven't been factored into the _totalDuration yet. Otherwise, if you create a repeated TweenMax and then immediately check its duration(), it would cache the value and the totalDuration would not be correct, thus repeats wouldn't take effect.
12970                         }
12971                         return Animation.prototype.duration.call(this, value);
12972                 };
12973
12974                 p.totalDuration = function(value) {
12975                         if (!arguments.length) {
12976                                 if (this._dirty) {
12977                                         //instead of Infinity, we use 999999999999 so that we can accommodate reverses
12978                                         this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat);
12979                                         this._dirty = false;
12980                                 }
12981                                 return this._totalDuration;
12982                         }
12983                         return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) );
12984                 };
12985                 
12986                 p.repeat = function(value) {
12987                         if (!arguments.length) {
12988                                 return this._repeat;
12989                         }
12990                         this._repeat = value;
12991                         return this._uncache(true);
12992                 };
12993                 
12994                 p.repeatDelay = function(value) {
12995                         if (!arguments.length) {
12996                                 return this._repeatDelay;
12997                         }
12998                         this._repeatDelay = value;
12999                         return this._uncache(true);
13000                 };
13001                 
13002                 p.yoyo = function(value) {
13003                         if (!arguments.length) {
13004                                 return this._yoyo;
13005                         }
13006                         this._yoyo = value;
13007                         return this;
13008                 };
13009                 
13010                 
13011                 return TweenMax;
13012                 
13013         }, true);
13014
13015
13016
13017
13018
13019
13020
13021
13022 /*
13023  * ----------------------------------------------------------------
13024  * TimelineLite
13025  * ----------------------------------------------------------------
13026  */
13027         window._gsDefine("TimelineLite", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {
13028
13029                 var TimelineLite = function(vars) {
13030                                 SimpleTimeline.call(this, vars);
13031                                 this._labels = {};
13032                                 this.autoRemoveChildren = (this.vars.autoRemoveChildren === true);
13033                                 this.smoothChildTiming = (this.vars.smoothChildTiming === true);
13034                                 this._sortChildren = true;
13035                                 this._onUpdate = this.vars.onUpdate;
13036                                 var v = this.vars,
13037                                         val, p;
13038                                 for (p in v) {
13039                                         val = v[p];
13040                                         if (_isArray(val)) if (val.join("").indexOf("{self}") !== -1) {
13041                                                 v[p] = this._swapSelfInParams(val);
13042                                         }
13043                                 }
13044                                 if (_isArray(v.tweens)) {
13045                                         this.add(v.tweens, 0, v.align, v.stagger);
13046                                 }
13047                         },
13048                         _tinyNum = 0.0000000001,
13049                         _isSelector = TweenLite._internals.isSelector,
13050                         _isArray = TweenLite._internals.isArray,
13051                         _blankArray = [],
13052                         _globals = window._gsDefine.globals,
13053                         _copy = function(vars) {
13054                                 var copy = {}, p;
13055                                 for (p in vars) {
13056                                         copy[p] = vars[p];
13057                                 }
13058                                 return copy;
13059                         },
13060                         _pauseCallback = function(tween, callback, params, scope) {
13061                                 tween._timeline.pause(tween._startTime);
13062                                 if (callback) {
13063                                         callback.apply(scope || tween._timeline, params || _blankArray);
13064                                 }
13065                         },
13066                         _slice = _blankArray.slice,
13067                         p = TimelineLite.prototype = new SimpleTimeline();
13068
13069                 TimelineLite.version = "1.12.1";
13070                 p.constructor = TimelineLite;
13071                 p.kill()._gc = false;
13072
13073                 p.to = function(target, duration, vars, position) {
13074                         var Engine = (vars.repeat && _globals.TweenMax) || TweenLite;
13075                         return duration ? this.add( new Engine(target, duration, vars), position) : this.set(target, vars, position);
13076                 };
13077
13078                 p.from = function(target, duration, vars, position) {
13079                         return this.add( ((vars.repeat && _globals.TweenMax) || TweenLite).from(target, duration, vars), position);
13080                 };
13081
13082                 p.fromTo = function(target, duration, fromVars, toVars, position) {
13083                         var Engine = (toVars.repeat && _globals.TweenMax) || TweenLite;
13084                         return duration ? this.add( Engine.fromTo(target, duration, fromVars, toVars), position) : this.set(target, toVars, position);
13085                 };
13086
13087                 p.staggerTo = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
13088                         var tl = new TimelineLite({onComplete:onCompleteAll, onCompleteParams:onCompleteAllParams, onCompleteScope:onCompleteAllScope, smoothChildTiming:this.smoothChildTiming}),
13089                                 i;
13090                         if (typeof(targets) === "string") {
13091                                 targets = TweenLite.selector(targets) || targets;
13092                         }
13093                         if (_isSelector(targets)) { //senses if the targets object is a selector. If it is, we should translate it into an array.
13094                                 targets = _slice.call(targets, 0);
13095                         }
13096                         stagger = stagger || 0;
13097                         for (i = 0; i < targets.length; i++) {
13098                                 if (vars.startAt) {
13099                                         vars.startAt = _copy(vars.startAt);
13100                                 }
13101                                 tl.to(targets[i], duration, _copy(vars), i * stagger);
13102                         }
13103                         return this.add(tl, position);
13104                 };
13105
13106                 p.staggerFrom = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
13107                         vars.immediateRender = (vars.immediateRender != false);
13108                         vars.runBackwards = true;
13109                         return this.staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
13110                 };
13111
13112                 p.staggerFromTo = function(targets, duration, fromVars, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
13113                         toVars.startAt = fromVars;
13114                         toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
13115                         return this.staggerTo(targets, duration, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
13116                 };
13117
13118                 p.call = function(callback, params, scope, position) {
13119                         return this.add( TweenLite.delayedCall(0, callback, params, scope), position);
13120                 };
13121
13122                 p.set = function(target, vars, position) {
13123                         position = this._parseTimeOrLabel(position, 0, true);
13124                         if (vars.immediateRender == null) {
13125                                 vars.immediateRender = (position === this._time && !this._paused);
13126                         }
13127                         return this.add( new TweenLite(target, 0, vars), position);
13128                 };
13129
13130                 TimelineLite.exportRoot = function(vars, ignoreDelayedCalls) {
13131                         vars = vars || {};
13132                         if (vars.smoothChildTiming == null) {
13133                                 vars.smoothChildTiming = true;
13134                         }
13135                         var tl = new TimelineLite(vars),
13136                                 root = tl._timeline,
13137                                 tween, next;
13138                         if (ignoreDelayedCalls == null) {
13139                                 ignoreDelayedCalls = true;
13140                         }
13141                         root._remove(tl, true);
13142                         tl._startTime = 0;
13143                         tl._rawPrevTime = tl._time = tl._totalTime = root._time;
13144                         tween = root._first;
13145                         while (tween) {
13146                                 next = tween._next;
13147                                 if (!ignoreDelayedCalls || !(tween instanceof TweenLite && tween.target === tween.vars.onComplete)) {
13148                                         tl.add(tween, tween._startTime - tween._delay);
13149                                 }
13150                                 tween = next;
13151                         }
13152                         root.add(tl, 0);
13153                         return tl;
13154                 };
13155
13156                 p.add = function(value, position, align, stagger) {
13157                         var curTime, l, i, child, tl, beforeRawTime;
13158                         if (typeof(position) !== "number") {
13159                                 position = this._parseTimeOrLabel(position, 0, true, value);
13160                         }
13161                         if (!(value instanceof Animation)) {
13162                                 if ((value instanceof Array) || (value && value.push && _isArray(value))) {
13163                                         align = align || "normal";
13164                                         stagger = stagger || 0;
13165                                         curTime = position;
13166                                         l = value.length;
13167                                         for (i = 0; i < l; i++) {
13168                                                 if (_isArray(child = value[i])) {
13169                                                         child = new TimelineLite({tweens:child});
13170                                                 }
13171                                                 this.add(child, curTime);
13172                                                 if (typeof(child) !== "string" && typeof(child) !== "function") {
13173                                                         if (align === "sequence") {
13174                                                                 curTime = child._startTime + (child.totalDuration() / child._timeScale);
13175                                                         } else if (align === "start") {
13176                                                                 child._startTime -= child.delay();
13177                                                         }
13178                                                 }
13179                                                 curTime += stagger;
13180                                         }
13181                                         return this._uncache(true);
13182                                 } else if (typeof(value) === "string") {
13183                                         return this.addLabel(value, position);
13184                                 } else if (typeof(value) === "function") {
13185                                         value = TweenLite.delayedCall(0, value);
13186                                 } else {
13187                                         throw("Cannot add " + value + " into the timeline; it is not a tween, timeline, function, or string.");
13188                                 }
13189                         }
13190
13191                         SimpleTimeline.prototype.add.call(this, value, position);
13192
13193                         //if the timeline has already ended but the inserted tween/timeline extends the duration, we should enable this timeline again so that it renders properly. We should also align the playhead with the parent timeline's when appropriate.
13194                         if (this._gc || this._time === this._duration) if (!this._paused) if (this._duration < this.duration()) {
13195                                 //in case any of the ancestors had completed but should now be enabled...
13196                                 tl = this;
13197                                 beforeRawTime = (tl.rawTime() > value._startTime); //if the tween is placed on the timeline so that it starts BEFORE the current rawTime, we should align the playhead (move the timeline). This is because sometimes users will create a timeline, let it finish, and much later append a tween and expect it to run instead of jumping to its end state. While technically one could argue that it should jump to its end state, that's not what users intuitively expect.
13198                                 while (tl._timeline) {
13199                                         if (beforeRawTime && tl._timeline.smoothChildTiming) {
13200                                                 tl.totalTime(tl._totalTime, true); //moves the timeline (shifts its startTime) if necessary, and also enables it.
13201                                         } else if (tl._gc) {
13202                                                 tl._enabled(true, false);
13203                                         }
13204                                         tl = tl._timeline;
13205                                 }
13206                         }
13207
13208                         return this;
13209                 };
13210
13211                 p.remove = function(value) {
13212                         if (value instanceof Animation) {
13213                                 return this._remove(value, false);
13214                         } else if (value instanceof Array || (value && value.push && _isArray(value))) {
13215                                 var i = value.length;
13216                                 while (--i > -1) {
13217                                         this.remove(value[i]);
13218                                 }
13219                                 return this;
13220                         } else if (typeof(value) === "string") {
13221                                 return this.removeLabel(value);
13222                         }
13223                         return this.kill(null, value);
13224                 };
13225
13226                 p._remove = function(tween, skipDisable) {
13227                         SimpleTimeline.prototype._remove.call(this, tween, skipDisable);
13228                         var last = this._last;
13229                         if (!last) {
13230                                 this._time = this._totalTime = this._duration = this._totalDuration = 0;
13231                         } else if (this._time > last._startTime + last._totalDuration / last._timeScale) {
13232                                 this._time = this.duration();
13233                                 this._totalTime = this._totalDuration;
13234                         }
13235                         return this;
13236                 };
13237
13238                 p.append = function(value, offsetOrLabel) {
13239                         return this.add(value, this._parseTimeOrLabel(null, offsetOrLabel, true, value));
13240                 };
13241
13242                 p.insert = p.insertMultiple = function(value, position, align, stagger) {
13243                         return this.add(value, position || 0, align, stagger);
13244                 };
13245
13246                 p.appendMultiple = function(tweens, offsetOrLabel, align, stagger) {
13247                         return this.add(tweens, this._parseTimeOrLabel(null, offsetOrLabel, true, tweens), align, stagger);
13248                 };
13249
13250                 p.addLabel = function(label, position) {
13251                         this._labels[label] = this._parseTimeOrLabel(position);
13252                         return this;
13253                 };
13254
13255                 p.addPause = function(position, callback, params, scope) {
13256                         return this.call(_pauseCallback, ["{self}", callback, params, scope], this, position);
13257                 };
13258
13259                 p.removeLabel = function(label) {
13260                         delete this._labels[label];
13261                         return this;
13262                 };
13263
13264                 p.getLabelTime = function(label) {
13265                         return (this._labels[label] != null) ? this._labels[label] : -1;
13266                 };
13267
13268                 p._parseTimeOrLabel = function(timeOrLabel, offsetOrLabel, appendIfAbsent, ignore) {
13269                         var i;
13270                         //if we're about to add a tween/timeline (or an array of them) that's already a child of this timeline, we should remove it first so that it doesn't contaminate the duration().
13271                         if (ignore instanceof Animation && ignore.timeline === this) {
13272                                 this.remove(ignore);
13273                         } else if (ignore && ((ignore instanceof Array) || (ignore.push && _isArray(ignore)))) {
13274                                 i = ignore.length;
13275                                 while (--i > -1) {
13276                                         if (ignore[i] instanceof Animation && ignore[i].timeline === this) {
13277                                                 this.remove(ignore[i]);
13278                                         }
13279                                 }
13280                         }
13281                         if (typeof(offsetOrLabel) === "string") {
13282                                 return this._parseTimeOrLabel(offsetOrLabel, (appendIfAbsent && typeof(timeOrLabel) === "number" && this._labels[offsetOrLabel] == null) ? timeOrLabel - this.duration() : 0, appendIfAbsent);
13283                         }
13284                         offsetOrLabel = offsetOrLabel || 0;
13285                         if (typeof(timeOrLabel) === "string" && (isNaN(timeOrLabel) || this._labels[timeOrLabel] != null)) { //if the string is a number like "1", check to see if there's a label with that name, otherwise interpret it as a number (absolute value).
13286                                 i = timeOrLabel.indexOf("=");
13287                                 if (i === -1) {
13288                                         if (this._labels[timeOrLabel] == null) {
13289                                                 return appendIfAbsent ? (this._labels[timeOrLabel] = this.duration() + offsetOrLabel) : offsetOrLabel;
13290                                         }
13291                                         return this._labels[timeOrLabel] + offsetOrLabel;
13292                                 }
13293                                 offsetOrLabel = parseInt(timeOrLabel.charAt(i-1) + "1", 10) * Number(timeOrLabel.substr(i+1));
13294                                 timeOrLabel = (i > 1) ? this._parseTimeOrLabel(timeOrLabel.substr(0, i-1), 0, appendIfAbsent) : this.duration();
13295                         } else if (timeOrLabel == null) {
13296                                 timeOrLabel = this.duration();
13297                         }
13298                         return Number(timeOrLabel) + offsetOrLabel;
13299                 };
13300
13301                 p.seek = function(position, suppressEvents) {
13302                         return this.totalTime((typeof(position) === "number") ? position : this._parseTimeOrLabel(position), (suppressEvents !== false));
13303                 };
13304
13305                 p.stop = function() {
13306                         return this.paused(true);
13307                 };
13308
13309                 p.gotoAndPlay = function(position, suppressEvents) {
13310                         return this.play(position, suppressEvents);
13311                 };
13312
13313                 p.gotoAndStop = function(position, suppressEvents) {
13314                         return this.pause(position, suppressEvents);
13315                 };
13316
13317                 p.render = function(time, suppressEvents, force) {
13318                         if (this._gc) {
13319                                 this._enabled(true, false);
13320                         }
13321                         var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
13322                                 prevTime = this._time,
13323                                 prevStart = this._startTime,
13324                                 prevTimeScale = this._timeScale,
13325                                 prevPaused = this._paused,
13326                                 tween, isComplete, next, callback, internalForce;
13327                         if (time >= totalDur) {
13328                                 this._totalTime = this._time = totalDur;
13329                                 if (!this._reversed) if (!this._hasPausedChild()) {
13330                                         isComplete = true;
13331                                         callback = "onComplete";
13332                                         if (this._duration === 0) if (time === 0 || this._rawPrevTime < 0 || this._rawPrevTime === _tinyNum) if (this._rawPrevTime !== time && this._first) {
13333                                                 internalForce = true;
13334                                                 if (this._rawPrevTime > _tinyNum) {
13335                                                         callback = "onReverseComplete";
13336                                                 }
13337                                         }
13338                                 }
13339                                 this._rawPrevTime = (this._duration || !suppressEvents || time || this._rawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration timeline or tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient.
13340                                 time = totalDur + 0.0001; //to avoid occasional floating point rounding errors - sometimes child tweens/timelines were not being fully completed (their progress might be 0.999999999999998 instead of 1 because when _time - tween._startTime is performed, floating point errors would return a value that was SLIGHTLY off). Try (999999999999.7 - 999999999999) * 1 = 0.699951171875 instead of 0.7.
13341
13342                         } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
13343                                 this._totalTime = this._time = 0;
13344                                 if (prevTime !== 0 || (this._duration === 0 && this._rawPrevTime !== _tinyNum && (this._rawPrevTime > 0 || (time < 0 && this._rawPrevTime >= 0)))) {
13345                                         callback = "onReverseComplete";
13346                                         isComplete = this._reversed;
13347                                 }
13348                                 if (time < 0) {
13349                                         this._active = false;
13350                                         if (this._duration === 0) if (this._rawPrevTime >= 0 && this._first) { //zero-duration timelines are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
13351                                                 internalForce = true;
13352                                         }
13353                                         this._rawPrevTime = time;
13354                                 } else {
13355                                         this._rawPrevTime = (this._duration || !suppressEvents || time || this._rawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration timeline or tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient.
13356
13357                                         time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline)
13358                                         if (!this._initted) {
13359                                                 internalForce = true;
13360                                         }
13361                                 }
13362
13363                         } else {
13364                                 this._totalTime = this._time = this._rawPrevTime = time;
13365                         }
13366                         if ((this._time === prevTime || !this._first) && !force && !internalForce) {
13367                                 return;
13368                         } else if (!this._initted) {
13369                                 this._initted = true;
13370                         }
13371
13372                         if (!this._active) if (!this._paused && this._time !== prevTime && time > 0) {
13373                                 this._active = true;  //so that if the user renders the timeline (as opposed to the parent timeline rendering it), it is forced to re-render and align it with the proper time/frame on the next rendering cycle. Maybe the timeline already finished but the user manually re-renders it as halfway done, for example.
13374                         }
13375
13376                         if (prevTime === 0) if (this.vars.onStart) if (this._time !== 0) if (!suppressEvents) {
13377                                 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
13378                         }
13379
13380                         if (this._time >= prevTime) {
13381                                 tween = this._first;
13382                                 while (tween) {
13383                                         next = tween._next; //record it here because the value could change after rendering...
13384                                         if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
13385                                                 break;
13386                                         } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) {
13387                                                 if (!tween._reversed) {
13388                                                         tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
13389                                                 } else {
13390                                                         tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
13391                                                 }
13392                                         }
13393                                         tween = next;
13394                                 }
13395                         } else {
13396                                 tween = this._last;
13397                                 while (tween) {
13398                                         next = tween._prev; //record it here because the value could change after rendering...
13399                                         if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
13400                                                 break;
13401                                         } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) {
13402                                                 if (!tween._reversed) {
13403                                                         tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
13404                                                 } else {
13405                                                         tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
13406                                                 }
13407                                         }
13408                                         tween = next;
13409                                 }
13410                         }
13411
13412                         if (this._onUpdate) if (!suppressEvents) {
13413                                 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
13414                         }
13415
13416                         if (callback) if (!this._gc) if (prevStart === this._startTime || prevTimeScale !== this._timeScale) if (this._time === 0 || totalDur >= this.totalDuration()) { //if one of the tweens that was rendered altered this timeline's startTime (like if an onComplete reversed the timeline), it probably isn't complete. If it is, don't worry, because whatever call altered the startTime would complete if it was necessary at the new time. The only exception is the timeScale property. Also check _gc because there's a chance that kill() could be called in an onUpdate
13417                                 if (isComplete) {
13418                                         if (this._timeline.autoRemoveChildren) {
13419                                                 this._enabled(false, false);
13420                                         }
13421                                         this._active = false;
13422                                 }
13423                                 if (!suppressEvents && this.vars[callback]) {
13424                                         this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
13425                                 }
13426                         }
13427                 };
13428
13429                 p._hasPausedChild = function() {
13430                         var tween = this._first;
13431                         while (tween) {
13432                                 if (tween._paused || ((tween instanceof TimelineLite) && tween._hasPausedChild())) {
13433                                         return true;
13434                                 }
13435                                 tween = tween._next;
13436                         }
13437                         return false;
13438                 };
13439
13440                 p.getChildren = function(nested, tweens, timelines, ignoreBeforeTime) {
13441                         ignoreBeforeTime = ignoreBeforeTime || -9999999999;
13442                         var a = [],
13443                                 tween = this._first,
13444                                 cnt = 0;
13445                         while (tween) {
13446                                 if (tween._startTime < ignoreBeforeTime) {
13447                                         //do nothing
13448                                 } else if (tween instanceof TweenLite) {
13449                                         if (tweens !== false) {
13450                                                 a[cnt++] = tween;
13451                                         }
13452                                 } else {
13453                                         if (timelines !== false) {
13454                                                 a[cnt++] = tween;
13455                                         }
13456                                         if (nested !== false) {
13457                                                 a = a.concat(tween.getChildren(true, tweens, timelines));
13458                                                 cnt = a.length;
13459                                         }
13460                                 }
13461                                 tween = tween._next;
13462                         }
13463                         return a;
13464                 };
13465
13466                 p.getTweensOf = function(target, nested) {
13467                         var disabled = this._gc,
13468                                 a = [],
13469                                 cnt = 0,
13470                                 tweens, i;
13471                         if (disabled) {
13472                                 this._enabled(true, true); //getTweensOf() filters out disabled tweens, and we have to mark them as _gc = true when the timeline completes in order to allow clean garbage collection, so temporarily re-enable the timeline here.
13473                         }
13474                         tweens = TweenLite.getTweensOf(target);
13475                         i = tweens.length;
13476                         while (--i > -1) {
13477                                 if (tweens[i].timeline === this || (nested && this._contains(tweens[i]))) {
13478                                         a[cnt++] = tweens[i];
13479                                 }
13480                         }
13481                         if (disabled) {
13482                                 this._enabled(false, true);
13483                         }
13484                         return a;
13485                 };
13486
13487                 p._contains = function(tween) {
13488                         var tl = tween.timeline;
13489                         while (tl) {
13490                                 if (tl === this) {
13491                                         return true;
13492                                 }
13493                                 tl = tl.timeline;
13494                         }
13495                         return false;
13496                 };
13497
13498                 p.shiftChildren = function(amount, adjustLabels, ignoreBeforeTime) {
13499                         ignoreBeforeTime = ignoreBeforeTime || 0;
13500                         var tween = this._first,
13501                                 labels = this._labels,
13502                                 p;
13503                         while (tween) {
13504                                 if (tween._startTime >= ignoreBeforeTime) {
13505                                         tween._startTime += amount;
13506                                 }
13507                                 tween = tween._next;
13508                         }
13509                         if (adjustLabels) {
13510                                 for (p in labels) {
13511                                         if (labels[p] >= ignoreBeforeTime) {
13512                                                 labels[p] += amount;
13513                                         }
13514                                 }
13515                         }
13516                         return this._uncache(true);
13517                 };
13518
13519                 p._kill = function(vars, target) {
13520                         if (!vars && !target) {
13521                                 return this._enabled(false, false);
13522                         }
13523                         var tweens = (!target) ? this.getChildren(true, true, false) : this.getTweensOf(target),
13524                                 i = tweens.length,
13525                                 changed = false;
13526                         while (--i > -1) {
13527                                 if (tweens[i]._kill(vars, target)) {
13528                                         changed = true;
13529                                 }
13530                         }
13531                         return changed;
13532                 };
13533
13534                 p.clear = function(labels) {
13535                         var tweens = this.getChildren(false, true, true),
13536                                 i = tweens.length;
13537                         this._time = this._totalTime = 0;
13538                         while (--i > -1) {
13539                                 tweens[i]._enabled(false, false);
13540                         }
13541                         if (labels !== false) {
13542                                 this._labels = {};
13543                         }
13544                         return this._uncache(true);
13545                 };
13546
13547                 p.invalidate = function() {
13548                         var tween = this._first;
13549                         while (tween) {
13550                                 tween.invalidate();
13551                                 tween = tween._next;
13552                         }
13553                         return this;
13554                 };
13555
13556                 p._enabled = function(enabled, ignoreTimeline) {
13557                         if (enabled === this._gc) {
13558                                 var tween = this._first;
13559                                 while (tween) {
13560                                         tween._enabled(enabled, true);
13561                                         tween = tween._next;
13562                                 }
13563                         }
13564                         return SimpleTimeline.prototype._enabled.call(this, enabled, ignoreTimeline);
13565                 };
13566
13567                 p.duration = function(value) {
13568                         if (!arguments.length) {
13569                                 if (this._dirty) {
13570                                         this.totalDuration(); //just triggers recalculation
13571                                 }
13572                                 return this._duration;
13573                         }
13574                         if (this.duration() !== 0 && value !== 0) {
13575                                 this.timeScale(this._duration / value);
13576                         }
13577                         return this;
13578                 };
13579
13580                 p.totalDuration = function(value) {
13581                         if (!arguments.length) {
13582                                 if (this._dirty) {
13583                                         var max = 0,
13584                                                 tween = this._last,
13585                                                 prevStart = 999999999999,
13586                                                 prev, end;
13587                                         while (tween) {
13588                                                 prev = tween._prev; //record it here in case the tween changes position in the sequence...
13589                                                 if (tween._dirty) {
13590                                                         tween.totalDuration(); //could change the tween._startTime, so make sure the tween's cache is clean before analyzing it.
13591                                                 }
13592                                                 if (tween._startTime > prevStart && this._sortChildren && !tween._paused) { //in case one of the tweens shifted out of order, it needs to be re-inserted into the correct position in the sequence
13593                                                         this.add(tween, tween._startTime - tween._delay);
13594                                                 } else {
13595                                                         prevStart = tween._startTime;
13596                                                 }
13597                                                 if (tween._startTime < 0 && !tween._paused) { //children aren't allowed to have negative startTimes unless smoothChildTiming is true, so adjust here if one is found.
13598                                                         max -= tween._startTime;
13599                                                         if (this._timeline.smoothChildTiming) {
13600                                                                 this._startTime += tween._startTime / this._timeScale;
13601                                                         }
13602                                                         this.shiftChildren(-tween._startTime, false, -9999999999);
13603                                                         prevStart = 0;
13604                                                 }
13605                                                 end = tween._startTime + (tween._totalDuration / tween._timeScale);
13606                                                 if (end > max) {
13607                                                         max = end;
13608                                                 }
13609                                                 tween = prev;
13610                                         }
13611                                         this._duration = this._totalDuration = max;
13612                                         this._dirty = false;
13613                                 }
13614                                 return this._totalDuration;
13615                         }
13616                         if (this.totalDuration() !== 0) if (value !== 0) {
13617                                 this.timeScale(this._totalDuration / value);
13618                         }
13619                         return this;
13620                 };
13621
13622                 p.usesFrames = function() {
13623                         var tl = this._timeline;
13624                         while (tl._timeline) {
13625                                 tl = tl._timeline;
13626                         }
13627                         return (tl === Animation._rootFramesTimeline);
13628                 };
13629
13630                 p.rawTime = function() {
13631                         return this._paused ? this._totalTime : (this._timeline.rawTime() - this._startTime) * this._timeScale;
13632                 };
13633
13634                 return TimelineLite;
13635
13636         }, true);
13637         
13638
13639
13640
13641
13642
13643
13644
13645         
13646         
13647         
13648         
13649         
13650 /*
13651  * ----------------------------------------------------------------
13652  * TimelineMax
13653  * ----------------------------------------------------------------
13654  */
13655         window._gsDefine("TimelineMax", ["TimelineLite","TweenLite","easing.Ease"], function(TimelineLite, TweenLite, Ease) {
13656
13657                 var TimelineMax = function(vars) {
13658                                 TimelineLite.call(this, vars);
13659                                 this._repeat = this.vars.repeat || 0;
13660                                 this._repeatDelay = this.vars.repeatDelay || 0;
13661                                 this._cycle = 0;
13662                                 this._yoyo = (this.vars.yoyo === true);
13663                                 this._dirty = true;
13664                         },
13665                         _tinyNum = 0.0000000001,
13666                         _blankArray = [],
13667                         _easeNone = new Ease(null, null, 1, 0),
13668                         p = TimelineMax.prototype = new TimelineLite();
13669
13670                 p.constructor = TimelineMax;
13671                 p.kill()._gc = false;
13672                 TimelineMax.version = "1.12.1";
13673
13674                 p.invalidate = function() {
13675                         this._yoyo = (this.vars.yoyo === true);
13676                         this._repeat = this.vars.repeat || 0;
13677                         this._repeatDelay = this.vars.repeatDelay || 0;
13678                         this._uncache(true);
13679                         return TimelineLite.prototype.invalidate.call(this);
13680                 };
13681
13682                 p.addCallback = function(callback, position, params, scope) {
13683                         return this.add( TweenLite.delayedCall(0, callback, params, scope), position);
13684                 };
13685
13686                 p.removeCallback = function(callback, position) {
13687                         if (callback) {
13688                                 if (position == null) {
13689                                         this._kill(null, callback);
13690                                 } else {
13691                                         var a = this.getTweensOf(callback, false),
13692                                                 i = a.length,
13693                                                 time = this._parseTimeOrLabel(position);
13694                                         while (--i > -1) {
13695                                                 if (a[i]._startTime === time) {
13696                                                         a[i]._enabled(false, false);
13697                                                 }
13698                                         }
13699                                 }
13700                         }
13701                         return this;
13702                 };
13703
13704                 p.tweenTo = function(position, vars) {
13705                         vars = vars || {};
13706                         var copy = {ease:_easeNone, overwrite:(vars.delay ? 2 : 1), useFrames:this.usesFrames(), immediateRender:false},//note: set overwrite to 1 (true/all) by default unless there's a delay so that we avoid a racing situation that could happen if, for example, an onmousemove creates the same tweenTo() over and over again.
13707                                 duration, p, t;
13708                         for (p in vars) {
13709                                 copy[p] = vars[p];
13710                         }
13711                         copy.time = this._parseTimeOrLabel(position);
13712                         duration = (Math.abs(Number(copy.time) - this._time) / this._timeScale) || 0.001;
13713                         t = new TweenLite(this, duration, copy);
13714                         copy.onStart = function() {
13715                                 t.target.paused(true);
13716                                 if (t.vars.time !== t.target.time() && duration === t.duration()) { //don't make the duration zero - if it's supposed to be zero, don't worry because it's already initting the tween and will complete immediately, effectively making the duration zero anyway. If we make duration zero, the tween won't run at all.
13717                                         t.duration( Math.abs( t.vars.time - t.target.time()) / t.target._timeScale );
13718                                 }
13719                                 if (vars.onStart) { //in case the user had an onStart in the vars - we don't want to overwrite it.
13720                                         vars.onStart.apply(vars.onStartScope || t, vars.onStartParams || _blankArray);
13721                                 }
13722                         };
13723                         return t;
13724                 };
13725
13726                 p.tweenFromTo = function(fromPosition, toPosition, vars) {
13727                         vars = vars || {};
13728                         fromPosition = this._parseTimeOrLabel(fromPosition);
13729                         vars.startAt = {onComplete:this.seek, onCompleteParams:[fromPosition], onCompleteScope:this};
13730                         vars.immediateRender = (vars.immediateRender !== false);
13731                         var t = this.tweenTo(toPosition, vars);
13732                         return t.duration((Math.abs( t.vars.time - fromPosition) / this._timeScale) || 0.001);
13733                 };
13734
13735                 p.render = function(time, suppressEvents, force) {
13736                         if (this._gc) {
13737                                 this._enabled(true, false);
13738                         }
13739                         var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
13740                                 dur = this._duration,
13741                                 prevTime = this._time,
13742                                 prevTotalTime = this._totalTime,
13743                                 prevStart = this._startTime,
13744                                 prevTimeScale = this._timeScale,
13745                                 prevRawPrevTime = this._rawPrevTime,
13746                                 prevPaused = this._paused,
13747                                 prevCycle = this._cycle,
13748                                 tween, isComplete, next, callback, internalForce, cycleDuration;
13749                         if (time >= totalDur) {
13750                                 if (!this._locked) {
13751                                         this._totalTime = totalDur;
13752                                         this._cycle = this._repeat;
13753                                 }
13754                                 if (!this._reversed) if (!this._hasPausedChild()) {
13755                                         isComplete = true;
13756                                         callback = "onComplete";
13757                                         if (this._duration === 0) if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time && this._first) {
13758                                                 internalForce = true;
13759                                                 if (prevRawPrevTime > _tinyNum) {
13760                                                         callback = "onReverseComplete";
13761                                                 }
13762                                         }
13763                                 }
13764                                 this._rawPrevTime = (this._duration || !suppressEvents || time || this._rawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration timeline or tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient.
13765                                 if (this._yoyo && (this._cycle & 1) !== 0) {
13766                                         this._time = time = 0;
13767                                 } else {
13768                                         this._time = dur;
13769                                         time = dur + 0.0001; //to avoid occasional floating point rounding errors - sometimes child tweens/timelines were not being fully completed (their progress might be 0.999999999999998 instead of 1 because when _time - tween._startTime is performed, floating point errors would return a value that was SLIGHTLY off). Try (999999999999.7 - 999999999999) * 1 = 0.699951171875 instead of 0.7. We cannot do less then 0.0001 because the same issue can occur when the duration is extremely large like 999999999999 in which case adding 0.00000001, for example, causes it to act like nothing was added.
13770                                 }
13771
13772                         } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
13773                                 if (!this._locked) {
13774                                         this._totalTime = this._cycle = 0;
13775                                 }
13776                                 this._time = 0;
13777                                 if (prevTime !== 0 || (dur === 0 && prevRawPrevTime !== _tinyNum && (prevRawPrevTime > 0 || (time < 0 && prevRawPrevTime >= 0)) && !this._locked)) { //edge case for checking time < 0 && prevRawPrevTime >= 0: a zero-duration fromTo() tween inside a zero-duration timeline (yeah, very rare)
13778                                         callback = "onReverseComplete";
13779                                         isComplete = this._reversed;
13780                                 }
13781                                 if (time < 0) {
13782                                         this._active = false;
13783                                         if (dur === 0) if (prevRawPrevTime >= 0 && this._first) { //zero-duration timelines are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
13784                                                 internalForce = true;
13785                                         }
13786                                         this._rawPrevTime = time;
13787                                 } else {
13788                                         this._rawPrevTime = (dur || !suppressEvents || time || this._rawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration timeline or tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient.
13789                                         time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline)
13790                                         if (!this._initted) {
13791                                                 internalForce = true;
13792                                         }
13793                                 }
13794
13795                         } else {
13796                                 if (dur === 0 && prevRawPrevTime < 0) { //without this, zero-duration repeating timelines (like with a simple callback nested at the very beginning and a repeatDelay) wouldn't render the first time through.
13797                                         internalForce = true;
13798                                 }
13799                                 this._time = this._rawPrevTime = time;
13800                                 if (!this._locked) {
13801                                         this._totalTime = time;
13802                                         if (this._repeat !== 0) {
13803                                                 cycleDuration = dur + this._repeatDelay;
13804                                                 this._cycle = (this._totalTime / cycleDuration) >> 0; //originally _totalTime % cycleDuration but floating point errors caused problems, so I normalized it. (4 % 0.8 should be 0 but it gets reported as 0.79999999!)
13805                                                 if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) {
13806                                                         this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning)
13807                                                 }
13808                                                 this._time = this._totalTime - (this._cycle * cycleDuration);
13809                                                 if (this._yoyo) if ((this._cycle & 1) !== 0) {
13810                                                         this._time = dur - this._time;
13811                                                 }
13812                                                 if (this._time > dur) {
13813                                                         this._time = dur;
13814                                                         time = dur + 0.0001; //to avoid occasional floating point rounding error
13815                                                 } else if (this._time < 0) {
13816                                                         this._time = time = 0;
13817                                                 } else {
13818                                                         time = this._time;
13819                                                 }
13820                                         }
13821                                 }
13822                         }
13823
13824                         if (this._cycle !== prevCycle) if (!this._locked) {
13825                                 /*
13826                                 make sure children at the end/beginning of the timeline are rendered properly. If, for example,
13827                                 a 3-second long timeline rendered at 2.9 seconds previously, and now renders at 3.2 seconds (which
13828                                 would get transated to 2.8 seconds if the timeline yoyos or 0.2 seconds if it just repeats), there
13829                                 could be a callback or a short tween that's at 2.95 or 3 seconds in which wouldn't render. So
13830                                 we need to push the timeline to the end (and/or beginning depending on its yoyo value). Also we must
13831                                 ensure that zero-duration tweens at the very beginning or end of the TimelineMax work.
13832                                 */
13833                                 var backwards = (this._yoyo && (prevCycle & 1) !== 0),
13834                                         wrap = (backwards === (this._yoyo && (this._cycle & 1) !== 0)),
13835                                         recTotalTime = this._totalTime,
13836                                         recCycle = this._cycle,
13837                                         recRawPrevTime = this._rawPrevTime,
13838                                         recTime = this._time;
13839
13840                                 this._totalTime = prevCycle * dur;
13841                                 if (this._cycle < prevCycle) {
13842                                         backwards = !backwards;
13843                                 } else {
13844                                         this._totalTime += dur;
13845                                 }
13846                                 this._time = prevTime; //temporarily revert _time so that render() renders the children in the correct order. Without this, tweens won't rewind correctly. We could arhictect things in a "cleaner" way by splitting out the rendering queue into a separate method but for performance reasons, we kept it all inside this method.
13847
13848                                 this._rawPrevTime = (dur === 0) ? prevRawPrevTime - 0.0001 : prevRawPrevTime;
13849                                 this._cycle = prevCycle;
13850                                 this._locked = true; //prevents changes to totalTime and skips repeat/yoyo behavior when we recursively call render()
13851                                 prevTime = (backwards) ? 0 : dur;
13852                                 this.render(prevTime, suppressEvents, (dur === 0));
13853                                 if (!suppressEvents) if (!this._gc) {
13854                                         if (this.vars.onRepeat) {
13855                                                 this.vars.onRepeat.apply(this.vars.onRepeatScope || this, this.vars.onRepeatParams || _blankArray);
13856                                         }
13857                                 }
13858                                 if (wrap) {
13859                                         prevTime = (backwards) ? dur + 0.0001 : -0.0001;
13860                                         this.render(prevTime, true, false);
13861                                 }
13862                                 this._locked = false;
13863                                 if (this._paused && !prevPaused) { //if the render() triggered callback that paused this timeline, we should abort (very rare, but possible)
13864                                         return;
13865                                 }
13866                                 this._time = recTime;
13867                                 this._totalTime = recTotalTime;
13868                                 this._cycle = recCycle;
13869                                 this._rawPrevTime = recRawPrevTime;
13870                         }
13871
13872                         if ((this._time === prevTime || !this._first) && !force && !internalForce) {
13873                                 if (prevTotalTime !== this._totalTime) if (this._onUpdate) if (!suppressEvents) { //so that onUpdate fires even during the repeatDelay - as long as the totalTime changed, we should trigger onUpdate.
13874                                         this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
13875                                 }
13876                                 return;
13877                         } else if (!this._initted) {
13878                                 this._initted = true;
13879                         }
13880
13881                         if (!this._active) if (!this._paused && this._totalTime !== prevTotalTime && time > 0) {
13882                                 this._active = true;  //so that if the user renders the timeline (as opposed to the parent timeline rendering it), it is forced to re-render and align it with the proper time/frame on the next rendering cycle. Maybe the timeline already finished but the user manually re-renders it as halfway done, for example.
13883                         }
13884
13885                         if (prevTotalTime === 0) if (this.vars.onStart) if (this._totalTime !== 0) if (!suppressEvents) {
13886                                 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
13887                         }
13888
13889                         if (this._time >= prevTime) {
13890                                 tween = this._first;
13891                                 while (tween) {
13892                                         next = tween._next; //record it here because the value could change after rendering...
13893                                         if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
13894                                                 break;
13895                                         } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) {
13896                                                 if (!tween._reversed) {
13897                                                         tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
13898                                                 } else {
13899                                                         tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
13900                                                 }
13901
13902                                         }
13903                                         tween = next;
13904                                 }
13905                         } else {
13906                                 tween = this._last;
13907                                 while (tween) {
13908                                         next = tween._prev; //record it here because the value could change after rendering...
13909                                         if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
13910                                                 break;
13911                                         } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) {
13912                                                 if (!tween._reversed) {
13913                                                         tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
13914                                                 } else {
13915                                                         tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
13916                                                 }
13917                                         }
13918                                         tween = next;
13919                                 }
13920                         }
13921
13922                         if (this._onUpdate) if (!suppressEvents) {
13923                                 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
13924                         }
13925                         if (callback) if (!this._locked) if (!this._gc) if (prevStart === this._startTime || prevTimeScale !== this._timeScale) if (this._time === 0 || totalDur >= this.totalDuration()) { //if one of the tweens that was rendered altered this timeline's startTime (like if an onComplete reversed the timeline), it probably isn't complete. If it is, don't worry, because whatever call altered the startTime would complete if it was necessary at the new time. The only exception is the timeScale property. Also check _gc because there's a chance that kill() could be called in an onUpdate
13926                                 if (isComplete) {
13927                                         if (this._timeline.autoRemoveChildren) {
13928                                                 this._enabled(false, false);
13929                                         }
13930                                         this._active = false;
13931                                 }
13932                                 if (!suppressEvents && this.vars[callback]) {
13933                                         this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
13934                                 }
13935                         }
13936                 };
13937
13938                 p.getActive = function(nested, tweens, timelines) {
13939                         if (nested == null) {
13940                                 nested = true;
13941                         }
13942                         if (tweens == null) {
13943                                 tweens = true;
13944                         }
13945                         if (timelines == null) {
13946                                 timelines = false;
13947                         }
13948                         var a = [],
13949                                 all = this.getChildren(nested, tweens, timelines),
13950                                 cnt = 0,
13951                                 l = all.length,
13952                                 i, tween;
13953                         for (i = 0; i < l; i++) {
13954                                 tween = all[i];
13955                                 if (tween.isActive()) {
13956                                         a[cnt++] = tween;
13957                                 }
13958                         }
13959                         return a;
13960                 };
13961
13962
13963                 p.getLabelAfter = function(time) {
13964                         if (!time) if (time !== 0) { //faster than isNan()
13965                                 time = this._time;
13966                         }
13967                         var labels = this.getLabelsArray(),
13968                                 l = labels.length,
13969                                 i;
13970                         for (i = 0; i < l; i++) {
13971                                 if (labels[i].time > time) {
13972                                         return labels[i].name;
13973                                 }
13974                         }
13975                         return null;
13976                 };
13977
13978                 p.getLabelBefore = function(time) {
13979                         if (time == null) {
13980                                 time = this._time;
13981                         }
13982                         var labels = this.getLabelsArray(),
13983                                 i = labels.length;
13984                         while (--i > -1) {
13985                                 if (labels[i].time < time) {
13986                                         return labels[i].name;
13987                                 }
13988                         }
13989                         return null;
13990                 };
13991
13992                 p.getLabelsArray = function() {
13993                         var a = [],
13994                                 cnt = 0,
13995                                 p;
13996                         for (p in this._labels) {
13997                                 a[cnt++] = {time:this._labels[p], name:p};
13998                         }
13999                         a.sort(function(a,b) {
14000                                 return a.time - b.time;
14001                         });
14002                         return a;
14003                 };
14004
14005
14006 //---- GETTERS / SETTERS -------------------------------------------------------------------------------------------------------
14007
14008                 p.progress = function(value) {
14009                         return (!arguments.length) ? this._time / this.duration() : this.totalTime( this.duration() * ((this._yoyo && (this._cycle & 1) !== 0) ? 1 - value : value) + (this._cycle * (this._duration + this._repeatDelay)), false);
14010                 };
14011
14012                 p.totalProgress = function(value) {
14013                         return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, false);
14014                 };
14015
14016                 p.totalDuration = function(value) {
14017                         if (!arguments.length) {
14018                                 if (this._dirty) {
14019                                         TimelineLite.prototype.totalDuration.call(this); //just forces refresh
14020                                         //Instead of Infinity, we use 999999999999 so that we can accommodate reverses.
14021                                         this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat);
14022                                 }
14023                                 return this._totalDuration;
14024                         }
14025                         return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) );
14026                 };
14027
14028                 p.time = function(value, suppressEvents) {
14029                         if (!arguments.length) {
14030                                 return this._time;
14031                         }
14032                         if (this._dirty) {
14033                                 this.totalDuration();
14034                         }
14035                         if (value > this._duration) {
14036                                 value = this._duration;
14037                         }
14038                         if (this._yoyo && (this._cycle & 1) !== 0) {
14039                                 value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay));
14040                         } else if (this._repeat !== 0) {
14041                                 value += this._cycle * (this._duration + this._repeatDelay);
14042                         }
14043                         return this.totalTime(value, suppressEvents);
14044                 };
14045
14046                 p.repeat = function(value) {
14047                         if (!arguments.length) {
14048                                 return this._repeat;
14049                         }
14050                         this._repeat = value;
14051                         return this._uncache(true);
14052                 };
14053
14054                 p.repeatDelay = function(value) {
14055                         if (!arguments.length) {
14056                                 return this._repeatDelay;
14057                         }
14058                         this._repeatDelay = value;
14059                         return this._uncache(true);
14060                 };
14061
14062                 p.yoyo = function(value) {
14063                         if (!arguments.length) {
14064                                 return this._yoyo;
14065                         }
14066                         this._yoyo = value;
14067                         return this;
14068                 };
14069
14070                 p.currentLabel = function(value) {
14071                         if (!arguments.length) {
14072                                 return this.getLabelBefore(this._time + 0.00000001);
14073                         }
14074                         return this.seek(value, true);
14075                 };
14076
14077                 return TimelineMax;
14078
14079         }, true);
14080         
14081
14082
14083
14084
14085         
14086         
14087         
14088         
14089         
14090         
14091         
14092 /*
14093  * ----------------------------------------------------------------
14094  * BezierPlugin
14095  * ----------------------------------------------------------------
14096  */
14097         (function() {
14098
14099                 var _RAD2DEG = 180 / Math.PI,
14100                         _r1 = [],
14101                         _r2 = [],
14102                         _r3 = [],
14103                         _corProps = {},
14104                         Segment = function(a, b, c, d) {
14105                                 this.a = a;
14106                                 this.b = b;
14107                                 this.c = c;
14108                                 this.d = d;
14109                                 this.da = d - a;
14110                                 this.ca = c - a;
14111                                 this.ba = b - a;
14112                         },
14113                         _correlate = ",x,y,z,left,top,right,bottom,marginTop,marginLeft,marginRight,marginBottom,paddingLeft,paddingTop,paddingRight,paddingBottom,backgroundPosition,backgroundPosition_y,",
14114                         cubicToQuadratic = function(a, b, c, d) {
14115                                 var q1 = {a:a},
14116                                         q2 = {},
14117                                         q3 = {},
14118                                         q4 = {c:d},
14119                                         mab = (a + b) / 2,
14120                                         mbc = (b + c) / 2,
14121                                         mcd = (c + d) / 2,
14122                                         mabc = (mab + mbc) / 2,
14123                                         mbcd = (mbc + mcd) / 2,
14124                                         m8 = (mbcd - mabc) / 8;
14125                                 q1.b = mab + (a - mab) / 4;
14126                                 q2.b = mabc + m8;
14127                                 q1.c = q2.a = (q1.b + q2.b) / 2;
14128                                 q2.c = q3.a = (mabc + mbcd) / 2;
14129                                 q3.b = mbcd - m8;
14130                                 q4.b = mcd + (d - mcd) / 4;
14131                                 q3.c = q4.a = (q3.b + q4.b) / 2;
14132                                 return [q1, q2, q3, q4];
14133                         },
14134                         _calculateControlPoints = function(a, curviness, quad, basic, correlate) {
14135                                 var l = a.length - 1,
14136                                         ii = 0,
14137                                         cp1 = a[0].a,
14138                                         i, p1, p2, p3, seg, m1, m2, mm, cp2, qb, r1, r2, tl;
14139                                 for (i = 0; i < l; i++) {
14140                                         seg = a[ii];
14141                                         p1 = seg.a;
14142                                         p2 = seg.d;
14143                                         p3 = a[ii+1].d;
14144
14145                                         if (correlate) {
14146                                                 r1 = _r1[i];
14147                                                 r2 = _r2[i];
14148                                                 tl = ((r2 + r1) * curviness * 0.25) / (basic ? 0.5 : _r3[i] || 0.5);
14149                                                 m1 = p2 - (p2 - p1) * (basic ? curviness * 0.5 : (r1 !== 0 ? tl / r1 : 0));
14150                                                 m2 = p2 + (p3 - p2) * (basic ? curviness * 0.5 : (r2 !== 0 ? tl / r2 : 0));
14151                                                 mm = p2 - (m1 + (((m2 - m1) * ((r1 * 3 / (r1 + r2)) + 0.5) / 4) || 0));
14152                                         } else {
14153                                                 m1 = p2 - (p2 - p1) * curviness * 0.5;
14154                                                 m2 = p2 + (p3 - p2) * curviness * 0.5;
14155                                                 mm = p2 - (m1 + m2) / 2;
14156                                         }
14157                                         m1 += mm;
14158                                         m2 += mm;
14159
14160                                         seg.c = cp2 = m1;
14161                                         if (i !== 0) {
14162                                                 seg.b = cp1;
14163                                         } else {
14164                                                 seg.b = cp1 = seg.a + (seg.c - seg.a) * 0.6; //instead of placing b on a exactly, we move it inline with c so that if the user specifies an ease like Back.easeIn or Elastic.easeIn which goes BEYOND the beginning, it will do so smoothly.
14165                                         }
14166
14167                                         seg.da = p2 - p1;
14168                                         seg.ca = cp2 - p1;
14169                                         seg.ba = cp1 - p1;
14170
14171                                         if (quad) {
14172                                                 qb = cubicToQuadratic(p1, cp1, cp2, p2);
14173                                                 a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]);
14174                                                 ii += 4;
14175                                         } else {
14176                                                 ii++;
14177                                         }
14178
14179                                         cp1 = m2;
14180                                 }
14181                                 seg = a[ii];
14182                                 seg.b = cp1;
14183                                 seg.c = cp1 + (seg.d - cp1) * 0.4; //instead of placing c on d exactly, we move it inline with b so that if the user specifies an ease like Back.easeOut or Elastic.easeOut which goes BEYOND the end, it will do so smoothly.
14184                                 seg.da = seg.d - seg.a;
14185                                 seg.ca = seg.c - seg.a;
14186                                 seg.ba = cp1 - seg.a;
14187                                 if (quad) {
14188                                         qb = cubicToQuadratic(seg.a, cp1, seg.c, seg.d);
14189                                         a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]);
14190                                 }
14191                         },
14192                         _parseAnchors = function(values, p, correlate, prepend) {
14193                                 var a = [],
14194                                         l, i, p1, p2, p3, tmp;
14195                                 if (prepend) {
14196                                         values = [prepend].concat(values);
14197                                         i = values.length;
14198                                         while (--i > -1) {
14199                                                 if (typeof( (tmp = values[i][p]) ) === "string") if (tmp.charAt(1) === "=") {
14200                                                         values[i][p] = prepend[p] + Number(tmp.charAt(0) + tmp.substr(2)); //accommodate relative values. Do it inline instead of breaking it out into a function for speed reasons
14201                                                 }
14202                                         }
14203                                 }
14204                                 l = values.length - 2;
14205                                 if (l < 0) {
14206                                         a[0] = new Segment(values[0][p], 0, 0, values[(l < -1) ? 0 : 1][p]);
14207                                         return a;
14208                                 }
14209                                 for (i = 0; i < l; i++) {
14210                                         p1 = values[i][p];
14211                                         p2 = values[i+1][p];
14212                                         a[i] = new Segment(p1, 0, 0, p2);
14213                                         if (correlate) {
14214                                                 p3 = values[i+2][p];
14215                                                 _r1[i] = (_r1[i] || 0) + (p2 - p1) * (p2 - p1);
14216                                                 _r2[i] = (_r2[i] || 0) + (p3 - p2) * (p3 - p2);
14217                                         }
14218                                 }
14219                                 a[i] = new Segment(values[i][p], 0, 0, values[i+1][p]);
14220                                 return a;
14221                         },
14222                         bezierThrough = function(values, curviness, quadratic, basic, correlate, prepend) {
14223                                 var obj = {},
14224                                         props = [],
14225                                         first = prepend || values[0],
14226                                         i, p, a, j, r, l, seamless, last;
14227                                 correlate = (typeof(correlate) === "string") ? ","+correlate+"," : _correlate;
14228                                 if (curviness == null) {
14229                                         curviness = 1;
14230                                 }
14231                                 for (p in values[0]) {
14232                                         props.push(p);
14233                                 }
14234                                 //check to see if the last and first values are identical (well, within 0.05). If so, make seamless by appending the second element to the very end of the values array and the 2nd-to-last element to the very beginning (we'll remove those segments later)
14235                                 if (values.length > 1) {
14236                                         last = values[values.length - 1];
14237                                         seamless = true;
14238                                         i = props.length;
14239                                         while (--i > -1) {
14240                                                 p = props[i];
14241                                                 if (Math.abs(first[p] - last[p]) > 0.05) { //build in a tolerance of +/-0.05 to accommodate rounding errors. For example, if you set an object's position to 4.945, Flash will make it 4.9
14242                                                         seamless = false;
14243                                                         break;
14244                                                 }
14245                                         }
14246                                         if (seamless) {
14247                                                 values = values.concat(); //duplicate the array to avoid contaminating the original which the user may be reusing for other tweens
14248                                                 if (prepend) {
14249                                                         values.unshift(prepend);
14250                                                 }
14251                                                 values.push(values[1]);
14252                                                 prepend = values[values.length - 3];
14253                                         }
14254                                 }
14255                                 _r1.length = _r2.length = _r3.length = 0;
14256                                 i = props.length;
14257                                 while (--i > -1) {
14258                                         p = props[i];
14259                                         _corProps[p] = (correlate.indexOf(","+p+",") !== -1);
14260                                         obj[p] = _parseAnchors(values, p, _corProps[p], prepend);
14261                                 }
14262                                 i = _r1.length;
14263                                 while (--i > -1) {
14264                                         _r1[i] = Math.sqrt(_r1[i]);
14265                                         _r2[i] = Math.sqrt(_r2[i]);
14266                                 }
14267                                 if (!basic) {
14268                                         i = props.length;
14269                                         while (--i > -1) {
14270                                                 if (_corProps[p]) {
14271                                                         a = obj[props[i]];
14272                                                         l = a.length - 1;
14273                                                         for (j = 0; j < l; j++) {
14274                                                                 r = a[j+1].da / _r2[j] + a[j].da / _r1[j];
14275                                                                 _r3[j] = (_r3[j] || 0) + r * r;
14276                                                         }
14277                                                 }
14278                                         }
14279                                         i = _r3.length;
14280                                         while (--i > -1) {
14281                                                 _r3[i] = Math.sqrt(_r3[i]);
14282                                         }
14283                                 }
14284                                 i = props.length;
14285                                 j = quadratic ? 4 : 1;
14286                                 while (--i > -1) {
14287                                         p = props[i];
14288                                         a = obj[p];
14289                                         _calculateControlPoints(a, curviness, quadratic, basic, _corProps[p]); //this method requires that _parseAnchors() and _setSegmentRatios() ran first so that _r1, _r2, and _r3 values are populated for all properties
14290                                         if (seamless) {
14291                                                 a.splice(0, j);
14292                                                 a.splice(a.length - j, j);
14293                                         }
14294                                 }
14295                                 return obj;
14296                         },
14297                         _parseBezierData = function(values, type, prepend) {
14298                                 type = type || "soft";
14299                                 var obj = {},
14300                                         inc = (type === "cubic") ? 3 : 2,
14301                                         soft = (type === "soft"),
14302                                         props = [],
14303                                         a, b, c, d, cur, i, j, l, p, cnt, tmp;
14304                                 if (soft && prepend) {
14305                                         values = [prepend].concat(values);
14306                                 }
14307                                 if (values == null || values.length < inc + 1) { throw "invalid Bezier data"; }
14308                                 for (p in values[0]) {
14309                                         props.push(p);
14310                                 }
14311                                 i = props.length;
14312                                 while (--i > -1) {
14313                                         p = props[i];
14314                                         obj[p] = cur = [];
14315                                         cnt = 0;
14316                                         l = values.length;
14317                                         for (j = 0; j < l; j++) {
14318                                                 a = (prepend == null) ? values[j][p] : (typeof( (tmp = values[j][p]) ) === "string" && tmp.charAt(1) === "=") ? prepend[p] + Number(tmp.charAt(0) + tmp.substr(2)) : Number(tmp);
14319                                                 if (soft) if (j > 1) if (j < l - 1) {
14320                                                         cur[cnt++] = (a + cur[cnt-2]) / 2;
14321                                                 }
14322                                                 cur[cnt++] = a;
14323                                         }
14324                                         l = cnt - inc + 1;
14325                                         cnt = 0;
14326                                         for (j = 0; j < l; j += inc) {
14327                                                 a = cur[j];
14328                                                 b = cur[j+1];
14329                                                 c = cur[j+2];
14330                                                 d = (inc === 2) ? 0 : cur[j+3];
14331                                                 cur[cnt++] = tmp = (inc === 3) ? new Segment(a, b, c, d) : new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c);
14332                                         }
14333                                         cur.length = cnt;
14334                                 }
14335                                 return obj;
14336                         },
14337                         _addCubicLengths = function(a, steps, resolution) {
14338                                 var inc = 1 / resolution,
14339                                         j = a.length,
14340                                         d, d1, s, da, ca, ba, p, i, inv, bez, index;
14341                                 while (--j > -1) {
14342                                         bez = a[j];
14343                                         s = bez.a;
14344                                         da = bez.d - s;
14345                                         ca = bez.c - s;
14346                                         ba = bez.b - s;
14347                                         d = d1 = 0;
14348                                         for (i = 1; i <= resolution; i++) {
14349                                                 p = inc * i;
14350                                                 inv = 1 - p;
14351                                                 d = d1 - (d1 = (p * p * da + 3 * inv * (p * ca + inv * ba)) * p);
14352                                                 index = j * resolution + i - 1;
14353                                                 steps[index] = (steps[index] || 0) + d * d;
14354                                         }
14355                                 }
14356                         },
14357                         _parseLengthData = function(obj, resolution) {
14358                                 resolution = resolution >> 0 || 6;
14359                                 var a = [],
14360                                         lengths = [],
14361                                         d = 0,
14362                                         total = 0,
14363                                         threshold = resolution - 1,
14364                                         segments = [],
14365                                         curLS = [], //current length segments array
14366                                         p, i, l, index;
14367                                 for (p in obj) {
14368                                         _addCubicLengths(obj[p], a, resolution);
14369                                 }
14370                                 l = a.length;
14371                                 for (i = 0; i < l; i++) {
14372                                         d += Math.sqrt(a[i]);
14373                                         index = i % resolution;
14374                                         curLS[index] = d;
14375                                         if (index === threshold) {
14376                                                 total += d;
14377                                                 index = (i / resolution) >> 0;
14378                                                 segments[index] = curLS;
14379                                                 lengths[index] = total;
14380                                                 d = 0;
14381                                                 curLS = [];
14382                                         }
14383                                 }
14384                                 return {length:total, lengths:lengths, segments:segments};
14385                         },
14386
14387
14388
14389                         BezierPlugin = window._gsDefine.plugin({
14390                                         propName: "bezier",
14391                                         priority: -1,
14392                                         version: "1.3.2",
14393                                         API: 2,
14394                                         global:true,
14395
14396                                         //gets called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
14397                                         init: function(target, vars, tween) {
14398                                                 this._target = target;
14399                                                 if (vars instanceof Array) {
14400                                                         vars = {values:vars};
14401                                                 }
14402                                                 this._func = {};
14403                                                 this._round = {};
14404                                                 this._props = [];
14405                                                 this._timeRes = (vars.timeResolution == null) ? 6 : parseInt(vars.timeResolution, 10);
14406                                                 var values = vars.values || [],
14407                                                         first = {},
14408                                                         second = values[0],
14409                                                         autoRotate = vars.autoRotate || tween.vars.orientToBezier,
14410                                                         p, isFunc, i, j, prepend;
14411
14412                                                 this._autoRotate = autoRotate ? (autoRotate instanceof Array) ? autoRotate : [["x","y","rotation",((autoRotate === true) ? 0 : Number(autoRotate) || 0)]] : null;
14413                                                 for (p in second) {
14414                                                         this._props.push(p);
14415                                                 }
14416
14417                                                 i = this._props.length;
14418                                                 while (--i > -1) {
14419                                                         p = this._props[i];
14420
14421                                                         this._overwriteProps.push(p);
14422                                                         isFunc = this._func[p] = (typeof(target[p]) === "function");
14423                                                         first[p] = (!isFunc) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();
14424                                                         if (!prepend) if (first[p] !== values[0][p]) {
14425                                                                 prepend = first;
14426                                                         }
14427                                                 }
14428                                                 this._beziers = (vars.type !== "cubic" && vars.type !== "quadratic" && vars.type !== "soft") ? bezierThrough(values, isNaN(vars.curviness) ? 1 : vars.curviness, false, (vars.type === "thruBasic"), vars.correlate, prepend) : _parseBezierData(values, vars.type, first);
14429                                                 this._segCount = this._beziers[p].length;
14430
14431                                                 if (this._timeRes) {
14432                                                         var ld = _parseLengthData(this._beziers, this._timeRes);
14433                                                         this._length = ld.length;
14434                                                         this._lengths = ld.lengths;
14435                                                         this._segments = ld.segments;
14436                                                         this._l1 = this._li = this._s1 = this._si = 0;
14437                                                         this._l2 = this._lengths[0];
14438                                                         this._curSeg = this._segments[0];
14439                                                         this._s2 = this._curSeg[0];
14440                                                         this._prec = 1 / this._curSeg.length;
14441                                                 }
14442
14443                                                 if ((autoRotate = this._autoRotate)) {
14444                                                         this._initialRotations = [];
14445                                                         if (!(autoRotate[0] instanceof Array)) {
14446                                                                 this._autoRotate = autoRotate = [autoRotate];
14447                                                         }
14448                                                         i = autoRotate.length;
14449                                                         while (--i > -1) {
14450                                                                 for (j = 0; j < 3; j++) {
14451                                                                         p = autoRotate[i][j];
14452                                                                         this._func[p] = (typeof(target[p]) === "function") ? target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ] : false;
14453                                                                 }
14454                                                                 p = autoRotate[i][2];
14455                                                                 this._initialRotations[i] = this._func[p] ? this._func[p].call(this._target) : this._target[p];
14456                                                         }
14457                                                 }
14458                                                 this._startRatio = tween.vars.runBackwards ? 1 : 0; //we determine the starting ratio when the tween inits which is always 0 unless the tween has runBackwards:true (indicating it's a from() tween) in which case it's 1.
14459                                                 return true;
14460                                         },
14461
14462                                         //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
14463                                         set: function(v) {
14464                                                 var segments = this._segCount,
14465                                                         func = this._func,
14466                                                         target = this._target,
14467                                                         notStart = (v !== this._startRatio),
14468                                                         curIndex, inv, i, p, b, t, val, l, lengths, curSeg;
14469                                                 if (!this._timeRes) {
14470                                                         curIndex = (v < 0) ? 0 : (v >= 1) ? segments - 1 : (segments * v) >> 0;
14471                                                         t = (v - (curIndex * (1 / segments))) * segments;
14472                                                 } else {
14473                                                         lengths = this._lengths;
14474                                                         curSeg = this._curSeg;
14475                                                         v *= this._length;
14476                                                         i = this._li;
14477                                                         //find the appropriate segment (if the currently cached one isn't correct)
14478                                                         if (v > this._l2 && i < segments - 1) {
14479                                                                 l = segments - 1;
14480                                                                 while (i < l && (this._l2 = lengths[++i]) <= v) {       }
14481                                                                 this._l1 = lengths[i-1];
14482                                                                 this._li = i;
14483                                                                 this._curSeg = curSeg = this._segments[i];
14484                                                                 this._s2 = curSeg[(this._s1 = this._si = 0)];
14485                                                         } else if (v < this._l1 && i > 0) {
14486                                                                 while (i > 0 && (this._l1 = lengths[--i]) >= v) { }
14487                                                                 if (i === 0 && v < this._l1) {
14488                                                                         this._l1 = 0;
14489                                                                 } else {
14490                                                                         i++;
14491                                                                 }
14492                                                                 this._l2 = lengths[i];
14493                                                                 this._li = i;
14494                                                                 this._curSeg = curSeg = this._segments[i];
14495                                                                 this._s1 = curSeg[(this._si = curSeg.length - 1) - 1] || 0;
14496                                                                 this._s2 = curSeg[this._si];
14497                                                         }
14498                                                         curIndex = i;
14499                                                         //now find the appropriate sub-segment (we split it into the number of pieces that was defined by "precision" and measured each one)
14500                                                         v -= this._l1;
14501                                                         i = this._si;
14502                                                         if (v > this._s2 && i < curSeg.length - 1) {
14503                                                                 l = curSeg.length - 1;
14504                                                                 while (i < l && (this._s2 = curSeg[++i]) <= v) {        }
14505                                                                 this._s1 = curSeg[i-1];
14506                                                                 this._si = i;
14507                                                         } else if (v < this._s1 && i > 0) {
14508                                                                 while (i > 0 && (this._s1 = curSeg[--i]) >= v) {        }
14509                                                                 if (i === 0 && v < this._s1) {
14510                                                                         this._s1 = 0;
14511                                                                 } else {
14512                                                                         i++;
14513                                                                 }
14514                                                                 this._s2 = curSeg[i];
14515                                                                 this._si = i;
14516                                                         }
14517                                                         t = (i + (v - this._s1) / (this._s2 - this._s1)) * this._prec;
14518                                                 }
14519                                                 inv = 1 - t;
14520
14521                                                 i = this._props.length;
14522                                                 while (--i > -1) {
14523                                                         p = this._props[i];
14524                                                         b = this._beziers[p][curIndex];
14525                                                         val = (t * t * b.da + 3 * inv * (t * b.ca + inv * b.ba)) * t + b.a;
14526                                                         if (this._round[p]) {
14527                                                                 val = Math.round(val);
14528                                                         }
14529                                                         if (func[p]) {
14530                                                                 target[p](val);
14531                                                         } else {
14532                                                                 target[p] = val;
14533                                                         }
14534                                                 }
14535
14536                                                 if (this._autoRotate) {
14537                                                         var ar = this._autoRotate,
14538                                                                 b2, x1, y1, x2, y2, add, conv;
14539                                                         i = ar.length;
14540                                                         while (--i > -1) {
14541                                                                 p = ar[i][2];
14542                                                                 add = ar[i][3] || 0;
14543                                                                 conv = (ar[i][4] === true) ? 1 : _RAD2DEG;
14544                                                                 b = this._beziers[ar[i][0]];
14545                                                                 b2 = this._beziers[ar[i][1]];
14546
14547                                                                 if (b && b2) { //in case one of the properties got overwritten.
14548                                                                         b = b[curIndex];
14549                                                                         b2 = b2[curIndex];
14550
14551                                                                         x1 = b.a + (b.b - b.a) * t;
14552                                                                         x2 = b.b + (b.c - b.b) * t;
14553                                                                         x1 += (x2 - x1) * t;
14554                                                                         x2 += ((b.c + (b.d - b.c) * t) - x2) * t;
14555
14556                                                                         y1 = b2.a + (b2.b - b2.a) * t;
14557                                                                         y2 = b2.b + (b2.c - b2.b) * t;
14558                                                                         y1 += (y2 - y1) * t;
14559                                                                         y2 += ((b2.c + (b2.d - b2.c) * t) - y2) * t;
14560
14561                                                                         val = notStart ? Math.atan2(y2 - y1, x2 - x1) * conv + add : this._initialRotations[i];
14562
14563                                                                         if (func[p]) {
14564                                                                                 target[p](val);
14565                                                                         } else {
14566                                                                                 target[p] = val;
14567                                                                         }
14568                                                                 }
14569                                                         }
14570                                                 }
14571                                         }
14572                         }),
14573                         p = BezierPlugin.prototype;
14574
14575
14576                 BezierPlugin.bezierThrough = bezierThrough;
14577                 BezierPlugin.cubicToQuadratic = cubicToQuadratic;
14578                 BezierPlugin._autoCSS = true; //indicates that this plugin can be inserted into the "css" object using the autoCSS feature of TweenLite
14579                 BezierPlugin.quadraticToCubic = function(a, b, c) {
14580                         return new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c);
14581                 };
14582
14583                 BezierPlugin._cssRegister = function() {
14584                         var CSSPlugin = window._gsDefine.globals.CSSPlugin;
14585                         if (!CSSPlugin) {
14586                                 return;
14587                         }
14588                         var _internals = CSSPlugin._internals,
14589                                 _parseToProxy = _internals._parseToProxy,
14590                                 _setPluginRatio = _internals._setPluginRatio,
14591                                 CSSPropTween = _internals.CSSPropTween;
14592                         _internals._registerComplexSpecialProp("bezier", {parser:function(t, e, prop, cssp, pt, plugin) {
14593                                 if (e instanceof Array) {
14594                                         e = {values:e};
14595                                 }
14596                                 plugin = new BezierPlugin();
14597                                 var values = e.values,
14598                                         l = values.length - 1,
14599                                         pluginValues = [],
14600                                         v = {},
14601                                         i, p, data;
14602                                 if (l < 0) {
14603                                         return pt;
14604                                 }
14605                                 for (i = 0; i <= l; i++) {
14606                                         data = _parseToProxy(t, values[i], cssp, pt, plugin, (l !== i));
14607                                         pluginValues[i] = data.end;
14608                                 }
14609                                 for (p in e) {
14610                                         v[p] = e[p]; //duplicate the vars object because we need to alter some things which would cause problems if the user plans to reuse the same vars object for another tween.
14611                                 }
14612                                 v.values = pluginValues;
14613                                 pt = new CSSPropTween(t, "bezier", 0, 0, data.pt, 2);
14614                                 pt.data = data;
14615                                 pt.plugin = plugin;
14616                                 pt.setRatio = _setPluginRatio;
14617                                 if (v.autoRotate === 0) {
14618                                         v.autoRotate = true;
14619                                 }
14620                                 if (v.autoRotate && !(v.autoRotate instanceof Array)) {
14621                                         i = (v.autoRotate === true) ? 0 : Number(v.autoRotate);
14622                                         v.autoRotate = (data.end.left != null) ? [["left","top","rotation",i,false]] : (data.end.x != null) ? [["x","y","rotation",i,false]] : false;
14623                                 }
14624                                 if (v.autoRotate) {
14625                                         if (!cssp._transform) {
14626                                                 cssp._enableTransforms(false);
14627                                         }
14628                                         data.autoRotate = cssp._target._gsTransform;
14629                                 }
14630                                 plugin._onInitTween(data.proxy, v, cssp._tween);
14631                                 return pt;
14632                         }});
14633                 };
14634
14635                 p._roundProps = function(lookup, value) {
14636                         var op = this._overwriteProps,
14637                                 i = op.length;
14638                         while (--i > -1) {
14639                                 if (lookup[op[i]] || lookup.bezier || lookup.bezierThrough) {
14640                                         this._round[op[i]] = value;
14641                                 }
14642                         }
14643                 };
14644
14645                 p._kill = function(lookup) {
14646                         var a = this._props,
14647                                 p, i;
14648                         for (p in this._beziers) {
14649                                 if (p in lookup) {
14650                                         delete this._beziers[p];
14651                                         delete this._func[p];
14652                                         i = a.length;
14653                                         while (--i > -1) {
14654                                                 if (a[i] === p) {
14655                                                         a.splice(i, 1);
14656                                                 }
14657                                         }
14658                                 }
14659                         }
14660                         return this._super._kill.call(this, lookup);
14661                 };
14662
14663         }());
14664
14665
14666
14667
14668
14669
14670         
14671         
14672         
14673         
14674         
14675         
14676         
14677         
14678 /*
14679  * ----------------------------------------------------------------
14680  * CSSPlugin
14681  * ----------------------------------------------------------------
14682  */
14683         window._gsDefine("plugins.CSSPlugin", ["plugins.TweenPlugin","TweenLite"], function(TweenPlugin, TweenLite) {
14684
14685                 /** @constructor **/
14686                 var CSSPlugin = function() {
14687                                 TweenPlugin.call(this, "css");
14688                                 this._overwriteProps.length = 0;
14689                                 this.setRatio = CSSPlugin.prototype.setRatio; //speed optimization (avoid prototype lookup on this "hot" method)
14690                         },
14691                         _hasPriority, //turns true whenever a CSSPropTween instance is created that has a priority other than 0. This helps us discern whether or not we should spend the time organizing the linked list or not after a CSSPlugin's _onInitTween() method is called.
14692                         _suffixMap, //we set this in _onInitTween() each time as a way to have a persistent variable we can use in other methods like _parse() without having to pass it around as a parameter and we keep _parse() decoupled from a particular CSSPlugin instance
14693                         _cs, //computed style (we store this in a shared variable to conserve memory and make minification tighter
14694                         _overwriteProps, //alias to the currently instantiating CSSPlugin's _overwriteProps array. We use this closure in order to avoid having to pass a reference around from method to method and aid in minification.
14695                         _specialProps = {},
14696                         p = CSSPlugin.prototype = new TweenPlugin("css");
14697
14698                 p.constructor = CSSPlugin;
14699                 CSSPlugin.version = "1.12.1";
14700                 CSSPlugin.API = 2;
14701                 CSSPlugin.defaultTransformPerspective = 0;
14702                 CSSPlugin.defaultSkewType = "compensated";
14703                 p = "px"; //we'll reuse the "p" variable to keep file size down
14704                 CSSPlugin.suffixMap = {top:p, right:p, bottom:p, left:p, width:p, height:p, fontSize:p, padding:p, margin:p, perspective:p, lineHeight:""};
14705
14706
14707                 var _numExp = /(?:\d|\-\d|\.\d|\-\.\d)+/g,
14708                         _relNumExp = /(?:\d|\-\d|\.\d|\-\.\d|\+=\d|\-=\d|\+=.\d|\-=\.\d)+/g,
14709                         _valuesExp = /(?:\+=|\-=|\-|\b)[\d\-\.]+[a-zA-Z0-9]*(?:%|\b)/gi, //finds all the values that begin with numbers or += or -= and then a number. Includes suffixes. We use this to split complex values apart like "1px 5px 20px rgb(255,102,51)"
14710                         _NaNExp = /[^\d\-\.]/g,
14711                         _suffixExp = /(?:\d|\-|\+|=|#|\.)*/g,
14712                         _opacityExp = /opacity *= *([^)]*)/i,
14713                         _opacityValExp = /opacity:([^;]*)/i,
14714                         _alphaFilterExp = /alpha\(opacity *=.+?\)/i,
14715                         _rgbhslExp = /^(rgb|hsl)/,
14716                         _capsExp = /([A-Z])/g,
14717                         _camelExp = /-([a-z])/gi,
14718                         _urlExp = /(^(?:url\(\"|url\())|(?:(\"\))$|\)$)/gi, //for pulling out urls from url(...) or url("...") strings (some browsers wrap urls in quotes, some don't when reporting things like backgroundImage)
14719                         _camelFunc = function(s, g) { return g.toUpperCase(); },
14720                         _horizExp = /(?:Left|Right|Width)/i,
14721                         _ieGetMatrixExp = /(M11|M12|M21|M22)=[\d\-\.e]+/gi,
14722                         _ieSetMatrixExp = /progid\:DXImageTransform\.Microsoft\.Matrix\(.+?\)/i,
14723                         _commasOutsideParenExp = /,(?=[^\)]*(?:\(|$))/gi, //finds any commas that are not within parenthesis
14724                         _DEG2RAD = Math.PI / 180,
14725                         _RAD2DEG = 180 / Math.PI,
14726                         _forcePT = {},
14727                         _doc = document,
14728                         _tempDiv = _doc.createElement("div"),
14729                         _tempImg = _doc.createElement("img"),
14730                         _internals = CSSPlugin._internals = {_specialProps:_specialProps}, //provides a hook to a few internal methods that we need to access from inside other plugins
14731                         _agent = navigator.userAgent,
14732                         _autoRound,
14733                         _reqSafariFix, //we won't apply the Safari transform fix until we actually come across a tween that affects a transform property (to maintain best performance).
14734
14735                         _isSafari,
14736                         _isFirefox, //Firefox has a bug that causes 3D transformed elements to randomly disappear unless a repaint is forced after each update on each element.
14737                         _isSafariLT6, //Safari (and Android 4 which uses a flavor of Safari) has a bug that prevents changes to "top" and "left" properties from rendering properly if changed on the same frame as a transform UNLESS we set the element's WebkitBackfaceVisibility to hidden (weird, I know). Doing this for Android 3 and earlier seems to actually cause other problems, though (fun!)
14738                         _ieVers,
14739                         _supportsOpacity = (function() { //we set _isSafari, _ieVers, _isFirefox, and _supportsOpacity all in one function here to reduce file size slightly, especially in the minified version.
14740                                 var i = _agent.indexOf("Android"),
14741                                         d = _doc.createElement("div"), a;
14742
14743                                 _isSafari = (_agent.indexOf("Safari") !== -1 && _agent.indexOf("Chrome") === -1 && (i === -1 || Number(_agent.substr(i+8, 1)) > 3));
14744                                 _isSafariLT6 = (_isSafari && (Number(_agent.substr(_agent.indexOf("Version/")+8, 1)) < 6));
14745                                 _isFirefox = (_agent.indexOf("Firefox") !== -1);
14746
14747                                 if ((/MSIE ([0-9]{1,}[\.0-9]{0,})/).exec(_agent)) {
14748                                         _ieVers = parseFloat( RegExp.$1 );
14749                                 }
14750
14751                                 d.innerHTML = "<a title='' style='top:1px;opacity:.55;'>a</a>";
14752                                 a = d.getElementsByTagName("a")[0];
14753                                 return a ? /^0.55/.test(a.style.opacity) : false;
14754                         }()),
14755                         _getIEOpacity = function(v) {
14756                                 return (_opacityExp.test( ((typeof(v) === "string") ? v : (v.currentStyle ? v.currentStyle.filter : v.style.filter) || "") ) ? ( parseFloat( RegExp.$1 ) / 100 ) : 1);
14757                         },
14758                         _log = function(s) {//for logging messages, but in a way that won't throw errors in old versions of IE.
14759                                 if (window.console) {
14760                                         //console.log(s);
14761                                 }
14762                         },
14763                         _prefixCSS = "", //the non-camelCase vendor prefix like "-o-", "-moz-", "-ms-", or "-webkit-"
14764                         _prefix = "", //camelCase vendor prefix like "O", "ms", "Webkit", or "Moz".
14765
14766                         // @private feed in a camelCase property name like "transform" and it will check to see if it is valid as-is or if it needs a vendor prefix. It returns the corrected camelCase property name (i.e. "WebkitTransform" or "MozTransform" or "transform" or null if no such property is found, like if the browser is IE8 or before, "transform" won't be found at all)
14767                         _checkPropPrefix = function(p, e) {
14768                                 e = e || _tempDiv;
14769                                 var s = e.style,
14770                                         a, i;
14771                                 if (s[p] !== undefined) {
14772                                         return p;
14773                                 }
14774                                 p = p.charAt(0).toUpperCase() + p.substr(1);
14775                                 a = ["O","Moz","ms","Ms","Webkit"];
14776                                 i = 5;
14777                                 while (--i > -1 && s[a[i]+p] === undefined) { }
14778                                 if (i >= 0) {
14779                                         _prefix = (i === 3) ? "ms" : a[i];
14780                                         _prefixCSS = "-" + _prefix.toLowerCase() + "-";
14781                                         return _prefix + p;
14782                                 }
14783                                 return null;
14784                         },
14785
14786                         _getComputedStyle = _doc.defaultView ? _doc.defaultView.getComputedStyle : function() {},
14787
14788                         /**
14789                          * @private Returns the css style for a particular property of an element. For example, to get whatever the current "left" css value for an element with an ID of "myElement", you could do:
14790                          * var currentLeft = CSSPlugin.getStyle( document.getElementById("myElement"), "left");
14791                          *
14792                          * @param {!Object} t Target element whose style property you want to query
14793                          * @param {!string} p Property name (like "left" or "top" or "marginTop", etc.)
14794                          * @param {Object=} cs Computed style object. This just provides a way to speed processing if you're going to get several properties on the same element in quick succession - you can reuse the result of the getComputedStyle() call.
14795                          * @param {boolean=} calc If true, the value will not be read directly from the element's "style" property (if it exists there), but instead the getComputedStyle() result will be used. This can be useful when you want to ensure that the browser itself is interpreting the value.
14796                          * @param {string=} dflt Default value that should be returned in the place of null, "none", "auto" or "auto auto".
14797                          * @return {?string} The current property value
14798                          */
14799                         _getStyle = CSSPlugin.getStyle = function(t, p, cs, calc, dflt) {
14800                                 var rv;
14801                                 if (!_supportsOpacity) if (p === "opacity") { //several versions of IE don't use the standard "opacity" property - they use things like filter:alpha(opacity=50), so we parse that here.
14802                                         return _getIEOpacity(t);
14803                                 }
14804                                 if (!calc && t.style[p]) {
14805                                         rv = t.style[p];
14806                                 } else if ((cs = cs || _getComputedStyle(t))) {
14807                                         rv = cs[p] || cs.getPropertyValue(p) || cs.getPropertyValue(p.replace(_capsExp, "-$1").toLowerCase());
14808                                 } else if (t.currentStyle) {
14809                                         rv = t.currentStyle[p];
14810                                 }
14811                                 return (dflt != null && (!rv || rv === "none" || rv === "auto" || rv === "auto auto")) ? dflt : rv;
14812                         },
14813
14814                         /**
14815                          * @private Pass the target element, the property name, the numeric value, and the suffix (like "%", "em", "px", etc.) and it will spit back the equivalent pixel number.
14816                          * @param {!Object} t Target element
14817                          * @param {!string} p Property name (like "left", "top", "marginLeft", etc.)
14818                          * @param {!number} v Value
14819                          * @param {string=} sfx Suffix (like "px" or "%" or "em")
14820                          * @param {boolean=} recurse If true, the call is a recursive one. In some browsers (like IE7/8), occasionally the value isn't accurately reported initially, but if we run the function again it will take effect.
14821                          * @return {number} value in pixels
14822                          */
14823                         _convertToPixels = _internals.convertToPixels = function(t, p, v, sfx, recurse) {
14824                                 if (sfx === "px" || !sfx) { return v; }
14825                                 if (sfx === "auto" || !v) { return 0; }
14826                                 var horiz = _horizExp.test(p),
14827                                         node = t,
14828                                         style = _tempDiv.style,
14829                                         neg = (v < 0),
14830                                         pix, cache, time;
14831                                 if (neg) {
14832                                         v = -v;
14833                                 }
14834                                 if (sfx === "%" && p.indexOf("border") !== -1) {
14835                                         pix = (v / 100) * (horiz ? t.clientWidth : t.clientHeight);
14836                                 } else {
14837                                         style.cssText = "border:0 solid red;position:" + _getStyle(t, "position") + ";line-height:0;";
14838                                         if (sfx === "%" || !node.appendChild) {
14839                                                 node = t.parentNode || _doc.body;
14840                                                 cache = node._gsCache;
14841                                                 time = TweenLite.ticker.frame;
14842                                                 if (cache && horiz && cache.time === time) { //performance optimization: we record the width of elements along with the ticker frame so that we can quickly get it again on the same tick (seems relatively safe to assume it wouldn't change on the same tick)
14843                                                         return cache.width * v / 100;
14844                                                 }
14845                                                 style[(horiz ? "width" : "height")] = v + sfx;
14846                                         } else {
14847                                                 style[(horiz ? "borderLeftWidth" : "borderTopWidth")] = v + sfx;
14848                                         }
14849                                         node.appendChild(_tempDiv);
14850                                         pix = parseFloat(_tempDiv[(horiz ? "offsetWidth" : "offsetHeight")]);
14851                                         node.removeChild(_tempDiv);
14852                                         if (horiz && sfx === "%" && CSSPlugin.cacheWidths !== false) {
14853                                                 cache = node._gsCache = node._gsCache || {};
14854                                                 cache.time = time;
14855                                                 cache.width = pix / v * 100;
14856                                         }
14857                                         if (pix === 0 && !recurse) {
14858                                                 pix = _convertToPixels(t, p, v, sfx, true);
14859                                         }
14860                                 }
14861                                 return neg ? -pix : pix;
14862                         },
14863                         _calculateOffset = _internals.calculateOffset = function(t, p, cs) { //for figuring out "top" or "left" in px when it's "auto". We need to factor in margin with the offsetLeft/offsetTop
14864                                 if (_getStyle(t, "position", cs) !== "absolute") { return 0; }
14865                                 var dim = ((p === "left") ? "Left" : "Top"),
14866                                         v = _getStyle(t, "margin" + dim, cs);
14867                                 return t["offset" + dim] - (_convertToPixels(t, p, parseFloat(v), v.replace(_suffixExp, "")) || 0);
14868                         },
14869
14870                         // @private returns at object containing ALL of the style properties in camelCase and their associated values.
14871                         _getAllStyles = function(t, cs) {
14872                                 var s = {},
14873                                         i, tr;
14874                                 if ((cs = cs || _getComputedStyle(t, null))) {
14875                                         if ((i = cs.length)) {
14876                                                 while (--i > -1) {
14877                                                         s[cs[i].replace(_camelExp, _camelFunc)] = cs.getPropertyValue(cs[i]);
14878                                                 }
14879                                         } else { //Opera behaves differently - cs.length is always 0, so we must do a for...in loop.
14880                                                 for (i in cs) {
14881                                                         s[i] = cs[i];
14882                                                 }
14883                                         }
14884                                 } else if ((cs = t.currentStyle || t.style)) {
14885                                         for (i in cs) {
14886                                                 if (typeof(i) === "string" && s[i] === undefined) {
14887                                                         s[i.replace(_camelExp, _camelFunc)] = cs[i];
14888                                                 }
14889                                         }
14890                                 }
14891                                 if (!_supportsOpacity) {
14892                                         s.opacity = _getIEOpacity(t);
14893                                 }
14894                                 tr = _getTransform(t, cs, false);
14895                                 s.rotation = tr.rotation;
14896                                 s.skewX = tr.skewX;
14897                                 s.scaleX = tr.scaleX;
14898                                 s.scaleY = tr.scaleY;
14899                                 s.x = tr.x;
14900                                 s.y = tr.y;
14901                                 if (_supports3D) {
14902                                         s.z = tr.z;
14903                                         s.rotationX = tr.rotationX;
14904                                         s.rotationY = tr.rotationY;
14905                                         s.scaleZ = tr.scaleZ;
14906                                 }
14907                                 if (s.filters) {
14908                                         delete s.filters;
14909                                 }
14910                                 return s;
14911                         },
14912
14913                         // @private analyzes two style objects (as returned by _getAllStyles()) and only looks for differences between them that contain tweenable values (like a number or color). It returns an object with a "difs" property which refers to an object containing only those isolated properties and values for tweening, and a "firstMPT" property which refers to the first MiniPropTween instance in a linked list that recorded all the starting values of the different properties so that we can revert to them at the end or beginning of the tween - we don't want the cascading to get messed up. The forceLookup parameter is an optional generic object with properties that should be forced into the results - this is necessary for className tweens that are overwriting others because imagine a scenario where a rollover/rollout adds/removes a class and the user swipes the mouse over the target SUPER fast, thus nothing actually changed yet and the subsequent comparison of the properties would indicate they match (especially when px rounding is taken into consideration), thus no tweening is necessary even though it SHOULD tween and remove those properties after the tween (otherwise the inline styles will contaminate things). See the className SpecialProp code for details.
14914                         _cssDif = function(t, s1, s2, vars, forceLookup) {
14915                                 var difs = {},
14916                                         style = t.style,
14917                                         val, p, mpt;
14918                                 for (p in s2) {
14919                                         if (p !== "cssText") if (p !== "length") if (isNaN(p)) if (s1[p] !== (val = s2[p]) || (forceLookup && forceLookup[p])) if (p.indexOf("Origin") === -1) if (typeof(val) === "number" || typeof(val) === "string") {
14920                                                 difs[p] = (val === "auto" && (p === "left" || p === "top")) ? _calculateOffset(t, p) : ((val === "" || val === "auto" || val === "none") && typeof(s1[p]) === "string" && s1[p].replace(_NaNExp, "") !== "") ? 0 : val; //if the ending value is defaulting ("" or "auto"), we check the starting value and if it can be parsed into a number (a string which could have a suffix too, like 700px), then we swap in 0 for "" or "auto" so that things actually tween.
14921                                                 if (style[p] !== undefined) { //for className tweens, we must remember which properties already existed inline - the ones that didn't should be removed when the tween isn't in progress because they were only introduced to facilitate the transition between classes.
14922                                                         mpt = new MiniPropTween(style, p, style[p], mpt);
14923                                                 }
14924                                         }
14925                                 }
14926                                 if (vars) {
14927                                         for (p in vars) { //copy properties (except className)
14928                                                 if (p !== "className") {
14929                                                         difs[p] = vars[p];
14930                                                 }
14931                                         }
14932                                 }
14933                                 return {difs:difs, firstMPT:mpt};
14934                         },
14935                         _dimensions = {width:["Left","Right"], height:["Top","Bottom"]},
14936                         _margins = ["marginLeft","marginRight","marginTop","marginBottom"],
14937
14938                         /**
14939                          * @private Gets the width or height of an element
14940                          * @param {!Object} t Target element
14941                          * @param {!string} p Property name ("width" or "height")
14942                          * @param {Object=} cs Computed style object (if one exists). Just a speed optimization.
14943                          * @return {number} Dimension (in pixels)
14944                          */
14945                         _getDimension = function(t, p, cs) {
14946                                 var v = parseFloat((p === "width") ? t.offsetWidth : t.offsetHeight),
14947                                         a = _dimensions[p],
14948                                         i = a.length;
14949                                 cs = cs || _getComputedStyle(t, null);
14950                                 while (--i > -1) {
14951                                         v -= parseFloat( _getStyle(t, "padding" + a[i], cs, true) ) || 0;
14952                                         v -= parseFloat( _getStyle(t, "border" + a[i] + "Width", cs, true) ) || 0;
14953                                 }
14954                                 return v;
14955                         },
14956
14957                         // @private Parses position-related complex strings like "top left" or "50px 10px" or "70% 20%", etc. which are used for things like transformOrigin or backgroundPosition. Optionally decorates a supplied object (recObj) with the following properties: "ox" (offsetX), "oy" (offsetY), "oxp" (if true, "ox" is a percentage not a pixel value), and "oxy" (if true, "oy" is a percentage not a pixel value)
14958                         _parsePosition = function(v, recObj) {
14959                                 if (v == null || v === "" || v === "auto" || v === "auto auto") { //note: Firefox uses "auto auto" as default whereas Chrome uses "auto".
14960                                         v = "0 0";
14961                                 }
14962                                 var a = v.split(" "),
14963                                         x = (v.indexOf("left") !== -1) ? "0%" : (v.indexOf("right") !== -1) ? "100%" : a[0],
14964                                         y = (v.indexOf("top") !== -1) ? "0%" : (v.indexOf("bottom") !== -1) ? "100%" : a[1];
14965                                 if (y == null) {
14966                                         y = "0";
14967                                 } else if (y === "center") {
14968                                         y = "50%";
14969                                 }
14970                                 if (x === "center" || (isNaN(parseFloat(x)) && (x + "").indexOf("=") === -1)) { //remember, the user could flip-flop the values and say "bottom center" or "center bottom", etc. "center" is ambiguous because it could be used to describe horizontal or vertical, hence the isNaN(). If there's an "=" sign in the value, it's relative.
14971                                         x = "50%";
14972                                 }
14973                                 if (recObj) {
14974                                         recObj.oxp = (x.indexOf("%") !== -1);
14975                                         recObj.oyp = (y.indexOf("%") !== -1);
14976                                         recObj.oxr = (x.charAt(1) === "=");
14977                                         recObj.oyr = (y.charAt(1) === "=");
14978                                         recObj.ox = parseFloat(x.replace(_NaNExp, ""));
14979                                         recObj.oy = parseFloat(y.replace(_NaNExp, ""));
14980                                 }
14981                                 return x + " " + y + ((a.length > 2) ? " " + a[2] : "");
14982                         },
14983
14984                         /**
14985                          * @private Takes an ending value (typically a string, but can be a number) and a starting value and returns the change between the two, looking for relative value indicators like += and -= and it also ignores suffixes (but make sure the ending value starts with a number or +=/-= and that the starting value is a NUMBER!)
14986                          * @param {(number|string)} e End value which is typically a string, but could be a number
14987                          * @param {(number|string)} b Beginning value which is typically a string but could be a number
14988                          * @return {number} Amount of change between the beginning and ending values (relative values that have a "+=" or "-=" are recognized)
14989                          */
14990                         _parseChange = function(e, b) {
14991                                 return (typeof(e) === "string" && e.charAt(1) === "=") ? parseInt(e.charAt(0) + "1", 10) * parseFloat(e.substr(2)) : parseFloat(e) - parseFloat(b);
14992                         },
14993
14994                         /**
14995                          * @private Takes a value and a default number, checks if the value is relative, null, or numeric and spits back a normalized number accordingly. Primarily used in the _parseTransform() function.
14996                          * @param {Object} v Value to be parsed
14997                          * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter)
14998                          * @return {number} Parsed value
14999                          */
15000                         _parseVal = function(v, d) {
15001                                 return (v == null) ? d : (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) + d : parseFloat(v);
15002                         },
15003
15004                         /**
15005                          * @private Translates strings like "40deg" or "40" or 40rad" or "+=40deg" or "270_short" or "-90_cw" or "+=45_ccw" to a numeric radian angle. Of course a starting/default value must be fed in too so that relative values can be calculated properly.
15006                          * @param {Object} v Value to be parsed
15007                          * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter)
15008                          * @param {string=} p property name for directionalEnd (optional - only used when the parsed value is directional ("_short", "_cw", or "_ccw" suffix). We need a way to store the uncompensated value so that at the end of the tween, we set it to exactly what was requested with no directional compensation). Property name would be "rotation", "rotationX", or "rotationY"
15009                          * @param {Object=} directionalEnd An object that will store the raw end values for directional angles ("_short", "_cw", or "_ccw" suffix). We need a way to store the uncompensated value so that at the end of the tween, we set it to exactly what was requested with no directional compensation.
15010                          * @return {number} parsed angle in radians
15011                          */
15012                         _parseAngle = function(v, d, p, directionalEnd) {
15013                                 var min = 0.000001,
15014                                         cap, split, dif, result;
15015                                 if (v == null) {
15016                                         result = d;
15017                                 } else if (typeof(v) === "number") {
15018                                         result = v;
15019                                 } else {
15020                                         cap = 360;
15021                                         split = v.split("_");
15022                                         dif = Number(split[0].replace(_NaNExp, "")) * ((v.indexOf("rad") === -1) ? 1 : _RAD2DEG) - ((v.charAt(1) === "=") ? 0 : d);
15023                                         if (split.length) {
15024                                                 if (directionalEnd) {
15025                                                         directionalEnd[p] = d + dif;
15026                                                 }
15027                                                 if (v.indexOf("short") !== -1) {
15028                                                         dif = dif % cap;
15029                                                         if (dif !== dif % (cap / 2)) {
15030                                                                 dif = (dif < 0) ? dif + cap : dif - cap;
15031                                                         }
15032                                                 }
15033                                                 if (v.indexOf("_cw") !== -1 && dif < 0) {
15034                                                         dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
15035                                                 } else if (v.indexOf("ccw") !== -1 && dif > 0) {
15036                                                         dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
15037                                                 }
15038                                         }
15039                                         result = d + dif;
15040                                 }
15041                                 if (result < min && result > -min) {
15042                                         result = 0;
15043                                 }
15044                                 return result;
15045                         },
15046
15047                         _colorLookup = {aqua:[0,255,255],
15048                                 lime:[0,255,0],
15049                                 silver:[192,192,192],
15050                                 black:[0,0,0],
15051                                 maroon:[128,0,0],
15052                                 teal:[0,128,128],
15053                                 blue:[0,0,255],
15054                                 navy:[0,0,128],
15055                                 white:[255,255,255],
15056                                 fuchsia:[255,0,255],
15057                                 olive:[128,128,0],
15058                                 yellow:[255,255,0],
15059                                 orange:[255,165,0],
15060                                 gray:[128,128,128],
15061                                 purple:[128,0,128],
15062                                 green:[0,128,0],
15063                                 red:[255,0,0],
15064                                 pink:[255,192,203],
15065                                 cyan:[0,255,255],
15066                                 transparent:[255,255,255,0]},
15067
15068                         _hue = function(h, m1, m2) {
15069                                 h = (h < 0) ? h + 1 : (h > 1) ? h - 1 : h;
15070                                 return ((((h * 6 < 1) ? m1 + (m2 - m1) * h * 6 : (h < 0.5) ? m2 : (h * 3 < 2) ? m1 + (m2 - m1) * (2 / 3 - h) * 6 : m1) * 255) + 0.5) | 0;
15071                         },
15072
15073                         /**
15074                          * @private Parses a color (like #9F0, #FF9900, or rgb(255,51,153)) into an array with 3 elements for red, green, and blue. Also handles rgba() values (splits into array of 4 elements of course)
15075                          * @param {(string|number)} v The value the should be parsed which could be a string like #9F0 or rgb(255,102,51) or rgba(255,0,0,0.5) or it could be a number like 0xFF00CC or even a named color like red, blue, purple, etc.
15076                          * @return {Array.<number>} An array containing red, green, and blue (and optionally alpha) in that order.
15077                          */
15078                         _parseColor = function(v) {
15079                                 var c1, c2, c3, h, s, l;
15080                                 if (!v || v === "") {
15081                                         return _colorLookup.black;
15082                                 }
15083                                 if (typeof(v) === "number") {
15084                                         return [v >> 16, (v >> 8) & 255, v & 255];
15085                                 }
15086                                 if (v.charAt(v.length - 1) === ",") { //sometimes a trailing commma is included and we should chop it off (typically from a comma-delimited list of values like a textShadow:"2px 2px 2px blue, 5px 5px 5px rgb(255,0,0)" - in this example "blue," has a trailing comma. We could strip it out inside parseComplex() but we'd need to do it to the beginning and ending values plus it wouldn't provide protection from other potential scenarios like if the user passes in a similar value.
15087                                         v = v.substr(0, v.length - 1);
15088                                 }
15089                                 if (_colorLookup[v]) {
15090                                         return _colorLookup[v];
15091                                 }
15092                                 if (v.charAt(0) === "#") {
15093                                         if (v.length === 4) { //for shorthand like #9F0
15094                                                 c1 = v.charAt(1),
15095                                                 c2 = v.charAt(2),
15096                                                 c3 = v.charAt(3);
15097                                                 v = "#" + c1 + c1 + c2 + c2 + c3 + c3;
15098                                         }
15099                                         v = parseInt(v.substr(1), 16);
15100                                         return [v >> 16, (v >> 8) & 255, v & 255];
15101                                 }
15102                                 if (v.substr(0, 3) === "hsl") {
15103                                         v = v.match(_numExp);
15104                                         h = (Number(v[0]) % 360) / 360;
15105                                         s = Number(v[1]) / 100;
15106                                         l = Number(v[2]) / 100;
15107                                         c2 = (l <= 0.5) ? l * (s + 1) : l + s - l * s;
15108                                         c1 = l * 2 - c2;
15109                                         if (v.length > 3) {
15110                                                 v[3] = Number(v[3]);
15111                                         }
15112                                         v[0] = _hue(h + 1 / 3, c1, c2);
15113                                         v[1] = _hue(h, c1, c2);
15114                                         v[2] = _hue(h - 1 / 3, c1, c2);
15115                                         return v;
15116                                 }
15117                                 v = v.match(_numExp) || _colorLookup.transparent;
15118                                 v[0] = Number(v[0]);
15119                                 v[1] = Number(v[1]);
15120                                 v[2] = Number(v[2]);
15121                                 if (v.length > 3) {
15122                                         v[3] = Number(v[3]);
15123                                 }
15124                                 return v;
15125                         },
15126                         _colorExp = "(?:\\b(?:(?:rgb|rgba|hsl|hsla)\\(.+?\\))|\\B#.+?\\b"; //we'll dynamically build this Regular Expression to conserve file size. After building it, it will be able to find rgb(), rgba(), # (hexadecimal), and named color values like red, blue, purple, etc.
15127
15128                 for (p in _colorLookup) {
15129                         _colorExp += "|" + p + "\\b";
15130                 }
15131                 _colorExp = new RegExp(_colorExp+")", "gi");
15132
15133                 /**
15134                  * @private Returns a formatter function that handles taking a string (or number in some cases) and returning a consistently formatted one in terms of delimiters, quantity of values, etc. For example, we may get boxShadow values defined as "0px red" or "0px 0px 10px rgb(255,0,0)" or "0px 0px 20px 20px #F00" and we need to ensure that what we get back is described with 4 numbers and a color. This allows us to feed it into the _parseComplex() method and split the values up appropriately. The neat thing about this _getFormatter() function is that the dflt defines a pattern as well as a default, so for example, _getFormatter("0px 0px 0px 0px #777", true) not only sets the default as 0px for all distances and #777 for the color, but also sets the pattern such that 4 numbers and a color will always get returned.
15135                  * @param {!string} dflt The default value and pattern to follow. So "0px 0px 0px 0px #777" will ensure that 4 numbers and a color will always get returned.
15136                  * @param {boolean=} clr If true, the values should be searched for color-related data. For example, boxShadow values typically contain a color whereas borderRadius don't.
15137                  * @param {boolean=} collapsible If true, the value is a top/left/right/bottom style one that acts like margin or padding, where if only one value is received, it's used for all 4; if 2 are received, the first is duplicated for 3rd (bottom) and the 2nd is duplicated for the 4th spot (left), etc.
15138                  * @return {Function} formatter function
15139                  */
15140                 var _getFormatter = function(dflt, clr, collapsible, multi) {
15141                                 if (dflt == null) {
15142                                         return function(v) {return v;};
15143                                 }
15144                                 var dColor = clr ? (dflt.match(_colorExp) || [""])[0] : "",
15145                                         dVals = dflt.split(dColor).join("").match(_valuesExp) || [],
15146                                         pfx = dflt.substr(0, dflt.indexOf(dVals[0])),
15147                                         sfx = (dflt.charAt(dflt.length - 1) === ")") ? ")" : "",
15148                                         delim = (dflt.indexOf(" ") !== -1) ? " " : ",",
15149                                         numVals = dVals.length,
15150                                         dSfx = (numVals > 0) ? dVals[0].replace(_numExp, "") : "",
15151                                         formatter;
15152                                 if (!numVals) {
15153                                         return function(v) {return v;};
15154                                 }
15155                                 if (clr) {
15156                                         formatter = function(v) {
15157                                                 var color, vals, i, a;
15158                                                 if (typeof(v) === "number") {
15159                                                         v += dSfx;
15160                                                 } else if (multi && _commasOutsideParenExp.test(v)) {
15161                                                         a = v.replace(_commasOutsideParenExp, "|").split("|");
15162                                                         for (i = 0; i < a.length; i++) {
15163                                                                 a[i] = formatter(a[i]);
15164                                                         }
15165                                                         return a.join(",");
15166                                                 }
15167                                                 color = (v.match(_colorExp) || [dColor])[0];
15168                                                 vals = v.split(color).join("").match(_valuesExp) || [];
15169                                                 i = vals.length;
15170                                                 if (numVals > i--) {
15171                                                         while (++i < numVals) {
15172                                                                 vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];
15173                                                         }
15174                                                 }
15175                                                 return pfx + vals.join(delim) + delim + color + sfx + (v.indexOf("inset") !== -1 ? " inset" : "");
15176                                         };
15177                                         return formatter;
15178
15179                                 }
15180                                 formatter = function(v) {
15181                                         var vals, a, i;
15182                                         if (typeof(v) === "number") {
15183                                                 v += dSfx;
15184                                         } else if (multi && _commasOutsideParenExp.test(v)) {
15185                                                 a = v.replace(_commasOutsideParenExp, "|").split("|");
15186                                                 for (i = 0; i < a.length; i++) {
15187                                                         a[i] = formatter(a[i]);
15188                                                 }
15189                                                 return a.join(",");
15190                                         }
15191                                         vals = v.match(_valuesExp) || [];
15192                                         i = vals.length;
15193                                         if (numVals > i--) {
15194                                                 while (++i < numVals) {
15195                                                         vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];
15196                                                 }
15197                                         }
15198                                         return pfx + vals.join(delim) + sfx;
15199                                 };
15200                                 return formatter;
15201                         },
15202
15203                         /**
15204                          * @private returns a formatter function that's used for edge-related values like marginTop, marginLeft, paddingBottom, paddingRight, etc. Just pass a comma-delimited list of property names related to the edges.
15205                          * @param {!string} props a comma-delimited list of property names in order from top to left, like "marginTop,marginRight,marginBottom,marginLeft"
15206                          * @return {Function} a formatter function
15207                          */
15208                         _getEdgeParser = function(props) {
15209                                 props = props.split(",");
15210                                 return function(t, e, p, cssp, pt, plugin, vars) {
15211                                         var a = (e + "").split(" "),
15212                                                 i;
15213                                         vars = {};
15214                                         for (i = 0; i < 4; i++) {
15215                                                 vars[props[i]] = a[i] = a[i] || a[(((i - 1) / 2) >> 0)];
15216                                         }
15217                                         return cssp.parse(t, vars, pt, plugin);
15218                                 };
15219                         },
15220
15221                         // @private used when other plugins must tween values first, like BezierPlugin or ThrowPropsPlugin, etc. That plugin's setRatio() gets called first so that the values are updated, and then we loop through the MiniPropTweens  which handle copying the values into their appropriate slots so that they can then be applied correctly in the main CSSPlugin setRatio() method. Remember, we typically create a proxy object that has a bunch of uniquely-named properties that we feed to the sub-plugin and it does its magic normally, and then we must interpret those values and apply them to the css because often numbers must get combined/concatenated, suffixes added, etc. to work with css, like boxShadow could have 4 values plus a color.
15222                         _setPluginRatio = _internals._setPluginRatio = function(v) {
15223                                 this.plugin.setRatio(v);
15224                                 var d = this.data,
15225                                         proxy = d.proxy,
15226                                         mpt = d.firstMPT,
15227                                         min = 0.000001,
15228                                         val, pt, i, str;
15229                                 while (mpt) {
15230                                         val = proxy[mpt.v];
15231                                         if (mpt.r) {
15232                                                 val = Math.round(val);
15233                                         } else if (val < min && val > -min) {
15234                                                 val = 0;
15235                                         }
15236                                         mpt.t[mpt.p] = val;
15237                                         mpt = mpt._next;
15238                                 }
15239                                 if (d.autoRotate) {
15240                                         d.autoRotate.rotation = proxy.rotation;
15241                                 }
15242                                 //at the end, we must set the CSSPropTween's "e" (end) value dynamically here because that's what is used in the final setRatio() method.
15243                                 if (v === 1) {
15244                                         mpt = d.firstMPT;
15245                                         while (mpt) {
15246                                                 pt = mpt.t;
15247                                                 if (!pt.type) {
15248                                                         pt.e = pt.s + pt.xs0;
15249                                                 } else if (pt.type === 1) {
15250                                                         str = pt.xs0 + pt.s + pt.xs1;
15251                                                         for (i = 1; i < pt.l; i++) {
15252                                                                 str += pt["xn"+i] + pt["xs"+(i+1)];
15253                                                         }
15254                                                         pt.e = str;
15255                                                 }
15256                                                 mpt = mpt._next;
15257                                         }
15258                                 }
15259                         },
15260
15261                         /**
15262                          * @private @constructor Used by a few SpecialProps to hold important values for proxies. For example, _parseToProxy() creates a MiniPropTween instance for each property that must get tweened on the proxy, and we record the original property name as well as the unique one we create for the proxy, plus whether or not the value needs to be rounded plus the original value.
15263                          * @param {!Object} t target object whose property we're tweening (often a CSSPropTween)
15264                          * @param {!string} p property name
15265                          * @param {(number|string|object)} v value
15266                          * @param {MiniPropTween=} next next MiniPropTween in the linked list
15267                          * @param {boolean=} r if true, the tweened value should be rounded to the nearest integer
15268                          */
15269                         MiniPropTween = function(t, p, v, next, r) {
15270                                 this.t = t;
15271                                 this.p = p;
15272                                 this.v = v;
15273                                 this.r = r;
15274                                 if (next) {
15275                                         next._prev = this;
15276                                         this._next = next;
15277                                 }
15278                         },
15279
15280                         /**
15281                          * @private Most other plugins (like BezierPlugin and ThrowPropsPlugin and others) can only tween numeric values, but CSSPlugin must accommodate special values that have a bunch of extra data (like a suffix or strings between numeric values, etc.). For example, boxShadow has values like "10px 10px 20px 30px rgb(255,0,0)" which would utterly confuse other plugins. This method allows us to split that data apart and grab only the numeric data and attach it to uniquely-named properties of a generic proxy object ({}) so that we can feed that to virtually any plugin to have the numbers tweened. However, we must also keep track of which properties from the proxy go with which CSSPropTween values and instances. So we create a linked list of MiniPropTweens. Each one records a target (the original CSSPropTween), property (like "s" or "xn1" or "xn2") that we're tweening and the unique property name that was used for the proxy (like "boxShadow_xn1" and "boxShadow_xn2") and whether or not they need to be rounded. That way, in the _setPluginRatio() method we can simply copy the values over from the proxy to the CSSPropTween instance(s). Then, when the main CSSPlugin setRatio() method runs and applies the CSSPropTween values accordingly, they're updated nicely. So the external plugin tweens the numbers, _setPluginRatio() copies them over, and setRatio() acts normally, applying css-specific values to the element.
15282                          * This method returns an object that has the following properties:
15283                          *  - proxy: a generic object containing the starting values for all the properties that will be tweened by the external plugin.  This is what we feed to the external _onInitTween() as the target
15284                          *  - end: a generic object containing the ending values for all the properties that will be tweened by the external plugin. This is what we feed to the external plugin's _onInitTween() as the destination values
15285                          *  - firstMPT: the first MiniPropTween in the linked list
15286                          *  - pt: the first CSSPropTween in the linked list that was created when parsing. If shallow is true, this linked list will NOT attach to the one passed into the _parseToProxy() as the "pt" (4th) parameter.
15287                          * @param {!Object} t target object to be tweened
15288                          * @param {!(Object|string)} vars the object containing the information about the tweening values (typically the end/destination values) that should be parsed
15289                          * @param {!CSSPlugin} cssp The CSSPlugin instance
15290                          * @param {CSSPropTween=} pt the next CSSPropTween in the linked list
15291                          * @param {TweenPlugin=} plugin the external TweenPlugin instance that will be handling tweening the numeric values
15292                          * @param {boolean=} shallow if true, the resulting linked list from the parse will NOT be attached to the CSSPropTween that was passed in as the "pt" (4th) parameter.
15293                          * @return An object containing the following properties: proxy, end, firstMPT, and pt (see above for descriptions)
15294                          */
15295                         _parseToProxy = _internals._parseToProxy = function(t, vars, cssp, pt, plugin, shallow) {
15296                                 var bpt = pt,
15297                                         start = {},
15298                                         end = {},
15299                                         transform = cssp._transform,
15300                                         oldForce = _forcePT,
15301                                         i, p, xp, mpt, firstPT;
15302                                 cssp._transform = null;
15303                                 _forcePT = vars;
15304                                 pt = firstPT = cssp.parse(t, vars, pt, plugin);
15305                                 _forcePT = oldForce;
15306                                 //break off from the linked list so the new ones are isolated.
15307                                 if (shallow) {
15308                                         cssp._transform = transform;
15309                                         if (bpt) {
15310                                                 bpt._prev = null;
15311                                                 if (bpt._prev) {
15312                                                         bpt._prev._next = null;
15313                                                 }
15314                                         }
15315                                 }
15316                                 while (pt && pt !== bpt) {
15317                                         if (pt.type <= 1) {
15318                                                 p = pt.p;
15319                                                 end[p] = pt.s + pt.c;
15320                                                 start[p] = pt.s;
15321                                                 if (!shallow) {
15322                                                         mpt = new MiniPropTween(pt, "s", p, mpt, pt.r);
15323                                                         pt.c = 0;
15324                                                 }
15325                                                 if (pt.type === 1) {
15326                                                         i = pt.l;
15327                                                         while (--i > 0) {
15328                                                                 xp = "xn" + i;
15329                                                                 p = pt.p + "_" + xp;
15330                                                                 end[p] = pt.data[xp];
15331                                                                 start[p] = pt[xp];
15332                                                                 if (!shallow) {
15333                                                                         mpt = new MiniPropTween(pt, xp, p, mpt, pt.rxp[xp]);
15334                                                                 }
15335                                                         }
15336                                                 }
15337                                         }
15338                                         pt = pt._next;
15339                                 }
15340                                 return {proxy:start, end:end, firstMPT:mpt, pt:firstPT};
15341                         },
15342
15343
15344
15345                         /**
15346                          * @constructor Each property that is tweened has at least one CSSPropTween associated with it. These instances store important information like the target, property, starting value, amount of change, etc. They can also optionally have a number of "extra" strings and numeric values named xs1, xn1, xs2, xn2, xs3, xn3, etc. where "s" indicates string and "n" indicates number. These can be pieced together in a complex-value tween (type:1) that has alternating types of data like a string, number, string, number, etc. For example, boxShadow could be "5px 5px 8px rgb(102, 102, 51)". In that value, there are 6 numbers that may need to tween and then pieced back together into a string again with spaces, suffixes, etc. xs0 is special in that it stores the suffix for standard (type:0) tweens, -OR- the first string (prefix) in a complex-value (type:1) CSSPropTween -OR- it can be the non-tweening value in a type:-1 CSSPropTween. We do this to conserve memory.
15347                          * CSSPropTweens have the following optional properties as well (not defined through the constructor):
15348                          *  - l: Length in terms of the number of extra properties that the CSSPropTween has (default: 0). For example, for a boxShadow we may need to tween 5 numbers in which case l would be 5; Keep in mind that the start/end values for the first number that's tweened are always stored in the s and c properties to conserve memory. All additional values thereafter are stored in xn1, xn2, etc.
15349                          *  - xfirst: The first instance of any sub-CSSPropTweens that are tweening properties of this instance. For example, we may split up a boxShadow tween so that there's a main CSSPropTween of type:1 that has various xs* and xn* values associated with the h-shadow, v-shadow, blur, color, etc. Then we spawn a CSSPropTween for each of those that has a higher priority and runs BEFORE the main CSSPropTween so that the values are all set by the time it needs to re-assemble them. The xfirst gives us an easy way to identify the first one in that chain which typically ends at the main one (because they're all prepende to the linked list)
15350                          *  - plugin: The TweenPlugin instance that will handle the tweening of any complex values. For example, sometimes we don't want to use normal subtweens (like xfirst refers to) to tween the values - we might want ThrowPropsPlugin or BezierPlugin some other plugin to do the actual tweening, so we create a plugin instance and store a reference here. We need this reference so that if we get a request to round values or disable a tween, we can pass along that request.
15351                          *  - data: Arbitrary data that needs to be stored with the CSSPropTween. Typically if we're going to have a plugin handle the tweening of a complex-value tween, we create a generic object that stores the END values that we're tweening to and the CSSPropTween's xs1, xs2, etc. have the starting values. We store that object as data. That way, we can simply pass that object to the plugin and use the CSSPropTween as the target.
15352                          *  - setRatio: Only used for type:2 tweens that require custom functionality. In this case, we call the CSSPropTween's setRatio() method and pass the ratio each time the tween updates. This isn't quite as efficient as doing things directly in the CSSPlugin's setRatio() method, but it's very convenient and flexible.
15353                          * @param {!Object} t Target object whose property will be tweened. Often a DOM element, but not always. It could be anything.
15354                          * @param {string} p Property to tween (name). For example, to tween element.width, p would be "width".
15355                          * @param {number} s Starting numeric value
15356                          * @param {number} c Change in numeric value over the course of the entire tween. For example, if element.width starts at 5 and should end at 100, c would be 95.
15357                          * @param {CSSPropTween=} next The next CSSPropTween in the linked list. If one is defined, we will define its _prev as the new instance, and the new instance's _next will be pointed at it.
15358                          * @param {number=} type The type of CSSPropTween where -1 = a non-tweening value, 0 = a standard simple tween, 1 = a complex value (like one that has multiple numbers in a comma- or space-delimited string like border:"1px solid red"), and 2 = one that uses a custom setRatio function that does all of the work of applying the values on each update.
15359                          * @param {string=} n Name of the property that should be used for overwriting purposes which is typically the same as p but not always. For example, we may need to create a subtween for the 2nd part of a "clip:rect(...)" tween in which case "p" might be xs1 but "n" is still "clip"
15360                          * @param {boolean=} r If true, the value(s) should be rounded
15361                          * @param {number=} pr Priority in the linked list order. Higher priority CSSPropTweens will be updated before lower priority ones. The default priority is 0.
15362                          * @param {string=} b Beginning value. We store this to ensure that it is EXACTLY what it was when the tween began without any risk of interpretation issues.
15363                          * @param {string=} e Ending value. We store this to ensure that it is EXACTLY what the user defined at the end of the tween without any risk of interpretation issues.
15364                          */
15365                         CSSPropTween = _internals.CSSPropTween = function(t, p, s, c, next, type, n, r, pr, b, e) {
15366                                 this.t = t; //target
15367                                 this.p = p; //property
15368                                 this.s = s; //starting value
15369                                 this.c = c; //change value
15370                                 this.n = n || p; //name that this CSSPropTween should be associated to (usually the same as p, but not always - n is what overwriting looks at)
15371                                 if (!(t instanceof CSSPropTween)) {
15372                                         _overwriteProps.push(this.n);
15373                                 }
15374                                 this.r = r; //round (boolean)
15375                                 this.type = type || 0; //0 = normal tween, -1 = non-tweening (in which case xs0 will be applied to the target's property, like tp.t[tp.p] = tp.xs0), 1 = complex-value SpecialProp, 2 = custom setRatio() that does all the work
15376                                 if (pr) {
15377                                         this.pr = pr;
15378                                         _hasPriority = true;
15379                                 }
15380                                 this.b = (b === undefined) ? s : b;
15381                                 this.e = (e === undefined) ? s + c : e;
15382                                 if (next) {
15383                                         this._next = next;
15384                                         next._prev = this;
15385                                 }
15386                         },
15387
15388                         /**
15389                          * Takes a target, the beginning value and ending value (as strings) and parses them into a CSSPropTween (possibly with child CSSPropTweens) that accommodates multiple numbers, colors, comma-delimited values, etc. For example:
15390                          * sp.parseComplex(element, "boxShadow", "5px 10px 20px rgb(255,102,51)", "0px 0px 0px red", true, "0px 0px 0px rgb(0,0,0,0)", pt);
15391                          * It will walk through the beginning and ending values (which should be in the same format with the same number and type of values) and figure out which parts are numbers, what strings separate the numeric/tweenable values, and then create the CSSPropTweens accordingly. If a plugin is defined, no child CSSPropTweens will be created. Instead, the ending values will be stored in the "data" property of the returned CSSPropTween like: {s:-5, xn1:-10, xn2:-20, xn3:255, xn4:0, xn5:0} so that it can be fed to any other plugin and it'll be plain numeric tweens but the recomposition of the complex value will be handled inside CSSPlugin's setRatio().
15392                          * If a setRatio is defined, the type of the CSSPropTween will be set to 2 and recomposition of the values will be the responsibility of that method.
15393                          *
15394                          * @param {!Object} t Target whose property will be tweened
15395                          * @param {!string} p Property that will be tweened (its name, like "left" or "backgroundColor" or "boxShadow")
15396                          * @param {string} b Beginning value
15397                          * @param {string} e Ending value
15398                          * @param {boolean} clrs If true, the value could contain a color value like "rgb(255,0,0)" or "#F00" or "red". The default is false, so no colors will be recognized (a performance optimization)
15399                          * @param {(string|number|Object)} dflt The default beginning value that should be used if no valid beginning value is defined or if the number of values inside the complex beginning and ending values don't match
15400                          * @param {?CSSPropTween} pt CSSPropTween instance that is the current head of the linked list (we'll prepend to this).
15401                          * @param {number=} pr Priority in the linked list order. Higher priority properties will be updated before lower priority ones. The default priority is 0.
15402                          * @param {TweenPlugin=} plugin If a plugin should handle the tweening of extra properties, pass the plugin instance here. If one is defined, then NO subtweens will be created for any extra properties (the properties will be created - just not additional CSSPropTween instances to tween them) because the plugin is expected to do so. However, the end values WILL be populated in the "data" property, like {s:100, xn1:50, xn2:300}
15403                          * @param {function(number)=} setRatio If values should be set in a custom function instead of being pieced together in a type:1 (complex-value) CSSPropTween, define that custom function here.
15404                          * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parseComplex() call.
15405                          */
15406                         _parseComplex = CSSPlugin.parseComplex = function(t, p, b, e, clrs, dflt, pt, pr, plugin, setRatio) {
15407                                 //DEBUG: _log("parseComplex: "+p+", b: "+b+", e: "+e);
15408                                 b = b || dflt || "";
15409                                 pt = new CSSPropTween(t, p, 0, 0, pt, (setRatio ? 2 : 1), null, false, pr, b, e);
15410                                 e += ""; //ensures it's a string
15411                                 var ba = b.split(", ").join(",").split(" "), //beginning array
15412                                         ea = e.split(", ").join(",").split(" "), //ending array
15413                                         l = ba.length,
15414                                         autoRound = (_autoRound !== false),
15415                                         i, xi, ni, bv, ev, bnums, enums, bn, rgba, temp, cv, str;
15416                                 if (e.indexOf(",") !== -1 || b.indexOf(",") !== -1) {
15417                                         ba = ba.join(" ").replace(_commasOutsideParenExp, ", ").split(" ");
15418                                         ea = ea.join(" ").replace(_commasOutsideParenExp, ", ").split(" ");
15419                                         l = ba.length;
15420                                 }
15421                                 if (l !== ea.length) {
15422                                         //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")");
15423                                         ba = (dflt || "").split(" ");
15424                                         l = ba.length;
15425                                 }
15426                                 pt.plugin = plugin;
15427                                 pt.setRatio = setRatio;
15428                                 for (i = 0; i < l; i++) {
15429                                         bv = ba[i];
15430                                         ev = ea[i];
15431                                         bn = parseFloat(bv);
15432
15433                                         //if the value begins with a number (most common). It's fine if it has a suffix like px
15434                                         if (bn || bn === 0) {
15435                                                 pt.appendXtra("", bn, _parseChange(ev, bn), ev.replace(_relNumExp, ""), (autoRound && ev.indexOf("px") !== -1), true);
15436
15437                                         //if the value is a color
15438                                         } else if (clrs && (bv.charAt(0) === "#" || _colorLookup[bv] || _rgbhslExp.test(bv))) {
15439                                                 str = ev.charAt(ev.length - 1) === "," ? ")," : ")"; //if there's a comma at the end, retain it.
15440                                                 bv = _parseColor(bv);
15441                                                 ev = _parseColor(ev);
15442                                                 rgba = (bv.length + ev.length > 6);
15443                                                 if (rgba && !_supportsOpacity && ev[3] === 0) { //older versions of IE don't support rgba(), so if the destination alpha is 0, just use "transparent" for the end color
15444                                                         pt["xs" + pt.l] += pt.l ? " transparent" : "transparent";
15445                                                         pt.e = pt.e.split(ea[i]).join("transparent");
15446                                                 } else {
15447                                                         if (!_supportsOpacity) { //old versions of IE don't support rgba().
15448                                                                 rgba = false;
15449                                                         }
15450                                                         pt.appendXtra((rgba ? "rgba(" : "rgb("), bv[0], ev[0] - bv[0], ",", true, true)
15451                                                                 .appendXtra("", bv[1], ev[1] - bv[1], ",", true)
15452                                                                 .appendXtra("", bv[2], ev[2] - bv[2], (rgba ? "," : str), true);
15453                                                         if (rgba) {
15454                                                                 bv = (bv.length < 4) ? 1 : bv[3];
15455                                                                 pt.appendXtra("", bv, ((ev.length < 4) ? 1 : ev[3]) - bv, str, false);
15456                                                         }
15457                                                 }
15458
15459                                         } else {
15460                                                 bnums = bv.match(_numExp); //gets each group of numbers in the beginning value string and drops them into an array
15461
15462                                                 //if no number is found, treat it as a non-tweening value and just append the string to the current xs.
15463                                                 if (!bnums) {
15464                                                         pt["xs" + pt.l] += pt.l ? " " + bv : bv;
15465
15466                                                 //loop through all the numbers that are found and construct the extra values on the pt.
15467                                                 } else {
15468                                                         enums = ev.match(_relNumExp); //get each group of numbers in the end value string and drop them into an array. We allow relative values too, like +=50 or -=.5
15469                                                         if (!enums || enums.length !== bnums.length) {
15470                                                                 //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")");
15471                                                                 return pt;
15472                                                         }
15473                                                         ni = 0;
15474                                                         for (xi = 0; xi < bnums.length; xi++) {
15475                                                                 cv = bnums[xi];
15476                                                                 temp = bv.indexOf(cv, ni);
15477                                                                 pt.appendXtra(bv.substr(ni, temp - ni), Number(cv), _parseChange(enums[xi], cv), "", (autoRound && bv.substr(temp + cv.length, 2) === "px"), (xi === 0));
15478                                                                 ni = temp + cv.length;
15479                                                         }
15480                                                         pt["xs" + pt.l] += bv.substr(ni);
15481                                                 }
15482                                         }
15483                                 }
15484                                 //if there are relative values ("+=" or "-=" prefix), we need to adjust the ending value to eliminate the prefixes and combine the values properly.
15485                                 if (e.indexOf("=") !== -1) if (pt.data) {
15486                                         str = pt.xs0 + pt.data.s;
15487                                         for (i = 1; i < pt.l; i++) {
15488                                                 str += pt["xs" + i] + pt.data["xn" + i];
15489                                         }
15490                                         pt.e = str + pt["xs" + i];
15491                                 }
15492                                 if (!pt.l) {
15493                                         pt.type = -1;
15494                                         pt.xs0 = pt.e;
15495                                 }
15496                                 return pt.xfirst || pt;
15497                         },
15498                         i = 9;
15499
15500
15501                 p = CSSPropTween.prototype;
15502                 p.l = p.pr = 0; //length (number of extra properties like xn1, xn2, xn3, etc.
15503                 while (--i > 0) {
15504                         p["xn" + i] = 0;
15505                         p["xs" + i] = "";
15506                 }
15507                 p.xs0 = "";
15508                 p._next = p._prev = p.xfirst = p.data = p.plugin = p.setRatio = p.rxp = null;
15509
15510
15511                 /**
15512                  * Appends and extra tweening value to a CSSPropTween and automatically manages any prefix and suffix strings. The first extra value is stored in the s and c of the main CSSPropTween instance, but thereafter any extras are stored in the xn1, xn2, xn3, etc. The prefixes and suffixes are stored in the xs0, xs1, xs2, etc. properties. For example, if I walk through a clip value like "rect(10px, 5px, 0px, 20px)", the values would be stored like this:
15513                  * xs0:"rect(", s:10, xs1:"px, ", xn1:5, xs2:"px, ", xn2:0, xs3:"px, ", xn3:20, xn4:"px)"
15514                  * And they'd all get joined together when the CSSPlugin renders (in the setRatio() method).
15515                  * @param {string=} pfx Prefix (if any)
15516                  * @param {!number} s Starting value
15517                  * @param {!number} c Change in numeric value over the course of the entire tween. For example, if the start is 5 and the end is 100, the change would be 95.
15518                  * @param {string=} sfx Suffix (if any)
15519                  * @param {boolean=} r Round (if true).
15520                  * @param {boolean=} pad If true, this extra value should be separated by the previous one by a space. If there is no previous extra and pad is true, it will automatically drop the space.
15521                  * @return {CSSPropTween} returns itself so that multiple methods can be chained together.
15522                  */
15523                 p.appendXtra = function(pfx, s, c, sfx, r, pad) {
15524                         var pt = this,
15525                                 l = pt.l;
15526                         pt["xs" + l] += (pad && l) ? " " + pfx : pfx || "";
15527                         if (!c) if (l !== 0 && !pt.plugin) { //typically we'll combine non-changing values right into the xs to optimize performance, but we don't combine them when there's a plugin that will be tweening the values because it may depend on the values being split apart, like for a bezier, if a value doesn't change between the first and second iteration but then it does on the 3rd, we'll run into trouble because there's no xn slot for that value!
15528                                 pt["xs" + l] += s + (sfx || "");
15529                                 return pt;
15530                         }
15531                         pt.l++;
15532                         pt.type = pt.setRatio ? 2 : 1;
15533                         pt["xs" + pt.l] = sfx || "";
15534                         if (l > 0) {
15535                                 pt.data["xn" + l] = s + c;
15536                                 pt.rxp["xn" + l] = r; //round extra property (we need to tap into this in the _parseToProxy() method)
15537                                 pt["xn" + l] = s;
15538                                 if (!pt.plugin) {
15539                                         pt.xfirst = new CSSPropTween(pt, "xn" + l, s, c, pt.xfirst || pt, 0, pt.n, r, pt.pr);
15540                                         pt.xfirst.xs0 = 0; //just to ensure that the property stays numeric which helps modern browsers speed up processing. Remember, in the setRatio() method, we do pt.t[pt.p] = val + pt.xs0 so if pt.xs0 is "" (the default), it'll cast the end value as a string. When a property is a number sometimes and a string sometimes, it prevents the compiler from locking in the data type, slowing things down slightly.
15541                                 }
15542                                 return pt;
15543                         }
15544                         pt.data = {s:s + c};
15545                         pt.rxp = {};
15546                         pt.s = s;
15547                         pt.c = c;
15548                         pt.r = r;
15549                         return pt;
15550                 };
15551
15552                 /**
15553                  * @constructor A SpecialProp is basically a css property that needs to be treated in a non-standard way, like if it may contain a complex value like boxShadow:"5px 10px 15px rgb(255, 102, 51)" or if it is associated with another plugin like ThrowPropsPlugin or BezierPlugin. Every SpecialProp is associated with a particular property name like "boxShadow" or "throwProps" or "bezier" and it will intercept those values in the vars object that's passed to the CSSPlugin and handle them accordingly.
15554                  * @param {!string} p Property name (like "boxShadow" or "throwProps")
15555                  * @param {Object=} options An object containing any of the following configuration options:
15556                  *                      - defaultValue: the default value
15557                  *                      - parser: A function that should be called when the associated property name is found in the vars. This function should return a CSSPropTween instance and it should ensure that it is properly inserted into the linked list. It will receive 4 paramters: 1) The target, 2) The value defined in the vars, 3) The CSSPlugin instance (whose _firstPT should be used for the linked list), and 4) A computed style object if one was calculated (this is a speed optimization that allows retrieval of starting values quicker)
15558                  *                      - formatter: a function that formats any value received for this special property (for example, boxShadow could take "5px 5px red" and format it to "5px 5px 0px 0px red" so that both the beginning and ending values have a common order and quantity of values.)
15559                  *                      - prefix: if true, we'll determine whether or not this property requires a vendor prefix (like Webkit or Moz or ms or O)
15560                  *                      - color: set this to true if the value for this SpecialProp may contain color-related values like rgb(), rgba(), etc.
15561                  *                      - priority: priority in the linked list order. Higher priority SpecialProps will be updated before lower priority ones. The default priority is 0.
15562                  *                      - multi: if true, the formatter should accommodate a comma-delimited list of values, like boxShadow could have multiple boxShadows listed out.
15563                  *                      - collapsible: if true, the formatter should treat the value like it's a top/right/bottom/left value that could be collapsed, like "5px" would apply to all, "5px, 10px" would use 5px for top/bottom and 10px for right/left, etc.
15564                  *                      - keyword: a special keyword that can [optionally] be found inside the value (like "inset" for boxShadow). This allows us to validate beginning/ending values to make sure they match (if the keyword is found in one, it'll be added to the other for consistency by default).
15565                  */
15566                 var SpecialProp = function(p, options) {
15567                                 options = options || {};
15568                                 this.p = options.prefix ? _checkPropPrefix(p) || p : p;
15569                                 _specialProps[p] = _specialProps[this.p] = this;
15570                                 this.format = options.formatter || _getFormatter(options.defaultValue, options.color, options.collapsible, options.multi);
15571                                 if (options.parser) {
15572                                         this.parse = options.parser;
15573                                 }
15574                                 this.clrs = options.color;
15575                                 this.multi = options.multi;
15576                                 this.keyword = options.keyword;
15577                                 this.dflt = options.defaultValue;
15578                                 this.pr = options.priority || 0;
15579                         },
15580
15581                         //shortcut for creating a new SpecialProp that can accept multiple properties as a comma-delimited list (helps minification). dflt can be an array for multiple values (we don't do a comma-delimited list because the default value may contain commas, like rect(0px,0px,0px,0px)). We attach this method to the SpecialProp class/object instead of using a private _createSpecialProp() method so that we can tap into it externally if necessary, like from another plugin.
15582                         _registerComplexSpecialProp = _internals._registerComplexSpecialProp = function(p, options, defaults) {
15583                                 if (typeof(options) !== "object") {
15584                                         options = {parser:defaults}; //to make backwards compatible with older versions of BezierPlugin and ThrowPropsPlugin
15585                                 }
15586                                 var a = p.split(","),
15587                                         d = options.defaultValue,
15588                                         i, temp;
15589                                 defaults = defaults || [d];
15590                                 for (i = 0; i < a.length; i++) {
15591                                         options.prefix = (i === 0 && options.prefix);
15592                                         options.defaultValue = defaults[i] || d;
15593                                         temp = new SpecialProp(a[i], options);
15594                                 }
15595                         },
15596
15597                         //creates a placeholder special prop for a plugin so that the property gets caught the first time a tween of it is attempted, and at that time it makes the plugin register itself, thus taking over for all future tweens of that property. This allows us to not mandate that things load in a particular order and it also allows us to log() an error that informs the user when they attempt to tween an external plugin-related property without loading its .js file.
15598                         _registerPluginProp = function(p) {
15599                                 if (!_specialProps[p]) {
15600                                         var pluginName = p.charAt(0).toUpperCase() + p.substr(1) + "Plugin";
15601                                         _registerComplexSpecialProp(p, {parser:function(t, e, p, cssp, pt, plugin, vars) {
15602                                                 var pluginClass = (window.GreenSockGlobals || window).com.greensock.plugins[pluginName];
15603                                                 if (!pluginClass) {
15604                                                         _log("Error: " + pluginName + " js file not loaded.");
15605                                                         return pt;
15606                                                 }
15607                                                 pluginClass._cssRegister();
15608                                                 return _specialProps[p].parse(t, e, p, cssp, pt, plugin, vars);
15609                                         }});
15610                                 }
15611                         };
15612
15613
15614                 p = SpecialProp.prototype;
15615
15616                 /**
15617                  * Alias for _parseComplex() that automatically plugs in certain values for this SpecialProp, like its property name, whether or not colors should be sensed, the default value, and priority. It also looks for any keyword that the SpecialProp defines (like "inset" for boxShadow) and ensures that the beginning and ending values have the same number of values for SpecialProps where multi is true (like boxShadow and textShadow can have a comma-delimited list)
15618                  * @param {!Object} t target element
15619                  * @param {(string|number|object)} b beginning value
15620                  * @param {(string|number|object)} e ending (destination) value
15621                  * @param {CSSPropTween=} pt next CSSPropTween in the linked list
15622                  * @param {TweenPlugin=} plugin If another plugin will be tweening the complex value, that TweenPlugin instance goes here.
15623                  * @param {function=} setRatio If a custom setRatio() method should be used to handle this complex value, that goes here.
15624                  * @return {CSSPropTween=} First CSSPropTween in the linked list
15625                  */
15626                 p.parseComplex = function(t, b, e, pt, plugin, setRatio) {
15627                         var kwd = this.keyword,
15628                                 i, ba, ea, l, bi, ei;
15629                         //if this SpecialProp's value can contain a comma-delimited list of values (like boxShadow or textShadow), we must parse them in a special way, and look for a keyword (like "inset" for boxShadow) and ensure that the beginning and ending BOTH have it if the end defines it as such. We also must ensure that there are an equal number of values specified (we can't tween 1 boxShadow to 3 for example)
15630                         if (this.multi) if (_commasOutsideParenExp.test(e) || _commasOutsideParenExp.test(b)) {
15631                                 ba = b.replace(_commasOutsideParenExp, "|").split("|");
15632                                 ea = e.replace(_commasOutsideParenExp, "|").split("|");
15633                         } else if (kwd) {
15634                                 ba = [b];
15635                                 ea = [e];
15636                         }
15637                         if (ea) {
15638                                 l = (ea.length > ba.length) ? ea.length : ba.length;
15639                                 for (i = 0; i < l; i++) {
15640                                         b = ba[i] = ba[i] || this.dflt;
15641                                         e = ea[i] = ea[i] || this.dflt;
15642                                         if (kwd) {
15643                                                 bi = b.indexOf(kwd);
15644                                                 ei = e.indexOf(kwd);
15645                                                 if (bi !== ei) {
15646                                                         e = (ei === -1) ? ea : ba;
15647                                                         e[i] += " " + kwd;
15648                                                 }
15649                                         }
15650                                 }
15651                                 b = ba.join(", ");
15652                                 e = ea.join(", ");
15653                         }
15654                         return _parseComplex(t, this.p, b, e, this.clrs, this.dflt, pt, this.pr, plugin, setRatio);
15655                 };
15656
15657                 /**
15658                  * Accepts a target and end value and spits back a CSSPropTween that has been inserted into the CSSPlugin's linked list and conforms with all the conventions we use internally, like type:-1, 0, 1, or 2, setting up any extra property tweens, priority, etc. For example, if we have a boxShadow SpecialProp and call:
15659                  * this._firstPT = sp.parse(element, "5px 10px 20px rgb(2550,102,51)", "boxShadow", this);
15660                  * It should figure out the starting value of the element's boxShadow, compare it to the provided end value and create all the necessary CSSPropTweens of the appropriate types to tween the boxShadow. The CSSPropTween that gets spit back should already be inserted into the linked list (the 4th parameter is the current head, so prepend to that).
15661                  * @param {!Object} t Target object whose property is being tweened
15662                  * @param {Object} e End value as provided in the vars object (typically a string, but not always - like a throwProps would be an object).
15663                  * @param {!string} p Property name
15664                  * @param {!CSSPlugin} cssp The CSSPlugin instance that should be associated with this tween.
15665                  * @param {?CSSPropTween} pt The CSSPropTween that is the current head of the linked list (we'll prepend to it)
15666                  * @param {TweenPlugin=} plugin If a plugin will be used to tween the parsed value, this is the plugin instance.
15667                  * @param {Object=} vars Original vars object that contains the data for parsing.
15668                  * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parse() call.
15669                  */
15670                 p.parse = function(t, e, p, cssp, pt, plugin, vars) {
15671                         return this.parseComplex(t.style, this.format(_getStyle(t, this.p, _cs, false, this.dflt)), this.format(e), pt, plugin);
15672                 };
15673
15674                 /**
15675                  * Registers a special property that should be intercepted from any "css" objects defined in tweens. This allows you to handle them however you want without CSSPlugin doing it for you. The 2nd parameter should be a function that accepts 3 parameters:
15676                  *  1) Target object whose property should be tweened (typically a DOM element)
15677                  *  2) The end/destination value (could be a string, number, object, or whatever you want)
15678                  *  3) The tween instance (you probably don't need to worry about this, but it can be useful for looking up information like the duration)
15679                  *
15680                  * Then, your function should return a function which will be called each time the tween gets rendered, passing a numeric "ratio" parameter to your function that indicates the change factor (usually between 0 and 1). For example:
15681                  *
15682                  * CSSPlugin.registerSpecialProp("myCustomProp", function(target, value, tween) {
15683                  *      var start = target.style.width;
15684                  *      return function(ratio) {
15685                  *              target.style.width = (start + value * ratio) + "px";
15686                  *              console.log("set width to " + target.style.width);
15687                  *          }
15688                  * }, 0);
15689                  *
15690                  * Then, when I do this tween, it will trigger my special property:
15691                  *
15692                  * TweenLite.to(element, 1, {css:{myCustomProp:100}});
15693                  *
15694                  * In the example, of course, we're just changing the width, but you can do anything you want.
15695                  *
15696                  * @param {!string} name Property name (or comma-delimited list of property names) that should be intercepted and handled by your function. For example, if I define "myCustomProp", then it would handle that portion of the following tween: TweenLite.to(element, 1, {css:{myCustomProp:100}})
15697                  * @param {!function(Object, Object, Object, string):function(number)} onInitTween The function that will be called when a tween of this special property is performed. The function will receive 4 parameters: 1) Target object that should be tweened, 2) Value that was passed to the tween, 3) The tween instance itself (rarely used), and 4) The property name that's being tweened. Your function should return a function that should be called on every update of the tween. That function will receive a single parameter that is a "change factor" value (typically between 0 and 1) indicating the amount of change as a ratio. You can use this to determine how to set the values appropriately in your function.
15698                  * @param {number=} priority Priority that helps the engine determine the order in which to set the properties (default: 0). Higher priority properties will be updated before lower priority ones.
15699                  */
15700                 CSSPlugin.registerSpecialProp = function(name, onInitTween, priority) {
15701                         _registerComplexSpecialProp(name, {parser:function(t, e, p, cssp, pt, plugin, vars) {
15702                                 var rv = new CSSPropTween(t, p, 0, 0, pt, 2, p, false, priority);
15703                                 rv.plugin = plugin;
15704                                 rv.setRatio = onInitTween(t, e, cssp._tween, p);
15705                                 return rv;
15706                         }, priority:priority});
15707                 };
15708
15709
15710
15711
15712
15713
15714
15715
15716                 //transform-related methods and properties
15717                 var _transformProps = ("scaleX,scaleY,scaleZ,x,y,z,skewX,skewY,rotation,rotationX,rotationY,perspective").split(","),
15718                         _transformProp = _checkPropPrefix("transform"), //the Javascript (camelCase) transform property, like msTransform, WebkitTransform, MozTransform, or OTransform.
15719                         _transformPropCSS = _prefixCSS + "transform",
15720                         _transformOriginProp = _checkPropPrefix("transformOrigin"),
15721                         _supports3D = (_checkPropPrefix("perspective") !== null),
15722                         Transform = _internals.Transform = function() {
15723                                 this.skewY = 0;
15724                         },
15725
15726                         /**
15727                          * Parses the transform values for an element, returning an object with x, y, z, scaleX, scaleY, scaleZ, rotation, rotationX, rotationY, skewX, and skewY properties. Note: by default (for performance reasons), all skewing is combined into skewX and rotation but skewY still has a place in the transform object so that we can record how much of the skew is attributed to skewX vs skewY. Remember, a skewY of 10 looks the same as a rotation of 10 and skewX of -10.
15728                          * @param {!Object} t target element
15729                          * @param {Object=} cs computed style object (optional)
15730                          * @param {boolean=} rec if true, the transform values will be recorded to the target element's _gsTransform object, like target._gsTransform = {x:0, y:0, z:0, scaleX:1...}
15731                          * @param {boolean=} parse if true, we'll ignore any _gsTransform values that already exist on the element, and force a reparsing of the css (calculated style)
15732                          * @return {object} object containing all of the transform properties/values like {x:0, y:0, z:0, scaleX:1...}
15733                          */
15734                         _getTransform = _internals.getTransform = function(t, cs, rec, parse) {
15735                                 if (t._gsTransform && rec && !parse) {
15736                                         return t._gsTransform; //if the element already has a _gsTransform, use that. Note: some browsers don't accurately return the calculated style for the transform (particularly for SVG), so it's almost always safest to just use the values we've already applied rather than re-parsing things.
15737                                 }
15738                                 var tm = rec ? t._gsTransform || new Transform() : new Transform(),
15739                                         invX = (tm.scaleX < 0), //in order to interpret things properly, we need to know if the user applied a negative scaleX previously so that we can adjust the rotation and skewX accordingly. Otherwise, if we always interpret a flipped matrix as affecting scaleY and the user only wants to tween the scaleX on multiple sequential tweens, it would keep the negative scaleY without that being the user's intent.
15740                                         min = 0.00002,
15741                                         rnd = 100000,
15742                                         minAngle = 179.99,
15743                                         minPI = minAngle * _DEG2RAD,
15744                                         zOrigin = _supports3D ? parseFloat(_getStyle(t, _transformOriginProp, cs, false, "0 0 0").split(" ")[2]) || tm.zOrigin  || 0 : 0,
15745                                         s, m, i, n, dec, scaleX, scaleY, rotation, skewX, difX, difY, difR, difS;
15746                                 if (_transformProp) {
15747                                         s = _getStyle(t, _transformPropCSS, cs, true);
15748                                 } else if (t.currentStyle) {
15749                                         //for older versions of IE, we need to interpret the filter portion that is in the format: progid:DXImageTransform.Microsoft.Matrix(M11=6.123233995736766e-17, M12=-1, M21=1, M22=6.123233995736766e-17, sizingMethod='auto expand') Notice that we need to swap b and c compared to a normal matrix.
15750                                         s = t.currentStyle.filter.match(_ieGetMatrixExp);
15751                                         s = (s && s.length === 4) ? [s[0].substr(4), Number(s[2].substr(4)), Number(s[1].substr(4)), s[3].substr(4), (tm.x || 0), (tm.y || 0)].join(",") : "";
15752                                 }
15753                                 //split the matrix values out into an array (m for matrix)
15754                                 m = (s || "").match(/(?:\-|\b)[\d\-\.e]+\b/gi) || [];
15755                                 i = m.length;
15756                                 while (--i > -1) {
15757                                         n = Number(m[i]);
15758                                         m[i] = (dec = n - (n |= 0)) ? ((dec * rnd + (dec < 0 ? -0.5 : 0.5)) | 0) / rnd + n : n; //convert strings to Numbers and round to 5 decimal places to avoid issues with tiny numbers. Roughly 20x faster than Number.toFixed(). We also must make sure to round before dividing so that values like 0.9999999999 become 1 to avoid glitches in browser rendering and interpretation of flipped/rotated 3D matrices. And don't just multiply the number by rnd, floor it, and then divide by rnd because the bitwise operations max out at a 32-bit signed integer, thus it could get clipped at a relatively low value (like 22,000.00000 for example).
15759                                 }
15760                                 if (m.length === 16) {
15761
15762                                         //we'll only look at these position-related 6 variables first because if x/y/z all match, it's relatively safe to assume we don't need to re-parse everything which risks losing important rotational information (like rotationX:180 plus rotationY:180 would look the same as rotation:180 - there's no way to know for sure which direction was taken based solely on the matrix3d() values)
15763                                         var a13 = m[8], a23 = m[9], a33 = m[10],
15764                                                 a14 = m[12], a24 = m[13], a34 = m[14];
15765
15766                                         //we manually compensate for non-zero z component of transformOrigin to work around bugs in Safari
15767                                         if (tm.zOrigin) {
15768                                                 a34 = -tm.zOrigin;
15769                                                 a14 = a13*a34-m[12];
15770                                                 a24 = a23*a34-m[13];
15771                                                 a34 = a33*a34+tm.zOrigin-m[14];
15772                                         }
15773
15774                                         //only parse from the matrix if we MUST because not only is it usually unnecessary due to the fact that we store the values in the _gsTransform object, but also because it's impossible to accurately interpret rotationX, rotationY, rotationZ, scaleX, and scaleY if all are applied, so it's much better to rely on what we store. However, we must parse the first time that an object is tweened. We also assume that if the position has changed, the user must have done some styling changes outside of CSSPlugin, thus we force a parse in that scenario.
15775                                         if (!rec || parse || tm.rotationX == null) {
15776                                                 var a11 = m[0], a21 = m[1], a31 = m[2], a41 = m[3],
15777                                                         a12 = m[4], a22 = m[5], a32 = m[6], a42 = m[7],
15778                                                         a43 = m[11],
15779                                                         angle = Math.atan2(a32, a33),
15780                                                         xFlip = (angle < -minPI || angle > minPI),
15781                                                         t1, t2, t3, cos, sin, yFlip, zFlip;
15782                                                 tm.rotationX = angle * _RAD2DEG;
15783                                                 //rotationX
15784                                                 if (angle) {
15785                                                         cos = Math.cos(-angle);
15786                                                         sin = Math.sin(-angle);
15787                                                         t1 = a12*cos+a13*sin;
15788                                                         t2 = a22*cos+a23*sin;
15789                                                         t3 = a32*cos+a33*sin;
15790                                                         a13 = a12*-sin+a13*cos;
15791                                                         a23 = a22*-sin+a23*cos;
15792                                                         a33 = a32*-sin+a33*cos;
15793                                                         a43 = a42*-sin+a43*cos;
15794                                                         a12 = t1;
15795                                                         a22 = t2;
15796                                                         a32 = t3;
15797                                                 }
15798                                                 //rotationY
15799                                                 angle = Math.atan2(a13, a11);
15800                                                 tm.rotationY = angle * _RAD2DEG;
15801                                                 if (angle) {
15802                                                         yFlip = (angle < -minPI || angle > minPI);
15803                                                         cos = Math.cos(-angle);
15804                                                         sin = Math.sin(-angle);
15805                                                         t1 = a11*cos-a13*sin;
15806                                                         t2 = a21*cos-a23*sin;
15807                                                         t3 = a31*cos-a33*sin;
15808                                                         a23 = a21*sin+a23*cos;
15809                                                         a33 = a31*sin+a33*cos;
15810                                                         a43 = a41*sin+a43*cos;
15811                                                         a11 = t1;
15812                                                         a21 = t2;
15813                                                         a31 = t3;
15814                                                 }
15815                                                 //rotationZ
15816                                                 angle = Math.atan2(a21, a22);
15817                                                 tm.rotation = angle * _RAD2DEG;
15818                                                 if (angle) {
15819                                                         zFlip = (angle < -minPI || angle > minPI);
15820                                                         cos = Math.cos(-angle);
15821                                                         sin = Math.sin(-angle);
15822                                                         a11 = a11*cos+a12*sin;
15823                                                         t2 = a21*cos+a22*sin;
15824                                                         a22 = a21*-sin+a22*cos;
15825                                                         a32 = a31*-sin+a32*cos;
15826                                                         a21 = t2;
15827                                                 }
15828
15829                                                 if (zFlip && xFlip) {
15830                                                         tm.rotation = tm.rotationX = 0;
15831                                                 } else if (zFlip && yFlip) {
15832                                                         tm.rotation = tm.rotationY = 0;
15833                                                 } else if (yFlip && xFlip) {
15834                                                         tm.rotationY = tm.rotationX = 0;
15835                                                 }
15836
15837                                                 tm.scaleX = ((Math.sqrt(a11 * a11 + a21 * a21) * rnd + 0.5) | 0) / rnd;
15838                                                 tm.scaleY = ((Math.sqrt(a22 * a22 + a23 * a23) * rnd + 0.5) | 0) / rnd;
15839                                                 tm.scaleZ = ((Math.sqrt(a32 * a32 + a33 * a33) * rnd + 0.5) | 0) / rnd;
15840                                                 tm.skewX = 0;
15841                                                 tm.perspective = a43 ? 1 / ((a43 < 0) ? -a43 : a43) : 0;
15842                                                 tm.x = a14;
15843                                                 tm.y = a24;
15844                                                 tm.z = a34;
15845                                         }
15846
15847                                 } else if ((!_supports3D || parse || !m.length || tm.x !== m[4] || tm.y !== m[5] || (!tm.rotationX && !tm.rotationY)) && !(tm.x !== undefined && _getStyle(t, "display", cs) === "none")) { //sometimes a 6-element matrix is returned even when we performed 3D transforms, like if rotationX and rotationY are 180. In cases like this, we still need to honor the 3D transforms. If we just rely on the 2D info, it could affect how the data is interpreted, like scaleY might get set to -1 or rotation could get offset by 180 degrees. For example, do a TweenLite.to(element, 1, {css:{rotationX:180, rotationY:180}}) and then later, TweenLite.to(element, 1, {css:{rotationX:0}}) and without this conditional logic in place, it'd jump to a state of being unrotated when the 2nd tween starts. Then again, we need to honor the fact that the user COULD alter the transforms outside of CSSPlugin, like by manually applying new css, so we try to sense that by looking at x and y because if those changed, we know the changes were made outside CSSPlugin and we force a reinterpretation of the matrix values. Also, in Webkit browsers, if the element's "display" is "none", its calculated style value will always return empty, so if we've already recorded the values in the _gsTransform object, we'll just rely on those.
15848                                         var k = (m.length >= 6),
15849                                                 a = k ? m[0] : 1,
15850                                                 b = m[1] || 0,
15851                                                 c = m[2] || 0,
15852                                                 d = k ? m[3] : 1;
15853                                         tm.x = m[4] || 0;
15854                                         tm.y = m[5] || 0;
15855                                         scaleX = Math.sqrt(a * a + b * b);
15856                                         scaleY = Math.sqrt(d * d + c * c);
15857                                         rotation = (a || b) ? Math.atan2(b, a) * _RAD2DEG : tm.rotation || 0; //note: if scaleX is 0, we cannot accurately measure rotation. Same for skewX with a scaleY of 0. Therefore, we default to the previously recorded value (or zero if that doesn't exist).
15858                                         skewX = (c || d) ? Math.atan2(c, d) * _RAD2DEG + rotation : tm.skewX || 0;
15859                                         difX = scaleX - Math.abs(tm.scaleX || 0);
15860                                         difY = scaleY - Math.abs(tm.scaleY || 0);
15861                                         if (Math.abs(skewX) > 90 && Math.abs(skewX) < 270) {
15862                                                 if (invX) {
15863                                                         scaleX *= -1;
15864                                                         skewX += (rotation <= 0) ? 180 : -180;
15865                                                         rotation += (rotation <= 0) ? 180 : -180;
15866                                                 } else {
15867                                                         scaleY *= -1;
15868                                                         skewX += (skewX <= 0) ? 180 : -180;
15869                                                 }
15870                                         }
15871                                         difR = (rotation - tm.rotation) % 180; //note: matching ranges would be very small (+/-0.0001) or very close to 180.
15872                                         difS = (skewX - tm.skewX) % 180;
15873                                         //if there's already a recorded _gsTransform in place for the target, we should leave those values in place unless we know things changed for sure (beyond a super small amount). This gets around ambiguous interpretations, like if scaleX and scaleY are both -1, the matrix would be the same as if the rotation was 180 with normal scaleX/scaleY. If the user tweened to particular values, those must be prioritized to ensure animation is consistent.
15874                                         if (tm.skewX === undefined || difX > min || difX < -min || difY > min || difY < -min || (difR > -minAngle && difR < minAngle && (difR * rnd) | 0 !== 0) || (difS > -minAngle && difS < minAngle && (difS * rnd) | 0 !== 0)) {
15875                                                 tm.scaleX = scaleX;
15876                                                 tm.scaleY = scaleY;
15877                                                 tm.rotation = rotation;
15878                                                 tm.skewX = skewX;
15879                                         }
15880                                         if (_supports3D) {
15881                                                 tm.rotationX = tm.rotationY = tm.z = 0;
15882                                                 tm.perspective = parseFloat(CSSPlugin.defaultTransformPerspective) || 0;
15883                                                 tm.scaleZ = 1;
15884                                         }
15885                                 }
15886                                 tm.zOrigin = zOrigin;
15887
15888                                 //some browsers have a hard time with very small values like 2.4492935982947064e-16 (notice the "e-" towards the end) and would render the object slightly off. So we round to 0 in these cases. The conditional logic here is faster than calling Math.abs(). Also, browsers tend to render a SLIGHTLY rotated object in a fuzzy way, so we need to snap to exactly 0 when appropriate.
15889                                 for (i in tm) {
15890                                         if (tm[i] < min) if (tm[i] > -min) {
15891                                                 tm[i] = 0;
15892                                         }
15893                                 }
15894                                 //DEBUG: _log("parsed rotation: "+(tm.rotationX)+", "+(tm.rotationY)+", "+(tm.rotation)+", scale: "+tm.scaleX+", "+tm.scaleY+", "+tm.scaleZ+", position: "+tm.x+", "+tm.y+", "+tm.z+", perspective: "+tm.perspective);
15895                                 if (rec) {
15896                                         t._gsTransform = tm; //record to the object's _gsTransform which we use so that tweens can control individual properties independently (we need all the properties to accurately recompose the matrix in the setRatio() method)
15897                                 }
15898                                 return tm;
15899                         },
15900
15901                         //for setting 2D transforms in IE6, IE7, and IE8 (must use a "filter" to emulate the behavior of modern day browser transforms)
15902                         _setIETransformRatio = function(v) {
15903                                 var t = this.data, //refers to the element's _gsTransform object
15904                                         ang = -t.rotation * _DEG2RAD,
15905                                         skew = ang + t.skewX * _DEG2RAD,
15906                                         rnd = 100000,
15907                                         a = ((Math.cos(ang) * t.scaleX * rnd) | 0) / rnd,
15908                                         b = ((Math.sin(ang) * t.scaleX * rnd) | 0) / rnd,
15909                                         c = ((Math.sin(skew) * -t.scaleY * rnd) | 0) / rnd,
15910                                         d = ((Math.cos(skew) * t.scaleY * rnd) | 0) / rnd,
15911                                         style = this.t.style,
15912                                         cs = this.t.currentStyle,
15913                                         filters, val;
15914                                 if (!cs) {
15915                                         return;
15916                                 }
15917                                 val = b; //just for swapping the variables an inverting them (reused "val" to avoid creating another variable in memory). IE's filter matrix uses a non-standard matrix configuration (angle goes the opposite way, and b and c are reversed and inverted)
15918                                 b = -c;
15919                                 c = -val;
15920                                 filters = cs.filter;
15921                                 style.filter = ""; //remove filters so that we can accurately measure offsetWidth/offsetHeight
15922                                 var w = this.t.offsetWidth,
15923                                         h = this.t.offsetHeight,
15924                                         clip = (cs.position !== "absolute"),
15925                                         m = "progid:DXImageTransform.Microsoft.Matrix(M11=" + a + ", M12=" + b + ", M21=" + c + ", M22=" + d,
15926                                         ox = t.x,
15927                                         oy = t.y,
15928                                         dx, dy;
15929
15930                                 //if transformOrigin is being used, adjust the offset x and y
15931                                 if (t.ox != null) {
15932                                         dx = ((t.oxp) ? w * t.ox * 0.01 : t.ox) - w / 2;
15933                                         dy = ((t.oyp) ? h * t.oy * 0.01 : t.oy) - h / 2;
15934                                         ox += dx - (dx * a + dy * b);
15935                                         oy += dy - (dx * c + dy * d);
15936                                 }
15937
15938                                 if (!clip) {
15939                                         m += ", sizingMethod='auto expand')";
15940                                 } else {
15941                                         dx = (w / 2);
15942                                         dy = (h / 2);
15943                                         //translate to ensure that transformations occur around the correct origin (default is center).
15944                                         m += ", Dx=" + (dx - (dx * a + dy * b) + ox) + ", Dy=" + (dy - (dx * c + dy * d) + oy) + ")";
15945                                 }
15946                                 if (filters.indexOf("DXImageTransform.Microsoft.Matrix(") !== -1) {
15947                                         style.filter = filters.replace(_ieSetMatrixExp, m);
15948                                 } else {
15949                                         style.filter = m + " " + filters; //we must always put the transform/matrix FIRST (before alpha(opacity=xx)) to avoid an IE bug that slices part of the object when rotation is applied with alpha.
15950                                 }
15951
15952                                 //at the end or beginning of the tween, if the matrix is normal (1, 0, 0, 1) and opacity is 100 (or doesn't exist), remove the filter to improve browser performance.
15953                                 if (v === 0 || v === 1) if (a === 1) if (b === 0) if (c === 0) if (d === 1) if (!clip || m.indexOf("Dx=0, Dy=0") !== -1) if (!_opacityExp.test(filters) || parseFloat(RegExp.$1) === 100) if (filters.indexOf("gradient(" && filters.indexOf("Alpha")) === -1) {
15954                                         style.removeAttribute("filter");
15955                                 }
15956
15957                                 //we must set the margins AFTER applying the filter in order to avoid some bugs in IE8 that could (in rare scenarios) cause them to be ignored intermittently (vibration).
15958                                 if (!clip) {
15959                                         var mult = (_ieVers < 8) ? 1 : -1, //in Internet Explorer 7 and before, the box model is broken, causing the browser to treat the width/height of the actual rotated filtered image as the width/height of the box itself, but Microsoft corrected that in IE8. We must use a negative offset in IE8 on the right/bottom
15960                                                 marg, prop, dif;
15961                                         dx = t.ieOffsetX || 0;
15962                                         dy = t.ieOffsetY || 0;
15963                                         t.ieOffsetX = Math.round((w - ((a < 0 ? -a : a) * w + (b < 0 ? -b : b) * h)) / 2 + ox);
15964                                         t.ieOffsetY = Math.round((h - ((d < 0 ? -d : d) * h + (c < 0 ? -c : c) * w)) / 2 + oy);
15965                                         for (i = 0; i < 4; i++) {
15966                                                 prop = _margins[i];
15967                                                 marg = cs[prop];
15968                                                 //we need to get the current margin in case it is being tweened separately (we want to respect that tween's changes)
15969                                                 val = (marg.indexOf("px") !== -1) ? parseFloat(marg) : _convertToPixels(this.t, prop, parseFloat(marg), marg.replace(_suffixExp, "")) || 0;
15970                                                 if (val !== t[prop]) {
15971                                                         dif = (i < 2) ? -t.ieOffsetX : -t.ieOffsetY; //if another tween is controlling a margin, we cannot only apply the difference in the ieOffsets, so we essentially zero-out the dx and dy here in that case. We record the margin(s) later so that we can keep comparing them, making this code very flexible.
15972                                                 } else {
15973                                                         dif = (i < 2) ? dx - t.ieOffsetX : dy - t.ieOffsetY;
15974                                                 }
15975                                                 style[prop] = (t[prop] = Math.round( val - dif * ((i === 0 || i === 2) ? 1 : mult) )) + "px";
15976                                         }
15977                                 }
15978                         },
15979
15980                         _set3DTransformRatio = _internals.set3DTransformRatio = function(v) {
15981                                 var t = this.data, //refers to the element's _gsTransform object
15982                                         style = this.t.style,
15983                                         angle = t.rotation * _DEG2RAD,
15984                                         sx = t.scaleX,
15985                                         sy = t.scaleY,
15986                                         sz = t.scaleZ,
15987                                         perspective = t.perspective,
15988                                         a11, a12, a13, a14,     a21, a22, a23, a24, a31, a32, a33, a34, a41, a42, a43,
15989                                         zOrigin, rnd, cos, sin, t1, t2, t3, t4;
15990                                 if (v === 1 || v === 0) if (t.force3D === "auto") if (!t.rotationY && !t.rotationX && sz === 1 && !perspective && !t.z) { //on the final render (which could be 0 for a from tween), if there are no 3D aspects, render in 2D to free up memory and improve performance especially on mobile devices
15991                                         _set2DTransformRatio.call(this, v);
15992                                         return;
15993                                 }
15994                                 if (_isFirefox) {
15995                                         var n = 0.0001;
15996                                         if (sx < n && sx > -n) { //Firefox has a bug (at least in v25) that causes it to render the transparent part of 32-bit PNG images as black when displayed inside an iframe and the 3D scale is very small and doesn't change sufficiently enough between renders (like if you use a Power4.easeInOut to scale from 0 to 1 where the beginning values only change a tiny amount to begin the tween before accelerating). In this case, we force the scale to be 0.00002 instead which is visually the same but works around the Firefox issue.
15997                                                 sx = sz = 0.00002;
15998                                         }
15999                                         if (sy < n && sy > -n) {
16000                                                 sy = sz = 0.00002;
16001                                         }
16002                                         if (perspective && !t.z && !t.rotationX && !t.rotationY) { //Firefox has a bug that causes elements to have an odd super-thin, broken/dotted black border on elements that have a perspective set but aren't utilizing 3D space (no rotationX, rotationY, or z).
16003                                                 perspective = 0;
16004                                         }
16005                                 }
16006                                 if (angle || t.skewX) {
16007                                         cos = Math.cos(angle);
16008                                         sin = Math.sin(angle);
16009                                         a11 = cos;
16010                                         a21 = sin;
16011                                         if (t.skewX) {
16012                                                 angle -= t.skewX * _DEG2RAD;
16013                                                 cos = Math.cos(angle);
16014                                                 sin = Math.sin(angle);
16015                                                 if (t.skewType === "simple") { //by default, we compensate skewing on the other axis to make it look more natural, but you can set the skewType to "simple" to use the uncompensated skewing that CSS does
16016                                                         t1 = Math.tan(t.skewX * _DEG2RAD);
16017                                                         t1 = Math.sqrt(1 + t1 * t1);
16018                                                         cos *= t1;
16019                                                         sin *= t1;
16020                                                 }
16021                                         }
16022                                         a12 = -sin;
16023                                         a22 = cos;
16024
16025                                 } else if (!t.rotationY && !t.rotationX && sz === 1 && !perspective) { //if we're only translating and/or 2D scaling, this is faster...
16026                                         style[_transformProp] = "translate3d(" + t.x + "px," + t.y + "px," + t.z +"px)" + ((sx !== 1 || sy !== 1) ? " scale(" + sx + "," + sy + ")" : "");
16027                                         return;
16028                                 } else {
16029                                         a11 = a22 = 1;
16030                                         a12 = a21 = 0;
16031                                 }
16032                                 a33 = 1;
16033                                 a13 = a14 = a23 = a24 = a31 = a32 = a34 = a41 = a42 = 0;
16034                                 a43 = (perspective) ? -1 / perspective : 0;
16035                                 zOrigin = t.zOrigin;
16036                                 rnd = 100000;
16037                                 angle = t.rotationY * _DEG2RAD;
16038                                 if (angle) {
16039                                         cos = Math.cos(angle);
16040                                         sin = Math.sin(angle);
16041                                         a31 = a33*-sin;
16042                                         a41 = a43*-sin;
16043                                         a13 = a11*sin;
16044                                         a23 = a21*sin;
16045                                         a33 *= cos;
16046                                         a43 *= cos;
16047                                         a11 *= cos;
16048                                         a21 *= cos;
16049                                 }
16050                                 angle = t.rotationX * _DEG2RAD;
16051                                 if (angle) {
16052                                         cos = Math.cos(angle);
16053                                         sin = Math.sin(angle);
16054                                         t1 = a12*cos+a13*sin;
16055                                         t2 = a22*cos+a23*sin;
16056                                         t3 = a32*cos+a33*sin;
16057                                         t4 = a42*cos+a43*sin;
16058                                         a13 = a12*-sin+a13*cos;
16059                                         a23 = a22*-sin+a23*cos;
16060                                         a33 = a32*-sin+a33*cos;
16061                                         a43 = a42*-sin+a43*cos;
16062                                         a12 = t1;
16063                                         a22 = t2;
16064                                         a32 = t3;
16065                                         a42 = t4;
16066                                 }
16067                                 if (sz !== 1) {
16068                                         a13*=sz;
16069                                         a23*=sz;
16070                                         a33*=sz;
16071                                         a43*=sz;
16072                                 }
16073                                 if (sy !== 1) {
16074                                         a12*=sy;
16075                                         a22*=sy;
16076                                         a32*=sy;
16077                                         a42*=sy;
16078                                 }
16079                                 if (sx !== 1) {
16080                                         a11*=sx;
16081                                         a21*=sx;
16082                                         a31*=sx;
16083                                         a41*=sx;
16084                                 }
16085                                 if (zOrigin) {
16086                                         a34 -= zOrigin;
16087                                         a14 = a13*a34;
16088                                         a24 = a23*a34;
16089                                         a34 = a33*a34+zOrigin;
16090                                 }
16091                                 //we round the x, y, and z slightly differently to allow even larger values.
16092                                 a14 = (t1 = (a14 += t.x) - (a14 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a14 : a14;
16093                                 a24 = (t1 = (a24 += t.y) - (a24 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a24 : a24;
16094                                 a34 = (t1 = (a34 += t.z) - (a34 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a34 : a34;
16095                                 style[_transformProp] = "matrix3d(" + [ (((a11 * rnd) | 0) / rnd), (((a21 * rnd) | 0) / rnd), (((a31 * rnd) | 0) / rnd), (((a41 * rnd) | 0) / rnd), (((a12 * rnd) | 0) / rnd), (((a22 * rnd) | 0) / rnd), (((a32 * rnd) | 0) / rnd), (((a42 * rnd) | 0) / rnd), (((a13 * rnd) | 0) / rnd), (((a23 * rnd) | 0) / rnd), (((a33 * rnd) | 0) / rnd), (((a43 * rnd) | 0) / rnd), a14, a24, a34, (perspective ? (1 + (-a34 / perspective)) : 1) ].join(",") + ")";
16096                         },
16097
16098                         _set2DTransformRatio = _internals.set2DTransformRatio = function(v) {
16099                                 var t = this.data, //refers to the element's _gsTransform object
16100                                         targ = this.t,
16101                                         style = targ.style,
16102                                         ang, skew, rnd, sx, sy;
16103                                 if (t.rotationX || t.rotationY || t.z || t.force3D === true || (t.force3D === "auto" && v !== 1 && v !== 0)) { //if a 3D tween begins while a 2D one is running, we need to kick the rendering over to the 3D method. For example, imagine a yoyo-ing, infinitely repeating scale tween running, and then the object gets rotated in 3D space with a different tween.
16104                                         this.setRatio = _set3DTransformRatio;
16105                                         _set3DTransformRatio.call(this, v);
16106                                         return;
16107                                 }
16108                                 if (!t.rotation && !t.skewX) {
16109                                         style[_transformProp] = "matrix(" + t.scaleX + ",0,0," + t.scaleY + "," + t.x + "," + t.y + ")";
16110                                 } else {
16111                                         ang = t.rotation * _DEG2RAD;
16112                                         skew = ang - t.skewX * _DEG2RAD;
16113                                         rnd = 100000;
16114                                         sx = t.scaleX * rnd;
16115                                         sy = t.scaleY * rnd;
16116                                         //some browsers have a hard time with very small values like 2.4492935982947064e-16 (notice the "e-" towards the end) and would render the object slightly off. So we round to 5 decimal places.
16117                                         style[_transformProp] = "matrix(" + (((Math.cos(ang) * sx) | 0) / rnd) + "," + (((Math.sin(ang) * sx) | 0) / rnd) + "," + (((Math.sin(skew) * -sy) | 0) / rnd) + "," + (((Math.cos(skew) * sy) | 0) / rnd) + "," + t.x + "," + t.y + ")";
16118                                 }
16119                         };
16120
16121                 _registerComplexSpecialProp("transform,scale,scaleX,scaleY,scaleZ,x,y,z,rotation,rotationX,rotationY,rotationZ,skewX,skewY,shortRotation,shortRotationX,shortRotationY,shortRotationZ,transformOrigin,transformPerspective,directionalRotation,parseTransform,force3D,skewType", {parser:function(t, e, p, cssp, pt, plugin, vars) {
16122                         if (cssp._transform) { return pt; } //only need to parse the transform once, and only if the browser supports it.
16123                         var m1 = cssp._transform = _getTransform(t, _cs, true, vars.parseTransform),
16124                                 style = t.style,
16125                                 min = 0.000001,
16126                                 i = _transformProps.length,
16127                                 v = vars,
16128                                 endRotations = {},
16129                                 m2, skewY, copy, orig, has3D, hasChange, dr;
16130                         if (typeof(v.transform) === "string" && _transformProp) { //for values like transform:"rotate(60deg) scale(0.5, 0.8)"
16131                                 copy = _tempDiv.style; //don't use the original target because it might be SVG in which case some browsers don't report computed style correctly.
16132                                 copy[_transformProp] = v.transform;
16133                                 copy.display = "block"; //if display is "none", the browser often refuses to report the transform properties correctly.
16134                                 copy.position = "absolute";
16135                                 _doc.body.appendChild(_tempDiv);
16136                                 m2 = _getTransform(_tempDiv, null, false);
16137                                 _doc.body.removeChild(_tempDiv);
16138                         } else if (typeof(v) === "object") { //for values like scaleX, scaleY, rotation, x, y, skewX, and skewY or transform:{...} (object)
16139                                 m2 = {scaleX:_parseVal((v.scaleX != null) ? v.scaleX : v.scale, m1.scaleX),
16140                                         scaleY:_parseVal((v.scaleY != null) ? v.scaleY : v.scale, m1.scaleY),
16141                                         scaleZ:_parseVal(v.scaleZ, m1.scaleZ),
16142                                         x:_parseVal(v.x, m1.x),
16143                                         y:_parseVal(v.y, m1.y),
16144                                         z:_parseVal(v.z, m1.z),
16145                                         perspective:_parseVal(v.transformPerspective, m1.perspective)};
16146                                 dr = v.directionalRotation;
16147                                 if (dr != null) {
16148                                         if (typeof(dr) === "object") {
16149                                                 for (copy in dr) {
16150                                                         v[copy] = dr[copy];
16151                                                 }
16152                                         } else {
16153                                                 v.rotation = dr;
16154                                         }
16155                                 }
16156                                 m2.rotation = _parseAngle(("rotation" in v) ? v.rotation : ("shortRotation" in v) ? v.shortRotation + "_short" : ("rotationZ" in v) ? v.rotationZ : m1.rotation, m1.rotation, "rotation", endRotations);
16157                                 if (_supports3D) {
16158                                         m2.rotationX = _parseAngle(("rotationX" in v) ? v.rotationX : ("shortRotationX" in v) ? v.shortRotationX + "_short" : m1.rotationX || 0, m1.rotationX, "rotationX", endRotations);
16159                                         m2.rotationY = _parseAngle(("rotationY" in v) ? v.rotationY : ("shortRotationY" in v) ? v.shortRotationY + "_short" : m1.rotationY || 0, m1.rotationY, "rotationY", endRotations);
16160                                 }
16161                                 m2.skewX = (v.skewX == null) ? m1.skewX : _parseAngle(v.skewX, m1.skewX);
16162
16163                                 //note: for performance reasons, we combine all skewing into the skewX and rotation values, ignoring skewY but we must still record it so that we can discern how much of the overall skew is attributed to skewX vs. skewY. Otherwise, if the skewY would always act relative (tween skewY to 10deg, for example, multiple times and if we always combine things into skewX, we can't remember that skewY was 10 from last time). Remember, a skewY of 10 degrees looks the same as a rotation of 10 degrees plus a skewX of -10 degrees.
16164                                 m2.skewY = (v.skewY == null) ? m1.skewY : _parseAngle(v.skewY, m1.skewY);
16165                                 if ((skewY = m2.skewY - m1.skewY)) {
16166                                         m2.skewX += skewY;
16167                                         m2.rotation += skewY;
16168                                 }
16169                         }
16170
16171                         if (_supports3D && v.force3D != null) {
16172                                 m1.force3D = v.force3D;
16173                                 hasChange = true;
16174                         }
16175
16176                         m1.skewType = v.skewType || m1.skewType || CSSPlugin.defaultSkewType;
16177
16178                         has3D = (m1.force3D || m1.z || m1.rotationX || m1.rotationY || m2.z || m2.rotationX || m2.rotationY || m2.perspective);
16179                         if (!has3D && v.scale != null) {
16180                                 m2.scaleZ = 1; //no need to tween scaleZ.
16181                         }
16182
16183                         while (--i > -1) {
16184                                 p = _transformProps[i];
16185                                 orig = m2[p] - m1[p];
16186                                 if (orig > min || orig < -min || _forcePT[p] != null) {
16187                                         hasChange = true;
16188                                         pt = new CSSPropTween(m1, p, m1[p], orig, pt);
16189                                         if (p in endRotations) {
16190                                                 pt.e = endRotations[p]; //directional rotations typically have compensated values during the tween, but we need to make sure they end at exactly what the user requested
16191                                         }
16192                                         pt.xs0 = 0; //ensures the value stays numeric in setRatio()
16193                                         pt.plugin = plugin;
16194                                         cssp._overwriteProps.push(pt.n);
16195                                 }
16196                         }
16197
16198                         orig = v.transformOrigin;
16199                         if (orig || (_supports3D && has3D && m1.zOrigin)) { //if anything 3D is happening and there's a transformOrigin with a z component that's non-zero, we must ensure that the transformOrigin's z-component is set to 0 so that we can manually do those calculations to get around Safari bugs. Even if the user didn't specifically define a "transformOrigin" in this particular tween (maybe they did it via css directly).
16200                                 if (_transformProp) {
16201                                         hasChange = true;
16202                                         p = _transformOriginProp;
16203                                         orig = (orig || _getStyle(t, p, _cs, false, "50% 50%")) + ""; //cast as string to avoid errors
16204                                         pt = new CSSPropTween(style, p, 0, 0, pt, -1, "transformOrigin");
16205                                         pt.b = style[p];
16206                                         pt.plugin = plugin;
16207                                         if (_supports3D) {
16208                                                 copy = m1.zOrigin;
16209                                                 orig = orig.split(" ");
16210                                                 m1.zOrigin = ((orig.length > 2 && !(copy !== 0 && orig[2] === "0px")) ? parseFloat(orig[2]) : copy) || 0; //Safari doesn't handle the z part of transformOrigin correctly, so we'll manually handle it in the _set3DTransformRatio() method.
16211                                                 pt.xs0 = pt.e = orig[0] + " " + (orig[1] || "50%") + " 0px"; //we must define a z value of 0px specifically otherwise iOS 5 Safari will stick with the old one (if one was defined)!
16212                                                 pt = new CSSPropTween(m1, "zOrigin", 0, 0, pt, -1, pt.n); //we must create a CSSPropTween for the _gsTransform.zOrigin so that it gets reset properly at the beginning if the tween runs backward (as opposed to just setting m1.zOrigin here)
16213                                                 pt.b = copy;
16214                                                 pt.xs0 = pt.e = m1.zOrigin;
16215                                         } else {
16216                                                 pt.xs0 = pt.e = orig;
16217                                         }
16218
16219                                 //for older versions of IE (6-8), we need to manually calculate things inside the setRatio() function. We record origin x and y (ox and oy) and whether or not the values are percentages (oxp and oyp).
16220                                 } else {
16221                                         _parsePosition(orig + "", m1);
16222                                 }
16223                         }
16224
16225                         if (hasChange) {
16226                                 cssp._transformType = (has3D || this._transformType === 3) ? 3 : 2; //quicker than calling cssp._enableTransforms();
16227                         }
16228                         return pt;
16229                 }, prefix:true});
16230
16231                 _registerComplexSpecialProp("boxShadow", {defaultValue:"0px 0px 0px 0px #999", prefix:true, color:true, multi:true, keyword:"inset"});
16232
16233                 _registerComplexSpecialProp("borderRadius", {defaultValue:"0px", parser:function(t, e, p, cssp, pt, plugin) {
16234                         e = this.format(e);
16235                         var props = ["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"],
16236                                 style = t.style,
16237                                 ea1, i, es2, bs2, bs, es, bn, en, w, h, esfx, bsfx, rel, hn, vn, em;
16238                         w = parseFloat(t.offsetWidth);
16239                         h = parseFloat(t.offsetHeight);
16240                         ea1 = e.split(" ");
16241                         for (i = 0; i < props.length; i++) { //if we're dealing with percentages, we must convert things separately for the horizontal and vertical axis!
16242                                 if (this.p.indexOf("border")) { //older browsers used a prefix
16243                                         props[i] = _checkPropPrefix(props[i]);
16244                                 }
16245                                 bs = bs2 = _getStyle(t, props[i], _cs, false, "0px");
16246                                 if (bs.indexOf(" ") !== -1) {
16247                                         bs2 = bs.split(" ");
16248                                         bs = bs2[0];
16249                                         bs2 = bs2[1];
16250                                 }
16251                                 es = es2 = ea1[i];
16252                                 bn = parseFloat(bs);
16253                                 bsfx = bs.substr((bn + "").length);
16254                                 rel = (es.charAt(1) === "=");
16255                                 if (rel) {
16256                                         en = parseInt(es.charAt(0)+"1", 10);
16257                                         es = es.substr(2);
16258                                         en *= parseFloat(es);
16259                                         esfx = es.substr((en + "").length - (en < 0 ? 1 : 0)) || "";
16260                                 } else {
16261                                         en = parseFloat(es);
16262                                         esfx = es.substr((en + "").length);
16263                                 }
16264                                 if (esfx === "") {
16265                                         esfx = _suffixMap[p] || bsfx;
16266                                 }
16267                                 if (esfx !== bsfx) {
16268                                         hn = _convertToPixels(t, "borderLeft", bn, bsfx); //horizontal number (we use a bogus "borderLeft" property just because the _convertToPixels() method searches for the keywords "Left", "Right", "Top", and "Bottom" to determine of it's a horizontal or vertical property, and we need "border" in the name so that it knows it should measure relative to the element itself, not its parent.
16269                                         vn = _convertToPixels(t, "borderTop", bn, bsfx); //vertical number
16270                                         if (esfx === "%") {
16271                                                 bs = (hn / w * 100) + "%";
16272                                                 bs2 = (vn / h * 100) + "%";
16273                                         } else if (esfx === "em") {
16274                                                 em = _convertToPixels(t, "borderLeft", 1, "em");
16275                                                 bs = (hn / em) + "em";
16276                                                 bs2 = (vn / em) + "em";
16277                                         } else {
16278                                                 bs = hn + "px";
16279                                                 bs2 = vn + "px";
16280                                         }
16281                                         if (rel) {
16282                                                 es = (parseFloat(bs) + en) + esfx;
16283                                                 es2 = (parseFloat(bs2) + en) + esfx;
16284                                         }
16285                                 }
16286                                 pt = _parseComplex(style, props[i], bs + " " + bs2, es + " " + es2, false, "0px", pt);
16287                         }
16288                         return pt;
16289                 }, prefix:true, formatter:_getFormatter("0px 0px 0px 0px", false, true)});
16290                 _registerComplexSpecialProp("backgroundPosition", {defaultValue:"0 0", parser:function(t, e, p, cssp, pt, plugin) {
16291                         var bp = "background-position",
16292                                 cs = (_cs || _getComputedStyle(t, null)),
16293                                 bs = this.format( ((cs) ? _ieVers ? cs.getPropertyValue(bp + "-x") + " " + cs.getPropertyValue(bp + "-y") : cs.getPropertyValue(bp) : t.currentStyle.backgroundPositionX + " " + t.currentStyle.backgroundPositionY) || "0 0"), //Internet Explorer doesn't report background-position correctly - we must query background-position-x and background-position-y and combine them (even in IE10). Before IE9, we must do the same with the currentStyle object and use camelCase
16294                                 es = this.format(e),
16295                                 ba, ea, i, pct, overlap, src;
16296                         if ((bs.indexOf("%") !== -1) !== (es.indexOf("%") !== -1)) {
16297                                 src = _getStyle(t, "backgroundImage").replace(_urlExp, "");
16298                                 if (src && src !== "none") {
16299                                         ba = bs.split(" ");
16300                                         ea = es.split(" ");
16301                                         _tempImg.setAttribute("src", src); //set the temp <img>'s src to the background-image so that we can measure its width/height
16302                                         i = 2;
16303                                         while (--i > -1) {
16304                                                 bs = ba[i];
16305                                                 pct = (bs.indexOf("%") !== -1);
16306                                                 if (pct !== (ea[i].indexOf("%") !== -1)) {
16307                                                         overlap = (i === 0) ? t.offsetWidth - _tempImg.width : t.offsetHeight - _tempImg.height;
16308                                                         ba[i] = pct ? (parseFloat(bs) / 100 * overlap) + "px" : (parseFloat(bs) / overlap * 100) + "%";
16309                                                 }
16310                                         }
16311                                         bs = ba.join(" ");
16312                                 }
16313                         }
16314                         return this.parseComplex(t.style, bs, es, pt, plugin);
16315                 }, formatter:_parsePosition});
16316                 _registerComplexSpecialProp("backgroundSize", {defaultValue:"0 0", formatter:_parsePosition});
16317                 _registerComplexSpecialProp("perspective", {defaultValue:"0px", prefix:true});
16318                 _registerComplexSpecialProp("perspectiveOrigin", {defaultValue:"50% 50%", prefix:true});
16319                 _registerComplexSpecialProp("transformStyle", {prefix:true});
16320                 _registerComplexSpecialProp("backfaceVisibility", {prefix:true});
16321                 _registerComplexSpecialProp("userSelect", {prefix:true});
16322                 _registerComplexSpecialProp("margin", {parser:_getEdgeParser("marginTop,marginRight,marginBottom,marginLeft")});
16323                 _registerComplexSpecialProp("padding", {parser:_getEdgeParser("paddingTop,paddingRight,paddingBottom,paddingLeft")});
16324                 _registerComplexSpecialProp("clip", {defaultValue:"rect(0px,0px,0px,0px)", parser:function(t, e, p, cssp, pt, plugin){
16325                         var b, cs, delim;
16326                         if (_ieVers < 9) { //IE8 and earlier don't report a "clip" value in the currentStyle - instead, the values are split apart into clipTop, clipRight, clipBottom, and clipLeft. Also, in IE7 and earlier, the values inside rect() are space-delimited, not comma-delimited.
16327                                 cs = t.currentStyle;
16328                                 delim = _ieVers < 8 ? " " : ",";
16329                                 b = "rect(" + cs.clipTop + delim + cs.clipRight + delim + cs.clipBottom + delim + cs.clipLeft + ")";
16330                                 e = this.format(e).split(",").join(delim);
16331                         } else {
16332                                 b = this.format(_getStyle(t, this.p, _cs, false, this.dflt));
16333                                 e = this.format(e);
16334                         }
16335                         return this.parseComplex(t.style, b, e, pt, plugin);
16336                 }});
16337                 _registerComplexSpecialProp("textShadow", {defaultValue:"0px 0px 0px #999", color:true, multi:true});
16338                 _registerComplexSpecialProp("autoRound,strictUnits", {parser:function(t, e, p, cssp, pt) {return pt;}}); //just so that we can ignore these properties (not tween them)
16339                 _registerComplexSpecialProp("border", {defaultValue:"0px solid #000", parser:function(t, e, p, cssp, pt, plugin) {
16340                                 return this.parseComplex(t.style, this.format(_getStyle(t, "borderTopWidth", _cs, false, "0px") + " " + _getStyle(t, "borderTopStyle", _cs, false, "solid") + " " + _getStyle(t, "borderTopColor", _cs, false, "#000")), this.format(e), pt, plugin);
16341                         }, color:true, formatter:function(v) {
16342                                 var a = v.split(" ");
16343                                 return a[0] + " " + (a[1] || "solid") + " " + (v.match(_colorExp) || ["#000"])[0];
16344                         }});
16345                 _registerComplexSpecialProp("borderWidth", {parser:_getEdgeParser("borderTopWidth,borderRightWidth,borderBottomWidth,borderLeftWidth")}); //Firefox doesn't pick up on borderWidth set in style sheets (only inline).
16346                 _registerComplexSpecialProp("float,cssFloat,styleFloat", {parser:function(t, e, p, cssp, pt, plugin) {
16347                         var s = t.style,
16348                                 prop = ("cssFloat" in s) ? "cssFloat" : "styleFloat";
16349                         return new CSSPropTween(s, prop, 0, 0, pt, -1, p, false, 0, s[prop], e);
16350                 }});
16351
16352                 //opacity-related
16353                 var _setIEOpacityRatio = function(v) {
16354                                 var t = this.t, //refers to the element's style property
16355                                         filters = t.filter || _getStyle(this.data, "filter"),
16356                                         val = (this.s + this.c * v) | 0,
16357                                         skip;
16358                                 if (val === 100) { //for older versions of IE that need to use a filter to apply opacity, we should remove the filter if opacity hits 1 in order to improve performance, but make sure there isn't a transform (matrix) or gradient in the filters.
16359                                         if (filters.indexOf("atrix(") === -1 && filters.indexOf("radient(") === -1 && filters.indexOf("oader(") === -1) {
16360                                                 t.removeAttribute("filter");
16361                                                 skip = (!_getStyle(this.data, "filter")); //if a class is applied that has an alpha filter, it will take effect (we don't want that), so re-apply our alpha filter in that case. We must first remove it and then check.
16362                                         } else {
16363                                                 t.filter = filters.replace(_alphaFilterExp, "");
16364                                                 skip = true;
16365                                         }
16366                                 }
16367                                 if (!skip) {
16368                                         if (this.xn1) {
16369                                                 t.filter = filters = filters || ("alpha(opacity=" + val + ")"); //works around bug in IE7/8 that prevents changes to "visibility" from being applied properly if the filter is changed to a different alpha on the same frame.
16370                                         }
16371                                         if (filters.indexOf("pacity") === -1) { //only used if browser doesn't support the standard opacity style property (IE 7 and 8). We omit the "O" to avoid case-sensitivity issues
16372                                                 if (val !== 0 || !this.xn1) { //bugs in IE7/8 won't render the filter properly if opacity is ADDED on the same frame/render as "visibility" changes (this.xn1 is 1 if this tween is an "autoAlpha" tween)
16373                                                         t.filter = filters + " alpha(opacity=" + val + ")"; //we round the value because otherwise, bugs in IE7/8 can prevent "visibility" changes from being applied properly.
16374                                                 }
16375                                         } else {
16376                                                 t.filter = filters.replace(_opacityExp, "opacity=" + val);
16377                                         }
16378                                 }
16379                         };
16380                 _registerComplexSpecialProp("opacity,alpha,autoAlpha", {defaultValue:"1", parser:function(t, e, p, cssp, pt, plugin) {
16381                         var b = parseFloat(_getStyle(t, "opacity", _cs, false, "1")),
16382                                 style = t.style,
16383                                 isAutoAlpha = (p === "autoAlpha");
16384                         if (typeof(e) === "string" && e.charAt(1) === "=") {
16385                                 e = ((e.charAt(0) === "-") ? -1 : 1) * parseFloat(e.substr(2)) + b;
16386                         }
16387                         if (isAutoAlpha && b === 1 && _getStyle(t, "visibility", _cs) === "hidden" && e !== 0) { //if visibility is initially set to "hidden", we should interpret that as intent to make opacity 0 (a convenience)
16388                                 b = 0;
16389                         }
16390                         if (_supportsOpacity) {
16391                                 pt = new CSSPropTween(style, "opacity", b, e - b, pt);
16392                         } else {
16393                                 pt = new CSSPropTween(style, "opacity", b * 100, (e - b) * 100, pt);
16394                                 pt.xn1 = isAutoAlpha ? 1 : 0; //we need to record whether or not this is an autoAlpha so that in the setRatio(), we know to duplicate the setting of the alpha in order to work around a bug in IE7 and IE8 that prevents changes to "visibility" from taking effect if the filter is changed to a different alpha(opacity) at the same time. Setting it to the SAME value first, then the new value works around the IE7/8 bug.
16395                                 style.zoom = 1; //helps correct an IE issue.
16396                                 pt.type = 2;
16397                                 pt.b = "alpha(opacity=" + pt.s + ")";
16398                                 pt.e = "alpha(opacity=" + (pt.s + pt.c) + ")";
16399                                 pt.data = t;
16400                                 pt.plugin = plugin;
16401                                 pt.setRatio = _setIEOpacityRatio;
16402                         }
16403                         if (isAutoAlpha) { //we have to create the "visibility" PropTween after the opacity one in the linked list so that they run in the order that works properly in IE8 and earlier
16404                                 pt = new CSSPropTween(style, "visibility", 0, 0, pt, -1, null, false, 0, ((b !== 0) ? "inherit" : "hidden"), ((e === 0) ? "hidden" : "inherit"));
16405                                 pt.xs0 = "inherit";
16406                                 cssp._overwriteProps.push(pt.n);
16407                                 cssp._overwriteProps.push(p);
16408                         }
16409                         return pt;
16410                 }});
16411
16412
16413                 var _removeProp = function(s, p) {
16414                                 if (p) {
16415                                         if (s.removeProperty) {
16416                                                 if (p.substr(0,2) === "ms") { //Microsoft browsers don't conform to the standard of capping the first prefix character, so we adjust so that when we prefix the caps with a dash, it's correct (otherwise it'd be "ms-transform" instead of "-ms-transform" for IE9, for example)
16417                                                         p = "M" + p.substr(1);
16418                                                 }
16419                                                 s.removeProperty(p.replace(_capsExp, "-$1").toLowerCase());
16420                                         } else { //note: old versions of IE use "removeAttribute()" instead of "removeProperty()"
16421                                                 s.removeAttribute(p);
16422                                         }
16423                                 }
16424                         },
16425                         _setClassNameRatio = function(v) {
16426                                 this.t._gsClassPT = this;
16427                                 if (v === 1 || v === 0) {
16428                                         this.t.setAttribute("class", (v === 0) ? this.b : this.e);
16429                                         var mpt = this.data, //first MiniPropTween
16430                                                 s = this.t.style;
16431                                         while (mpt) {
16432                                                 if (!mpt.v) {
16433                                                         _removeProp(s, mpt.p);
16434                                                 } else {
16435                                                         s[mpt.p] = mpt.v;
16436                                                 }
16437                                                 mpt = mpt._next;
16438                                         }
16439                                         if (v === 1 && this.t._gsClassPT === this) {
16440                                                 this.t._gsClassPT = null;
16441                                         }
16442                                 } else if (this.t.getAttribute("class") !== this.e) {
16443                                         this.t.setAttribute("class", this.e);
16444                                 }
16445                         };
16446                 _registerComplexSpecialProp("className", {parser:function(t, e, p, cssp, pt, plugin, vars) {
16447                         var b = t.getAttribute("class") || "", //don't use t.className because it doesn't work consistently on SVG elements; getAttribute("class") and setAttribute("class", value") is more reliable.
16448                                 cssText = t.style.cssText,
16449                                 difData, bs, cnpt, cnptLookup, mpt;
16450                         pt = cssp._classNamePT = new CSSPropTween(t, p, 0, 0, pt, 2);
16451                         pt.setRatio = _setClassNameRatio;
16452                         pt.pr = -11;
16453                         _hasPriority = true;
16454                         pt.b = b;
16455                         bs = _getAllStyles(t, _cs);
16456                         //if there's a className tween already operating on the target, force it to its end so that the necessary inline styles are removed and the class name is applied before we determine the end state (we don't want inline styles interfering that were there just for class-specific values)
16457                         cnpt = t._gsClassPT;
16458                         if (cnpt) {
16459                                 cnptLookup = {};
16460                                 mpt = cnpt.data; //first MiniPropTween which stores the inline styles - we need to force these so that the inline styles don't contaminate things. Otherwise, there's a small chance that a tween could start and the inline values match the destination values and they never get cleaned.
16461                                 while (mpt) {
16462                                         cnptLookup[mpt.p] = 1;
16463                                         mpt = mpt._next;
16464                                 }
16465                                 cnpt.setRatio(1);
16466                         }
16467                         t._gsClassPT = pt;
16468                         pt.e = (e.charAt(1) !== "=") ? e : b.replace(new RegExp("\\s*\\b" + e.substr(2) + "\\b"), "") + ((e.charAt(0) === "+") ? " " + e.substr(2) : "");
16469                         if (cssp._tween._duration) { //if it's a zero-duration tween, there's no need to tween anything or parse the data. In fact, if we switch classes temporarily (which we must do for proper parsing) and the class has a transition applied, it could cause a quick flash to the end state and back again initially in some browsers.
16470                                 t.setAttribute("class", pt.e);
16471                                 difData = _cssDif(t, bs, _getAllStyles(t), vars, cnptLookup);
16472                                 t.setAttribute("class", b);
16473                                 pt.data = difData.firstMPT;
16474                                 t.style.cssText = cssText; //we recorded cssText before we swapped classes and ran _getAllStyles() because in cases when a className tween is overwritten, we remove all the related tweening properties from that class change (otherwise class-specific stuff can't override properties we've directly set on the target's style object due to specificity).
16475                                 pt = pt.xfirst = cssp.parse(t, difData.difs, pt, plugin); //we record the CSSPropTween as the xfirst so that we can handle overwriting propertly (if "className" gets overwritten, we must kill all the properties associated with the className part of the tween, so we can loop through from xfirst to the pt itself)
16476                         }
16477                         return pt;
16478                 }});
16479
16480
16481                 var _setClearPropsRatio = function(v) {
16482                         if (v === 1 || v === 0) if (this.data._totalTime === this.data._totalDuration && this.data.data !== "isFromStart") { //this.data refers to the tween. Only clear at the END of the tween (remember, from() tweens make the ratio go from 1 to 0, so we can't just check that and if the tween is the zero-duration one that's created internally to render the starting values in a from() tween, ignore that because otherwise, for example, from(...{height:100, clearProps:"height", delay:1}) would wipe the height at the beginning of the tween and after 1 second, it'd kick back in).
16483                                 var s = this.t.style,
16484                                         transformParse = _specialProps.transform.parse,
16485                                         a, p, i, clearTransform;
16486                                 if (this.e === "all") {
16487                                         s.cssText = "";
16488                                         clearTransform = true;
16489                                 } else {
16490                                         a = this.e.split(",");
16491                                         i = a.length;
16492                                         while (--i > -1) {
16493                                                 p = a[i];
16494                                                 if (_specialProps[p]) {
16495                                                         if (_specialProps[p].parse === transformParse) {
16496                                                                 clearTransform = true;
16497                                                         } else {
16498                                                                 p = (p === "transformOrigin") ? _transformOriginProp : _specialProps[p].p; //ensures that special properties use the proper browser-specific property name, like "scaleX" might be "-webkit-transform" or "boxShadow" might be "-moz-box-shadow"
16499                                                         }
16500                                                 }
16501                                                 _removeProp(s, p);
16502                                         }
16503                                 }
16504                                 if (clearTransform) {
16505                                         _removeProp(s, _transformProp);
16506                                         if (this.t._gsTransform) {
16507                                                 delete this.t._gsTransform;
16508                                         }
16509                                 }
16510
16511                         }
16512                 };
16513                 _registerComplexSpecialProp("clearProps", {parser:function(t, e, p, cssp, pt) {
16514                         pt = new CSSPropTween(t, p, 0, 0, pt, 2);
16515                         pt.setRatio = _setClearPropsRatio;
16516                         pt.e = e;
16517                         pt.pr = -10;
16518                         pt.data = cssp._tween;
16519                         _hasPriority = true;
16520                         return pt;
16521                 }});
16522
16523                 p = "bezier,throwProps,physicsProps,physics2D".split(",");
16524                 i = p.length;
16525                 while (i--) {
16526                         _registerPluginProp(p[i]);
16527                 }
16528
16529
16530
16531
16532
16533
16534
16535
16536                 p = CSSPlugin.prototype;
16537                 p._firstPT = null;
16538
16539                 //gets called when the tween renders for the first time. This kicks everything off, recording start/end values, etc.
16540                 p._onInitTween = function(target, vars, tween) {
16541                         if (!target.nodeType) { //css is only for dom elements
16542                                 return false;
16543                         }
16544                         this._target = target;
16545                         this._tween = tween;
16546                         this._vars = vars;
16547                         _autoRound = vars.autoRound;
16548                         _hasPriority = false;
16549                         _suffixMap = vars.suffixMap || CSSPlugin.suffixMap;
16550                         _cs = _getComputedStyle(target, "");
16551                         _overwriteProps = this._overwriteProps;
16552                         var style = target.style,
16553                                 v, pt, pt2, first, last, next, zIndex, tpt, threeD;
16554                         if (_reqSafariFix) if (style.zIndex === "") {
16555                                 v = _getStyle(target, "zIndex", _cs);
16556                                 if (v === "auto" || v === "") {
16557                                         //corrects a bug in [non-Android] Safari that prevents it from repainting elements in their new positions if they don't have a zIndex set. We also can't just apply this inside _parseTransform() because anything that's moved in any way (like using "left" or "top" instead of transforms like "x" and "y") can be affected, so it is best to ensure that anything that's tweening has a z-index. Setting "WebkitPerspective" to a non-zero value worked too except that on iOS Safari things would flicker randomly. Plus zIndex is less memory-intensive.
16558                                         this._addLazySet(style, "zIndex", 0);
16559                                 }
16560                         }
16561
16562                         if (typeof(vars) === "string") {
16563                                 first = style.cssText;
16564                                 v = _getAllStyles(target, _cs);
16565                                 style.cssText = first + ";" + vars;
16566                                 v = _cssDif(target, v, _getAllStyles(target)).difs;
16567                                 if (!_supportsOpacity && _opacityValExp.test(vars)) {
16568                                         v.opacity = parseFloat( RegExp.$1 );
16569                                 }
16570                                 vars = v;
16571                                 style.cssText = first;
16572                         }
16573                         this._firstPT = pt = this.parse(target, vars, null);
16574
16575                         if (this._transformType) {
16576                                 threeD = (this._transformType === 3);
16577                                 if (!_transformProp) {
16578                                         style.zoom = 1; //helps correct an IE issue.
16579                                 } else if (_isSafari) {
16580                                         _reqSafariFix = true;
16581                                         //if zIndex isn't set, iOS Safari doesn't repaint things correctly sometimes (seemingly at random).
16582                                         if (style.zIndex === "") {
16583                                                 zIndex = _getStyle(target, "zIndex", _cs);
16584                                                 if (zIndex === "auto" || zIndex === "") {
16585                                                         this._addLazySet(style, "zIndex", 0);
16586                                                 }
16587                                         }
16588                                         //Setting WebkitBackfaceVisibility corrects 3 bugs:
16589                                         // 1) [non-Android] Safari skips rendering changes to "top" and "left" that are made on the same frame/render as a transform update.
16590                                         // 2) iOS Safari sometimes neglects to repaint elements in their new positions. Setting "WebkitPerspective" to a non-zero value worked too except that on iOS Safari things would flicker randomly.
16591                                         // 3) Safari sometimes displayed odd artifacts when tweening the transform (or WebkitTransform) property, like ghosts of the edges of the element remained. Definitely a browser bug.
16592                                         //Note: we allow the user to override the auto-setting by defining WebkitBackfaceVisibility in the vars of the tween.
16593                                         if (_isSafariLT6) {
16594                                                 this._addLazySet(style, "WebkitBackfaceVisibility", this._vars.WebkitBackfaceVisibility || (threeD ? "visible" : "hidden"));
16595                                         }
16596                                 }
16597                                 pt2 = pt;
16598                                 while (pt2 && pt2._next) {
16599                                         pt2 = pt2._next;
16600                                 }
16601                                 tpt = new CSSPropTween(target, "transform", 0, 0, null, 2);
16602                                 this._linkCSSP(tpt, null, pt2);
16603                                 tpt.setRatio = (threeD && _supports3D) ? _set3DTransformRatio : _transformProp ? _set2DTransformRatio : _setIETransformRatio;
16604                                 tpt.data = this._transform || _getTransform(target, _cs, true);
16605                                 _overwriteProps.pop(); //we don't want to force the overwrite of all "transform" tweens of the target - we only care about individual transform properties like scaleX, rotation, etc. The CSSPropTween constructor automatically adds the property to _overwriteProps which is why we need to pop() here.
16606                         }
16607
16608                         if (_hasPriority) {
16609                                 //reorders the linked list in order of pr (priority)
16610                                 while (pt) {
16611                                         next = pt._next;
16612                                         pt2 = first;
16613                                         while (pt2 && pt2.pr > pt.pr) {
16614                                                 pt2 = pt2._next;
16615                                         }
16616                                         if ((pt._prev = pt2 ? pt2._prev : last)) {
16617                                                 pt._prev._next = pt;
16618                                         } else {
16619                                                 first = pt;
16620                                         }
16621                                         if ((pt._next = pt2)) {
16622                                                 pt2._prev = pt;
16623                                         } else {
16624                                                 last = pt;
16625                                         }
16626                                         pt = next;
16627                                 }
16628                                 this._firstPT = first;
16629                         }
16630                         return true;
16631                 };
16632
16633
16634                 p.parse = function(target, vars, pt, plugin) {
16635                         var style = target.style,
16636                                 p, sp, bn, en, bs, es, bsfx, esfx, isStr, rel;
16637                         for (p in vars) {
16638                                 es = vars[p]; //ending value string
16639                                 sp = _specialProps[p]; //SpecialProp lookup.
16640                                 if (sp) {
16641                                         pt = sp.parse(target, es, p, this, pt, plugin, vars);
16642
16643                                 } else {
16644                                         bs = _getStyle(target, p, _cs) + "";
16645                                         isStr = (typeof(es) === "string");
16646                                         if (p === "color" || p === "fill" || p === "stroke" || p.indexOf("Color") !== -1 || (isStr && _rgbhslExp.test(es))) { //Opera uses background: to define color sometimes in addition to backgroundColor:
16647                                                 if (!isStr) {
16648                                                         es = _parseColor(es);
16649                                                         es = ((es.length > 3) ? "rgba(" : "rgb(") + es.join(",") + ")";
16650                                                 }
16651                                                 pt = _parseComplex(style, p, bs, es, true, "transparent", pt, 0, plugin);
16652
16653                                         } else if (isStr && (es.indexOf(" ") !== -1 || es.indexOf(",") !== -1)) {
16654                                                 pt = _parseComplex(style, p, bs, es, true, null, pt, 0, plugin);
16655
16656                                         } else {
16657                                                 bn = parseFloat(bs);
16658                                                 bsfx = (bn || bn === 0) ? bs.substr((bn + "").length) : ""; //remember, bs could be non-numeric like "normal" for fontWeight, so we should default to a blank suffix in that case.
16659
16660                                                 if (bs === "" || bs === "auto") {
16661                                                         if (p === "width" || p === "height") {
16662                                                                 bn = _getDimension(target, p, _cs);
16663                                                                 bsfx = "px";
16664                                                         } else if (p === "left" || p === "top") {
16665                                                                 bn = _calculateOffset(target, p, _cs);
16666                                                                 bsfx = "px";
16667                                                         } else {
16668                                                                 bn = (p !== "opacity") ? 0 : 1;
16669                                                                 bsfx = "";
16670                                                         }
16671                                                 }
16672
16673                                                 rel = (isStr && es.charAt(1) === "=");
16674                                                 if (rel) {
16675                                                         en = parseInt(es.charAt(0) + "1", 10);
16676                                                         es = es.substr(2);
16677                                                         en *= parseFloat(es);
16678                                                         esfx = es.replace(_suffixExp, "");
16679                                                 } else {
16680                                                         en = parseFloat(es);
16681                                                         esfx = isStr ? es.substr((en + "").length) || "" : "";
16682                                                 }
16683
16684                                                 if (esfx === "") {
16685                                                         esfx = (p in _suffixMap) ? _suffixMap[p] : bsfx; //populate the end suffix, prioritizing the map, then if none is found, use the beginning suffix.
16686                                                 }
16687
16688                                                 es = (en || en === 0) ? (rel ? en + bn : en) + esfx : vars[p]; //ensures that any += or -= prefixes are taken care of. Record the end value before normalizing the suffix because we always want to end the tween on exactly what they intended even if it doesn't match the beginning value's suffix.
16689
16690                                                 //if the beginning/ending suffixes don't match, normalize them...
16691                                                 if (bsfx !== esfx) if (esfx !== "") if (en || en === 0) if (bn) { //note: if the beginning value (bn) is 0, we don't need to convert units!
16692                                                         bn = _convertToPixels(target, p, bn, bsfx);
16693                                                         if (esfx === "%") {
16694                                                                 bn /= _convertToPixels(target, p, 100, "%") / 100;
16695                                                                 if (vars.strictUnits !== true) { //some browsers report only "px" values instead of allowing "%" with getComputedStyle(), so we assume that if we're tweening to a %, we should start there too unless strictUnits:true is defined. This approach is particularly useful for responsive designs that use from() tweens.
16696                                                                         bs = bn + "%";
16697                                                                 }
16698
16699                                                         } else if (esfx === "em") {
16700                                                                 bn /= _convertToPixels(target, p, 1, "em");
16701
16702                                                         //otherwise convert to pixels.
16703                                                         } else if (esfx !== "px") {
16704                                                                 en = _convertToPixels(target, p, en, esfx);
16705                                                                 esfx = "px"; //we don't use bsfx after this, so we don't need to set it to px too.
16706                                                         }
16707                                                         if (rel) if (en || en === 0) {
16708                                                                 es = (en + bn) + esfx; //the changes we made affect relative calculations, so adjust the end value here.
16709                                                         }
16710                                                 }
16711
16712                                                 if (rel) {
16713                                                         en += bn;
16714                                                 }
16715
16716                                                 if ((bn || bn === 0) && (en || en === 0)) { //faster than isNaN(). Also, previously we required en !== bn but that doesn't really gain much performance and it prevents _parseToProxy() from working properly if beginning and ending values match but need to get tweened by an external plugin anyway. For example, a bezier tween where the target starts at left:0 and has these points: [{left:50},{left:0}] wouldn't work properly because when parsing the last point, it'd match the first (current) one and a non-tweening CSSPropTween would be recorded when we actually need a normal tween (type:0) so that things get updated during the tween properly.
16717                                                         pt = new CSSPropTween(style, p, bn, en - bn, pt, 0, p, (_autoRound !== false && (esfx === "px" || p === "zIndex")), 0, bs, es);
16718                                                         pt.xs0 = esfx;
16719                                                         //DEBUG: _log("tween "+p+" from "+pt.b+" ("+bn+esfx+") to "+pt.e+" with suffix: "+pt.xs0);
16720                                                 } else if (style[p] === undefined || !es && (es + "" === "NaN" || es == null)) {
16721                                                         _log("invalid " + p + " tween value: " + vars[p]);
16722                                                 } else {
16723                                                         pt = new CSSPropTween(style, p, en || bn || 0, 0, pt, -1, p, false, 0, bs, es);
16724                                                         pt.xs0 = (es === "none" && (p === "display" || p.indexOf("Style") !== -1)) ? bs : es; //intermediate value should typically be set immediately (end value) except for "display" or things like borderTopStyle, borderBottomStyle, etc. which should use the beginning value during the tween.
16725                                                         //DEBUG: _log("non-tweening value "+p+": "+pt.xs0);
16726                                                 }
16727                                         }
16728                                 }
16729                                 if (plugin) if (pt && !pt.plugin) {
16730                                         pt.plugin = plugin;
16731                                 }
16732                         }
16733                         return pt;
16734                 };
16735
16736
16737                 //gets called every time the tween updates, passing the new ratio (typically a value between 0 and 1, but not always (for example, if an Elastic.easeOut is used, the value can jump above 1 mid-tween). It will always start and 0 and end at 1.
16738                 p.setRatio = function(v) {
16739                         var pt = this._firstPT,
16740                                 min = 0.000001,
16741                                 val, str, i;
16742
16743                         //at the end of the tween, we set the values to exactly what we received in order to make sure non-tweening values (like "position" or "float" or whatever) are set and so that if the beginning/ending suffixes (units) didn't match and we normalized to px, the value that the user passed in is used here. We check to see if the tween is at its beginning in case it's a from() tween in which case the ratio will actually go from 1 to 0 over the course of the tween (backwards).
16744                         if (v === 1 && (this._tween._time === this._tween._duration || this._tween._time === 0)) {
16745                                 while (pt) {
16746                                         if (pt.type !== 2) {
16747                                                 pt.t[pt.p] = pt.e;
16748                                         } else {
16749                                                 pt.setRatio(v);
16750                                         }
16751                                         pt = pt._next;
16752                                 }
16753
16754                         } else if (v || !(this._tween._time === this._tween._duration || this._tween._time === 0) || this._tween._rawPrevTime === -0.000001) {
16755                                 while (pt) {
16756                                         val = pt.c * v + pt.s;
16757                                         if (pt.r) {
16758                                                 val = Math.round(val);
16759                                         } else if (val < min) if (val > -min) {
16760                                                 val = 0;
16761                                         }
16762                                         if (!pt.type) {
16763                                                 pt.t[pt.p] = val + pt.xs0;
16764                                         } else if (pt.type === 1) { //complex value (one that typically has multiple numbers inside a string, like "rect(5px,10px,20px,25px)"
16765                                                 i = pt.l;
16766                                                 if (i === 2) {
16767                                                         pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2;
16768                                                 } else if (i === 3) {
16769                                                         pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3;
16770                                                 } else if (i === 4) {
16771                                                         pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3 + pt.xn3 + pt.xs4;
16772                                                 } else if (i === 5) {
16773                                                         pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3 + pt.xn3 + pt.xs4 + pt.xn4 + pt.xs5;
16774                                                 } else {
16775                                                         str = pt.xs0 + val + pt.xs1;
16776                                                         for (i = 1; i < pt.l; i++) {
16777                                                                 str += pt["xn"+i] + pt["xs"+(i+1)];
16778                                                         }
16779                                                         pt.t[pt.p] = str;
16780                                                 }
16781
16782                                         } else if (pt.type === -1) { //non-tweening value
16783                                                 pt.t[pt.p] = pt.xs0;
16784
16785                                         } else if (pt.setRatio) { //custom setRatio() for things like SpecialProps, external plugins, etc.
16786                                                 pt.setRatio(v);
16787                                         }
16788                                         pt = pt._next;
16789                                 }
16790
16791                         //if the tween is reversed all the way back to the beginning, we need to restore the original values which may have different units (like % instead of px or em or whatever).
16792                         } else {
16793                                 while (pt) {
16794                                         if (pt.type !== 2) {
16795                                                 pt.t[pt.p] = pt.b;
16796                                         } else {
16797                                                 pt.setRatio(v);
16798                                         }
16799                                         pt = pt._next;
16800                                 }
16801                         }
16802                 };
16803
16804                 /**
16805                  * @private
16806                  * Forces rendering of the target's transforms (rotation, scale, etc.) whenever the CSSPlugin's setRatio() is called.
16807                  * Basically, this tells the CSSPlugin to create a CSSPropTween (type 2) after instantiation that runs last in the linked
16808                  * list and calls the appropriate (3D or 2D) rendering function. We separate this into its own method so that we can call
16809                  * it from other plugins like BezierPlugin if, for example, it needs to apply an autoRotation and this CSSPlugin
16810                  * doesn't have any transform-related properties of its own. You can call this method as many times as you
16811                  * want and it won't create duplicate CSSPropTweens.
16812                  *
16813                  * @param {boolean} threeD if true, it should apply 3D tweens (otherwise, just 2D ones are fine and typically faster)
16814                  */
16815                 p._enableTransforms = function(threeD) {
16816                         this._transformType = (threeD || this._transformType === 3) ? 3 : 2;
16817                         this._transform = this._transform || _getTransform(this._target, _cs, true); //ensures that the element has a _gsTransform property with the appropriate values.
16818                 };
16819
16820                 var lazySet = function(v) {
16821                         this.t[this.p] = this.e;
16822                         this.data._linkCSSP(this, this._next, null, true); //we purposefully keep this._next even though it'd make sense to null it, but this is a performance optimization, as this happens during the while (pt) {} loop in setRatio() at the bottom of which it sets pt = pt._next, so if we null it, the linked list will be broken in that loop.
16823                 };
16824                 /** @private Gives us a way to set a value on the first render (and only the first render). **/
16825                 p._addLazySet = function(t, p, v) {
16826                         var pt = this._firstPT = new CSSPropTween(t, p, 0, 0, this._firstPT, 2);
16827                         pt.e = v;
16828                         pt.setRatio = lazySet;
16829                         pt.data = this;
16830                 };
16831
16832                 /** @private **/
16833                 p._linkCSSP = function(pt, next, prev, remove) {
16834                         if (pt) {
16835                                 if (next) {
16836                                         next._prev = pt;
16837                                 }
16838                                 if (pt._next) {
16839                                         pt._next._prev = pt._prev;
16840                                 }
16841                                 if (pt._prev) {
16842                                         pt._prev._next = pt._next;
16843                                 } else if (this._firstPT === pt) {
16844                                         this._firstPT = pt._next;
16845                                         remove = true; //just to prevent resetting this._firstPT 5 lines down in case pt._next is null. (optimized for speed)
16846                                 }
16847                                 if (prev) {
16848                                         prev._next = pt;
16849                                 } else if (!remove && this._firstPT === null) {
16850                                         this._firstPT = pt;
16851                                 }
16852                                 pt._next = next;
16853                                 pt._prev = prev;
16854                         }
16855                         return pt;
16856                 };
16857
16858                 //we need to make sure that if alpha or autoAlpha is killed, opacity is too. And autoAlpha affects the "visibility" property.
16859                 p._kill = function(lookup) {
16860                         var copy = lookup,
16861                                 pt, p, xfirst;
16862                         if (lookup.autoAlpha || lookup.alpha) {
16863                                 copy = {};
16864                                 for (p in lookup) { //copy the lookup so that we're not changing the original which may be passed elsewhere.
16865                                         copy[p] = lookup[p];
16866                                 }
16867                                 copy.opacity = 1;
16868                                 if (copy.autoAlpha) {
16869                                         copy.visibility = 1;
16870                                 }
16871                         }
16872                         if (lookup.className && (pt = this._classNamePT)) { //for className tweens, we need to kill any associated CSSPropTweens too; a linked list starts at the className's "xfirst".
16873                                 xfirst = pt.xfirst;
16874                                 if (xfirst && xfirst._prev) {
16875                                         this._linkCSSP(xfirst._prev, pt._next, xfirst._prev._prev); //break off the prev
16876                                 } else if (xfirst === this._firstPT) {
16877                                         this._firstPT = pt._next;
16878                                 }
16879                                 if (pt._next) {
16880                                         this._linkCSSP(pt._next, pt._next._next, xfirst._prev);
16881                                 }
16882                                 this._classNamePT = null;
16883                         }
16884                         return TweenPlugin.prototype._kill.call(this, copy);
16885                 };
16886
16887
16888
16889                 //used by cascadeTo() for gathering all the style properties of each child element into an array for comparison.
16890                 var _getChildStyles = function(e, props, targets) {
16891                                 var children, i, child, type;
16892                                 if (e.slice) {
16893                                         i = e.length;
16894                                         while (--i > -1) {
16895                                                 _getChildStyles(e[i], props, targets);
16896                                         }
16897                                         return;
16898                                 }
16899                                 children = e.childNodes;
16900                                 i = children.length;
16901                                 while (--i > -1) {
16902                                         child = children[i];
16903                                         type = child.type;
16904                                         if (child.style) {
16905                                                 props.push(_getAllStyles(child));
16906                                                 if (targets) {
16907                                                         targets.push(child);
16908                                                 }
16909                                         }
16910                                         if ((type === 1 || type === 9 || type === 11) && child.childNodes.length) {
16911                                                 _getChildStyles(child, props, targets);
16912                                         }
16913                                 }
16914                         };
16915
16916                 /**
16917                  * Typically only useful for className tweens that may affect child elements, this method creates a TweenLite
16918                  * and then compares the style properties of all the target's child elements at the tween's start and end, and
16919                  * if any are different, it also creates tweens for those and returns an array containing ALL of the resulting
16920                  * tweens (so that you can easily add() them to a TimelineLite, for example). The reason this functionality is
16921                  * wrapped into a separate static method of CSSPlugin instead of being integrated into all regular className tweens
16922                  * is because it creates entirely new tweens that may have completely different targets than the original tween,
16923                  * so if they were all lumped into the original tween instance, it would be inconsistent with the rest of the API
16924                  * and it would create other problems. For example:
16925                  *  - If I create a tween of elementA, that tween instance may suddenly change its target to include 50 other elements (unintuitive if I specifically defined the target I wanted)
16926                  *  - We can't just create new independent tweens because otherwise, what happens if the original/parent tween is reversed or pause or dropped into a TimelineLite for tight control? You'd expect that tween's behavior to affect all the others.
16927                  *  - Analyzing every style property of every child before and after the tween is an expensive operation when there are many children, so this behavior shouldn't be imposed on all className tweens by default, especially since it's probably rare that this extra functionality is needed.
16928                  *
16929                  * @param {Object} target object to be tweened
16930                  * @param {number} Duration in seconds (or frames for frames-based tweens)
16931                  * @param {Object} Object containing the end values, like {className:"newClass", ease:Linear.easeNone}
16932                  * @return {Array} An array of TweenLite instances
16933                  */
16934                 CSSPlugin.cascadeTo = function(target, duration, vars) {
16935                         var tween = TweenLite.to(target, duration, vars),
16936                                 results = [tween],
16937                                 b = [],
16938                                 e = [],
16939                                 targets = [],
16940                                 _reservedProps = TweenLite._internals.reservedProps,
16941                                 i, difs, p;
16942                         target = tween._targets || tween.target;
16943                         _getChildStyles(target, b, targets);
16944                         tween.render(duration, true);
16945                         _getChildStyles(target, e);
16946                         tween.render(0, true);
16947                         tween._enabled(true);
16948                         i = targets.length;
16949                         while (--i > -1) {
16950                                 difs = _cssDif(targets[i], b[i], e[i]);
16951                                 if (difs.firstMPT) {
16952                                         difs = difs.difs;
16953                                         for (p in vars) {
16954                                                 if (_reservedProps[p]) {
16955                                                         difs[p] = vars[p];
16956                                                 }
16957                                         }
16958                                         results.push( TweenLite.to(targets[i], duration, difs) );
16959                                 }
16960                         }
16961                         return results;
16962                 };
16963
16964                 TweenPlugin.activate([CSSPlugin]);
16965                 return CSSPlugin;
16966
16967         }, true);
16968
16969         
16970         
16971         
16972         
16973         
16974         
16975         
16976         
16977         
16978         
16979 /*
16980  * ----------------------------------------------------------------
16981  * RoundPropsPlugin
16982  * ----------------------------------------------------------------
16983  */
16984         (function() {
16985
16986                 var RoundPropsPlugin = window._gsDefine.plugin({
16987                                 propName: "roundProps",
16988                                 priority: -1,
16989                                 API: 2,
16990
16991                                 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
16992                                 init: function(target, value, tween) {
16993                                         this._tween = tween;
16994                                         return true;
16995                                 }
16996
16997                         }),
16998                         p = RoundPropsPlugin.prototype;
16999
17000                 p._onInitAllProps = function() {
17001                         var tween = this._tween,
17002                                 rp = (tween.vars.roundProps instanceof Array) ? tween.vars.roundProps : tween.vars.roundProps.split(","),
17003                                 i = rp.length,
17004                                 lookup = {},
17005                                 rpt = tween._propLookup.roundProps,
17006                                 prop, pt, next;
17007                         while (--i > -1) {
17008                                 lookup[rp[i]] = 1;
17009                         }
17010                         i = rp.length;
17011                         while (--i > -1) {
17012                                 prop = rp[i];
17013                                 pt = tween._firstPT;
17014                                 while (pt) {
17015                                         next = pt._next; //record here, because it may get removed
17016                                         if (pt.pg) {
17017                                                 pt.t._roundProps(lookup, true);
17018                                         } else if (pt.n === prop) {
17019                                                 this._add(pt.t, prop, pt.s, pt.c);
17020                                                 //remove from linked list
17021                                                 if (next) {
17022                                                         next._prev = pt._prev;
17023                                                 }
17024                                                 if (pt._prev) {
17025                                                         pt._prev._next = next;
17026                                                 } else if (tween._firstPT === pt) {
17027                                                         tween._firstPT = next;
17028                                                 }
17029                                                 pt._next = pt._prev = null;
17030                                                 tween._propLookup[prop] = rpt;
17031                                         }
17032                                         pt = next;
17033                                 }
17034                         }
17035                         return false;
17036                 };
17037
17038                 p._add = function(target, p, s, c) {
17039                         this._addTween(target, p, s, s + c, p, true);
17040                         this._overwriteProps.push(p);
17041                 };
17042
17043         }());
17044
17045
17046
17047
17048
17049
17050
17051
17052
17053
17054 /*
17055  * ----------------------------------------------------------------
17056  * AttrPlugin
17057  * ----------------------------------------------------------------
17058  */
17059         window._gsDefine.plugin({
17060                 propName: "attr",
17061                 API: 2,
17062                 version: "0.3.2",
17063
17064                 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
17065                 init: function(target, value, tween) {
17066                         var p, start, end;
17067                         if (typeof(target.setAttribute) !== "function") {
17068                                 return false;
17069                         }
17070                         this._target = target;
17071                         this._proxy = {};
17072                         this._start = {}; // we record start and end values exactly as they are in case they're strings (not numbers) - we need to be able to revert to them cleanly.
17073                         this._end = {};
17074                         for (p in value) {
17075                                 this._start[p] = this._proxy[p] = start = target.getAttribute(p);
17076                                 end = this._addTween(this._proxy, p, parseFloat(start), value[p], p);
17077                                 this._end[p] = end ? end.s + end.c : value[p];
17078                                 this._overwriteProps.push(p);
17079                         }
17080                         return true;
17081                 },
17082
17083                 //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
17084                 set: function(ratio) {
17085                         this._super.setRatio.call(this, ratio);
17086                         var props = this._overwriteProps,
17087                                 i = props.length,
17088                                 lookup = (ratio === 1) ? this._end : ratio ? this._proxy : this._start,
17089                                 p;
17090                         while (--i > -1) {
17091                                 p = props[i];
17092                                 this._target.setAttribute(p, lookup[p] + "");
17093                         }
17094                 }
17095
17096         });
17097
17098
17099
17100
17101
17102
17103
17104
17105
17106
17107 /*
17108  * ----------------------------------------------------------------
17109  * DirectionalRotationPlugin
17110  * ----------------------------------------------------------------
17111  */
17112         window._gsDefine.plugin({
17113                 propName: "directionalRotation",
17114                 API: 2,
17115                 version: "0.2.0",
17116
17117                 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
17118                 init: function(target, value, tween) {
17119                         if (typeof(value) !== "object") {
17120                                 value = {rotation:value};
17121                         }
17122                         this.finals = {};
17123                         var cap = (value.useRadians === true) ? Math.PI * 2 : 360,
17124                                 min = 0.000001,
17125                                 p, v, start, end, dif, split;
17126                         for (p in value) {
17127                                 if (p !== "useRadians") {
17128                                         split = (value[p] + "").split("_");
17129                                         v = split[0];
17130                                         start = parseFloat( (typeof(target[p]) !== "function") ? target[p] : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]() );
17131                                         end = this.finals[p] = (typeof(v) === "string" && v.charAt(1) === "=") ? start + parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) : Number(v) || 0;
17132                                         dif = end - start;
17133                                         if (split.length) {
17134                                                 v = split.join("_");
17135                                                 if (v.indexOf("short") !== -1) {
17136                                                         dif = dif % cap;
17137                                                         if (dif !== dif % (cap / 2)) {
17138                                                                 dif = (dif < 0) ? dif + cap : dif - cap;
17139                                                         }
17140                                                 }
17141                                                 if (v.indexOf("_cw") !== -1 && dif < 0) {
17142                                                         dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
17143                                                 } else if (v.indexOf("ccw") !== -1 && dif > 0) {
17144                                                         dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
17145                                                 }
17146                                         }
17147                                         if (dif > min || dif < -min) {
17148                                                 this._addTween(target, p, start, start + dif, p);
17149                                                 this._overwriteProps.push(p);
17150                                         }
17151                                 }
17152                         }
17153                         return true;
17154                 },
17155
17156                 //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
17157                 set: function(ratio) {
17158                         var pt;
17159                         if (ratio !== 1) {
17160                                 this._super.setRatio.call(this, ratio);
17161                         } else {
17162                                 pt = this._firstPT;
17163                                 while (pt) {
17164                                         if (pt.f) {
17165                                                 pt.t[pt.p](this.finals[pt.p]);
17166                                         } else {
17167                                                 pt.t[pt.p] = this.finals[pt.p];
17168                                         }
17169                                         pt = pt._next;
17170                                 }
17171                         }
17172                 }
17173
17174         })._autoCSS = true;
17175
17176
17177
17178
17179
17180
17181
17182         
17183         
17184         
17185         
17186 /*
17187  * ----------------------------------------------------------------
17188  * EasePack
17189  * ----------------------------------------------------------------
17190  */
17191         window._gsDefine("easing.Back", ["easing.Ease"], function(Ease) {
17192                 
17193                 var w = (window.GreenSockGlobals || window),
17194                         gs = w.com.greensock,
17195                         _2PI = Math.PI * 2,
17196                         _HALF_PI = Math.PI / 2,
17197                         _class = gs._class,
17198                         _create = function(n, f) {
17199                                 var C = _class("easing." + n, function(){}, true),
17200                                         p = C.prototype = new Ease();
17201                                 p.constructor = C;
17202                                 p.getRatio = f;
17203                                 return C;
17204                         },
17205                         _easeReg = Ease.register || function(){}, //put an empty function in place just as a safety measure in case someone loads an OLD version of TweenLite.js where Ease.register doesn't exist.
17206                         _wrap = function(name, EaseOut, EaseIn, EaseInOut, aliases) {
17207                                 var C = _class("easing."+name, {
17208                                         easeOut:new EaseOut(),
17209                                         easeIn:new EaseIn(),
17210                                         easeInOut:new EaseInOut()
17211                                 }, true);
17212                                 _easeReg(C, name);
17213                                 return C;
17214                         },
17215                         EasePoint = function(time, value, next) {
17216                                 this.t = time;
17217                                 this.v = value;
17218                                 if (next) {
17219                                         this.next = next;
17220                                         next.prev = this;
17221                                         this.c = next.v - value;
17222                                         this.gap = next.t - time;
17223                                 }
17224                         },
17225
17226                         //Back
17227                         _createBack = function(n, f) {
17228                                 var C = _class("easing." + n, function(overshoot) {
17229                                                 this._p1 = (overshoot || overshoot === 0) ? overshoot : 1.70158;
17230                                                 this._p2 = this._p1 * 1.525;
17231                                         }, true),
17232                                         p = C.prototype = new Ease();
17233                                 p.constructor = C;
17234                                 p.getRatio = f;
17235                                 p.config = function(overshoot) {
17236                                         return new C(overshoot);
17237                                 };
17238                                 return C;
17239                         },
17240
17241                         Back = _wrap("Back",
17242                                 _createBack("BackOut", function(p) {
17243                                         return ((p = p - 1) * p * ((this._p1 + 1) * p + this._p1) + 1);
17244                                 }),
17245                                 _createBack("BackIn", function(p) {
17246                                         return p * p * ((this._p1 + 1) * p - this._p1);
17247                                 }),
17248                                 _createBack("BackInOut", function(p) {
17249                                         return ((p *= 2) < 1) ? 0.5 * p * p * ((this._p2 + 1) * p - this._p2) : 0.5 * ((p -= 2) * p * ((this._p2 + 1) * p + this._p2) + 2);
17250                                 })
17251                         ),
17252
17253
17254                         //SlowMo
17255                         SlowMo = _class("easing.SlowMo", function(linearRatio, power, yoyoMode) {
17256                                 power = (power || power === 0) ? power : 0.7;
17257                                 if (linearRatio == null) {
17258                                         linearRatio = 0.7;
17259                                 } else if (linearRatio > 1) {
17260                                         linearRatio = 1;
17261                                 }
17262                                 this._p = (linearRatio !== 1) ? power : 0;
17263                                 this._p1 = (1 - linearRatio) / 2;
17264                                 this._p2 = linearRatio;
17265                                 this._p3 = this._p1 + this._p2;
17266                                 this._calcEnd = (yoyoMode === true);
17267                         }, true),
17268                         p = SlowMo.prototype = new Ease(),
17269                         SteppedEase, RoughEase, _createElastic;
17270
17271                 p.constructor = SlowMo;
17272                 p.getRatio = function(p) {
17273                         var r = p + (0.5 - p) * this._p;
17274                         if (p < this._p1) {
17275                                 return this._calcEnd ? 1 - ((p = 1 - (p / this._p1)) * p) : r - ((p = 1 - (p / this._p1)) * p * p * p * r);
17276                         } else if (p > this._p3) {
17277                                 return this._calcEnd ? 1 - (p = (p - this._p3) / this._p1) * p : r + ((p - r) * (p = (p - this._p3) / this._p1) * p * p * p);
17278                         }
17279                         return this._calcEnd ? 1 : r;
17280                 };
17281                 SlowMo.ease = new SlowMo(0.7, 0.7);
17282
17283                 p.config = SlowMo.config = function(linearRatio, power, yoyoMode) {
17284                         return new SlowMo(linearRatio, power, yoyoMode);
17285                 };
17286
17287
17288                 //SteppedEase
17289                 SteppedEase = _class("easing.SteppedEase", function(steps) {
17290                                 steps = steps || 1;
17291                                 this._p1 = 1 / steps;
17292                                 this._p2 = steps + 1;
17293                         }, true);
17294                 p = SteppedEase.prototype = new Ease();
17295                 p.constructor = SteppedEase;
17296                 p.getRatio = function(p) {
17297                         if (p < 0) {
17298                                 p = 0;
17299                         } else if (p >= 1) {
17300                                 p = 0.999999999;
17301                         }
17302                         return ((this._p2 * p) >> 0) * this._p1;
17303                 };
17304                 p.config = SteppedEase.config = function(steps) {
17305                         return new SteppedEase(steps);
17306                 };
17307
17308
17309                 //RoughEase
17310                 RoughEase = _class("easing.RoughEase", function(vars) {
17311                         vars = vars || {};
17312                         var taper = vars.taper || "none",
17313                                 a = [],
17314                                 cnt = 0,
17315                                 points = (vars.points || 20) | 0,
17316                                 i = points,
17317                                 randomize = (vars.randomize !== false),
17318                                 clamp = (vars.clamp === true),
17319                                 template = (vars.template instanceof Ease) ? vars.template : null,
17320                                 strength = (typeof(vars.strength) === "number") ? vars.strength * 0.4 : 0.4,
17321                                 x, y, bump, invX, obj, pnt;
17322                         while (--i > -1) {
17323                                 x = randomize ? Math.random() : (1 / points) * i;
17324                                 y = template ? template.getRatio(x) : x;
17325                                 if (taper === "none") {
17326                                         bump = strength;
17327                                 } else if (taper === "out") {
17328                                         invX = 1 - x;
17329                                         bump = invX * invX * strength;
17330                                 } else if (taper === "in") {
17331                                         bump = x * x * strength;
17332                                 } else if (x < 0.5) {  //"both" (start)
17333                                         invX = x * 2;
17334                                         bump = invX * invX * 0.5 * strength;
17335                                 } else {                                //"both" (end)
17336                                         invX = (1 - x) * 2;
17337                                         bump = invX * invX * 0.5 * strength;
17338                                 }
17339                                 if (randomize) {
17340                                         y += (Math.random() * bump) - (bump * 0.5);
17341                                 } else if (i % 2) {
17342                                         y += bump * 0.5;
17343                                 } else {
17344                                         y -= bump * 0.5;
17345                                 }
17346                                 if (clamp) {
17347                                         if (y > 1) {
17348                                                 y = 1;
17349                                         } else if (y < 0) {
17350                                                 y = 0;
17351                                         }
17352                                 }
17353                                 a[cnt++] = {x:x, y:y};
17354                         }
17355                         a.sort(function(a, b) {
17356                                 return a.x - b.x;
17357                         });
17358
17359                         pnt = new EasePoint(1, 1, null);
17360                         i = points;
17361                         while (--i > -1) {
17362                                 obj = a[i];
17363                                 pnt = new EasePoint(obj.x, obj.y, pnt);
17364                         }
17365
17366                         this._prev = new EasePoint(0, 0, (pnt.t !== 0) ? pnt : pnt.next);
17367                 }, true);
17368                 p = RoughEase.prototype = new Ease();
17369                 p.constructor = RoughEase;
17370                 p.getRatio = function(p) {
17371                         var pnt = this._prev;
17372                         if (p > pnt.t) {
17373                                 while (pnt.next && p >= pnt.t) {
17374                                         pnt = pnt.next;
17375                                 }
17376                                 pnt = pnt.prev;
17377                         } else {
17378                                 while (pnt.prev && p <= pnt.t) {
17379                                         pnt = pnt.prev;
17380                                 }
17381                         }
17382                         this._prev = pnt;
17383                         return (pnt.v + ((p - pnt.t) / pnt.gap) * pnt.c);
17384                 };
17385                 p.config = function(vars) {
17386                         return new RoughEase(vars);
17387                 };
17388                 RoughEase.ease = new RoughEase();
17389
17390
17391                 //Bounce
17392                 _wrap("Bounce",
17393                         _create("BounceOut", function(p) {
17394                                 if (p < 1 / 2.75) {
17395                                         return 7.5625 * p * p;
17396                                 } else if (p < 2 / 2.75) {
17397                                         return 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;
17398                                 } else if (p < 2.5 / 2.75) {
17399                                         return 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;
17400                                 }
17401                                 return 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;
17402                         }),
17403                         _create("BounceIn", function(p) {
17404                                 if ((p = 1 - p) < 1 / 2.75) {
17405                                         return 1 - (7.5625 * p * p);
17406                                 } else if (p < 2 / 2.75) {
17407                                         return 1 - (7.5625 * (p -= 1.5 / 2.75) * p + 0.75);
17408                                 } else if (p < 2.5 / 2.75) {
17409                                         return 1 - (7.5625 * (p -= 2.25 / 2.75) * p + 0.9375);
17410                                 }
17411                                 return 1 - (7.5625 * (p -= 2.625 / 2.75) * p + 0.984375);
17412                         }),
17413                         _create("BounceInOut", function(p) {
17414                                 var invert = (p < 0.5);
17415                                 if (invert) {
17416                                         p = 1 - (p * 2);
17417                                 } else {
17418                                         p = (p * 2) - 1;
17419                                 }
17420                                 if (p < 1 / 2.75) {
17421                                         p = 7.5625 * p * p;
17422                                 } else if (p < 2 / 2.75) {
17423                                         p = 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;
17424                                 } else if (p < 2.5 / 2.75) {
17425                                         p = 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;
17426                                 } else {
17427                                         p = 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;
17428                                 }
17429                                 return invert ? (1 - p) * 0.5 : p * 0.5 + 0.5;
17430                         })
17431                 );
17432
17433
17434                 //CIRC
17435                 _wrap("Circ",
17436                         _create("CircOut", function(p) {
17437                                 return Math.sqrt(1 - (p = p - 1) * p);
17438                         }),
17439                         _create("CircIn", function(p) {
17440                                 return -(Math.sqrt(1 - (p * p)) - 1);
17441                         }),
17442                         _create("CircInOut", function(p) {
17443                                 return ((p*=2) < 1) ? -0.5 * (Math.sqrt(1 - p * p) - 1) : 0.5 * (Math.sqrt(1 - (p -= 2) * p) + 1);
17444                         })
17445                 );
17446
17447
17448                 //Elastic
17449                 _createElastic = function(n, f, def) {
17450                         var C = _class("easing." + n, function(amplitude, period) {
17451                                         this._p1 = amplitude || 1;
17452                                         this._p2 = period || def;
17453                                         this._p3 = this._p2 / _2PI * (Math.asin(1 / this._p1) || 0);
17454                                 }, true),
17455                                 p = C.prototype = new Ease();
17456                         p.constructor = C;
17457                         p.getRatio = f;
17458                         p.config = function(amplitude, period) {
17459                                 return new C(amplitude, period);
17460                         };
17461                         return C;
17462                 };
17463                 _wrap("Elastic",
17464                         _createElastic("ElasticOut", function(p) {
17465                                 return this._p1 * Math.pow(2, -10 * p) * Math.sin( (p - this._p3) * _2PI / this._p2 ) + 1;
17466                         }, 0.3),
17467                         _createElastic("ElasticIn", function(p) {
17468                                 return -(this._p1 * Math.pow(2, 10 * (p -= 1)) * Math.sin( (p - this._p3) * _2PI / this._p2 ));
17469                         }, 0.3),
17470                         _createElastic("ElasticInOut", function(p) {
17471                                 return ((p *= 2) < 1) ? -0.5 * (this._p1 * Math.pow(2, 10 * (p -= 1)) * Math.sin( (p - this._p3) * _2PI / this._p2)) : this._p1 * Math.pow(2, -10 *(p -= 1)) * Math.sin( (p - this._p3) * _2PI / this._p2 ) *0.5 + 1;
17472                         }, 0.45)
17473                 );
17474
17475
17476                 //Expo
17477                 _wrap("Expo",
17478                         _create("ExpoOut", function(p) {
17479                                 return 1 - Math.pow(2, -10 * p);
17480                         }),
17481                         _create("ExpoIn", function(p) {
17482                                 return Math.pow(2, 10 * (p - 1)) - 0.001;
17483                         }),
17484                         _create("ExpoInOut", function(p) {
17485                                 return ((p *= 2) < 1) ? 0.5 * Math.pow(2, 10 * (p - 1)) : 0.5 * (2 - Math.pow(2, -10 * (p - 1)));
17486                         })
17487                 );
17488
17489
17490                 //Sine
17491                 _wrap("Sine",
17492                         _create("SineOut", function(p) {
17493                                 return Math.sin(p * _HALF_PI);
17494                         }),
17495                         _create("SineIn", function(p) {
17496                                 return -Math.cos(p * _HALF_PI) + 1;
17497                         }),
17498                         _create("SineInOut", function(p) {
17499                                 return -0.5 * (Math.cos(Math.PI * p) - 1);
17500                         })
17501                 );
17502
17503                 _class("easing.EaseLookup", {
17504                                 find:function(s) {
17505                                         return Ease.map[s];
17506                                 }
17507                         }, true);
17508
17509                 //register the non-standard eases
17510                 _easeReg(w.SlowMo, "SlowMo", "ease,");
17511                 _easeReg(RoughEase, "RoughEase", "ease,");
17512                 _easeReg(SteppedEase, "SteppedEase", "ease,");
17513
17514                 return Back;
17515                 
17516         }, true);
17517
17518
17519 }); 
17520
17521
17522
17523
17524
17525
17526
17527
17528
17529
17530
17531 /*
17532  * ----------------------------------------------------------------
17533  * Base classes like TweenLite, SimpleTimeline, Ease, Ticker, etc.
17534  * ----------------------------------------------------------------
17535  */
17536 (function(window) {
17537
17538                 "use strict";
17539                 var _globals = window.GreenSockGlobals || window;
17540                 if (_globals.TweenLite) {
17541                         return; //in case the core set of classes is already loaded, don't instantiate twice.
17542                 }
17543                 var _namespace = function(ns) {
17544                                 var a = ns.split("."),
17545                                         p = _globals, i;
17546                                 for (i = 0; i < a.length; i++) {
17547                                         p[a[i]] = p = p[a[i]] || {};
17548                                 }
17549                                 return p;
17550                         },
17551                         gs = _namespace("com.greensock"),
17552                         _tinyNum = 0.0000000001,
17553                         _slice = [].slice,
17554                         _emptyFunc = function() {},
17555                         _isArray = (function() { //works around issues in iframe environments where the Array global isn't shared, thus if the object originates in a different window/iframe, "(obj instanceof Array)" will evaluate false. We added some speed optimizations to avoid Object.prototype.toString.call() unless it's absolutely necessary because it's VERY slow (like 20x slower)
17556                                 var toString = Object.prototype.toString,
17557                                         array = toString.call([]);
17558                                 return function(obj) {
17559                                         return obj != null && (obj instanceof Array || (typeof(obj) === "object" && !!obj.push && toString.call(obj) === array));
17560                                 };
17561                         }()),
17562                         a, i, p, _ticker, _tickerActive,
17563                         _defLookup = {},
17564
17565                         /**
17566                          * @constructor
17567                          * Defines a GreenSock class, optionally with an array of dependencies that must be instantiated first and passed into the definition.
17568                          * This allows users to load GreenSock JS files in any order even if they have interdependencies (like CSSPlugin extends TweenPlugin which is
17569                          * inside TweenLite.js, but if CSSPlugin is loaded first, it should wait to run its code until TweenLite.js loads and instantiates TweenPlugin
17570                          * and then pass TweenPlugin to CSSPlugin's definition). This is all done automatically and internally.
17571                          *
17572                          * Every definition will be added to a "com.greensock" global object (typically window, but if a window.GreenSockGlobals object is found,
17573                          * it will go there as of v1.7). For example, TweenLite will be found at window.com.greensock.TweenLite and since it's a global class that should be available anywhere,
17574                          * it is ALSO referenced at window.TweenLite. However some classes aren't considered global, like the base com.greensock.core.Animation class, so
17575                          * those will only be at the package like window.com.greensock.core.Animation. Again, if you define a GreenSockGlobals object on the window, everything
17576                          * gets tucked neatly inside there instead of on the window directly. This allows you to do advanced things like load multiple versions of GreenSock
17577                          * files and put them into distinct objects (imagine a banner ad uses a newer version but the main site uses an older one). In that case, you could
17578                          * sandbox the banner one like:
17579                          *
17580                          * <script>
17581                          *     var gs = window.GreenSockGlobals = {}; //the newer version we're about to load could now be referenced in a "gs" object, like gs.TweenLite.to(...). Use whatever alias you want as long as it's unique, "gs" or "banner" or whatever.
17582                          * </script>
17583                          * <script src="js/greensock/v1.7/TweenMax.js"></script>
17584                          * <script>
17585                          *     window.GreenSockGlobals = null; //reset it back to null so that the next load of TweenMax affects the window and we can reference things directly like TweenLite.to(...)
17586                          * </script>
17587                          * <script src="js/greensock/v1.6/TweenMax.js"></script>
17588                          * <script>
17589                          *     gs.TweenLite.to(...); //would use v1.7
17590                          *     TweenLite.to(...); //would use v1.6
17591                          * </script>
17592                          *
17593                          * @param {!string} ns The namespace of the class definition, leaving off "com.greensock." as that's assumed. For example, "TweenLite" or "plugins.CSSPlugin" or "easing.Back".
17594                          * @param {!Array.<string>} dependencies An array of dependencies (described as their namespaces minus "com.greensock." prefix). For example ["TweenLite","plugins.TweenPlugin","core.Animation"]
17595                          * @param {!function():Object} func The function that should be called and passed the resolved dependencies which will return the actual class for this definition.
17596                          * @param {boolean=} global If true, the class will be added to the global scope (typically window unless you define a window.GreenSockGlobals object)
17597                          */
17598                         Definition = function(ns, dependencies, func, global) {
17599                                 this.sc = (_defLookup[ns]) ? _defLookup[ns].sc : []; //subclasses
17600                                 _defLookup[ns] = this;
17601                                 this.gsClass = null;
17602                                 this.func = func;
17603                                 var _classes = [];
17604                                 this.check = function(init) {
17605                                         var i = dependencies.length,
17606                                                 missing = i,
17607                                                 cur, a, n, cl;
17608                                         while (--i > -1) {
17609                                                 if ((cur = _defLookup[dependencies[i]] || new Definition(dependencies[i], [])).gsClass) {
17610                                                         _classes[i] = cur.gsClass;
17611                                                         missing--;
17612                                                 } else if (init) {
17613                                                         cur.sc.push(this);
17614                                                 }
17615                                         }
17616                                         if (missing === 0 && func) {
17617                                                 a = ("com.greensock." + ns).split(".");
17618                                                 n = a.pop();
17619                                                 cl = _namespace(a.join("."))[n] = this.gsClass = func.apply(func, _classes);
17620
17621                                                 //exports to multiple environments
17622                                                 if (global) {
17623                                                         _globals[n] = cl; //provides a way to avoid global namespace pollution. By default, the main classes like TweenLite, Power1, Strong, etc. are added to window unless a GreenSockGlobals is defined. So if you want to have things added to a custom object instead, just do something like window.GreenSockGlobals = {} before loading any GreenSock files. You can even set up an alias like window.GreenSockGlobals = windows.gs = {} so that you can access everything like gs.TweenLite. Also remember that ALL classes are added to the window.com.greensock object (in their respective packages, like com.greensock.easing.Power1, com.greensock.TweenLite, etc.)
17624                                                         if (typeof(define) === "function" && define.amd){ //AMD
17625                                                                 define((window.GreenSockAMDPath ? window.GreenSockAMDPath + "/" : "") + ns.split(".").join("/"), [], function() { return cl; });
17626                                                         } else if (typeof(module) !== "undefined" && module.exports){ //node
17627                                                                 module.exports = cl;
17628                                                         }
17629                                                 }
17630                                                 for (i = 0; i < this.sc.length; i++) {
17631                                                         this.sc[i].check();
17632                                                 }
17633                                         }
17634                                 };
17635                                 this.check(true);
17636                         },
17637
17638                         //used to create Definition instances (which basically registers a class that has dependencies).
17639                         _gsDefine = window._gsDefine = function(ns, dependencies, func, global) {
17640                                 return new Definition(ns, dependencies, func, global);
17641                         },
17642
17643                         //a quick way to create a class that doesn't have any dependencies. Returns the class, but first registers it in the GreenSock namespace so that other classes can grab it (other classes might be dependent on the class).
17644                         _class = gs._class = function(ns, func, global) {
17645                                 func = func || function() {};
17646                                 _gsDefine(ns, [], function(){ return func; }, global);
17647                                 return func;
17648                         };
17649
17650                 _gsDefine.globals = _globals;
17651
17652
17653
17654 /*
17655  * ----------------------------------------------------------------
17656  * Ease
17657  * ----------------------------------------------------------------
17658  */
17659                 var _baseParams = [0, 0, 1, 1],
17660                         _blankArray = [],
17661                         Ease = _class("easing.Ease", function(func, extraParams, type, power) {
17662                                 this._func = func;
17663                                 this._type = type || 0;
17664                                 this._power = power || 0;
17665                                 this._params = extraParams ? _baseParams.concat(extraParams) : _baseParams;
17666                         }, true),
17667                         _easeMap = Ease.map = {},
17668                         _easeReg = Ease.register = function(ease, names, types, create) {
17669                                 var na = names.split(","),
17670                                         i = na.length,
17671                                         ta = (types || "easeIn,easeOut,easeInOut").split(","),
17672                                         e, name, j, type;
17673                                 while (--i > -1) {
17674                                         name = na[i];
17675                                         e = create ? _class("easing."+name, null, true) : gs.easing[name] || {};
17676                                         j = ta.length;
17677                                         while (--j > -1) {
17678                                                 type = ta[j];
17679                                                 _easeMap[name + "." + type] = _easeMap[type + name] = e[type] = ease.getRatio ? ease : ease[type] || new ease();
17680                                         }
17681                                 }
17682                         };
17683
17684                 p = Ease.prototype;
17685                 p._calcEnd = false;
17686                 p.getRatio = function(p) {
17687                         if (this._func) {
17688                                 this._params[0] = p;
17689                                 return this._func.apply(null, this._params);
17690                         }
17691                         var t = this._type,
17692                                 pw = this._power,
17693                                 r = (t === 1) ? 1 - p : (t === 2) ? p : (p < 0.5) ? p * 2 : (1 - p) * 2;
17694                         if (pw === 1) {
17695                                 r *= r;
17696                         } else if (pw === 2) {
17697                                 r *= r * r;
17698                         } else if (pw === 3) {
17699                                 r *= r * r * r;
17700                         } else if (pw === 4) {
17701                                 r *= r * r * r * r;
17702                         }
17703                         return (t === 1) ? 1 - r : (t === 2) ? r : (p < 0.5) ? r / 2 : 1 - (r / 2);
17704                 };
17705
17706                 //create all the standard eases like Linear, Quad, Cubic, Quart, Quint, Strong, Power0, Power1, Power2, Power3, and Power4 (each with easeIn, easeOut, and easeInOut)
17707                 a = ["Linear","Quad","Cubic","Quart","Quint,Strong"];
17708                 i = a.length;
17709                 while (--i > -1) {
17710                         p = a[i]+",Power"+i;
17711                         _easeReg(new Ease(null,null,1,i), p, "easeOut", true);
17712                         _easeReg(new Ease(null,null,2,i), p, "easeIn" + ((i === 0) ? ",easeNone" : ""));
17713                         _easeReg(new Ease(null,null,3,i), p, "easeInOut");
17714                 }
17715                 _easeMap.linear = gs.easing.Linear.easeIn;
17716                 _easeMap.swing = gs.easing.Quad.easeInOut; //for jQuery folks
17717
17718
17719 /*
17720  * ----------------------------------------------------------------
17721  * EventDispatcher
17722  * ----------------------------------------------------------------
17723  */
17724                 var EventDispatcher = _class("events.EventDispatcher", function(target) {
17725                         this._listeners = {};
17726                         this._eventTarget = target || this;
17727                 });
17728                 p = EventDispatcher.prototype;
17729
17730                 p.addEventListener = function(type, callback, scope, useParam, priority) {
17731                         priority = priority || 0;
17732                         var list = this._listeners[type],
17733                                 index = 0,
17734                                 listener, i;
17735                         if (list == null) {
17736                                 this._listeners[type] = list = [];
17737                         }
17738                         i = list.length;
17739                         while (--i > -1) {
17740                                 listener = list[i];
17741                                 if (listener.c === callback && listener.s === scope) {
17742                                         list.splice(i, 1);
17743                                 } else if (index === 0 && listener.pr < priority) {
17744                                         index = i + 1;
17745                                 }
17746                         }
17747                         list.splice(index, 0, {c:callback, s:scope, up:useParam, pr:priority});
17748                         if (this === _ticker && !_tickerActive) {
17749                                 _ticker.wake();
17750                         }
17751                 };
17752
17753                 p.removeEventListener = function(type, callback) {
17754                         var list = this._listeners[type], i;
17755                         if (list) {
17756                                 i = list.length;
17757                                 while (--i > -1) {
17758                                         if (list[i].c === callback) {
17759                                                 list.splice(i, 1);
17760                                                 return;
17761                                         }
17762                                 }
17763                         }
17764                 };
17765
17766                 p.dispatchEvent = function(type) {
17767                         var list = this._listeners[type],
17768                                 i, t, listener;
17769                         if (list) {
17770                                 i = list.length;
17771                                 t = this._eventTarget;
17772                                 while (--i > -1) {
17773                                         listener = list[i];
17774                                         if (listener.up) {
17775                                                 listener.c.call(listener.s || t, {type:type, target:t});
17776                                         } else {
17777                                                 listener.c.call(listener.s || t);
17778                                         }
17779                                 }
17780                         }
17781                 };
17782
17783
17784 /*
17785  * ----------------------------------------------------------------
17786  * Ticker
17787  * ----------------------------------------------------------------
17788  */
17789                 var _reqAnimFrame = window.requestAnimationFrame,
17790                         _cancelAnimFrame = window.cancelAnimationFrame,
17791                         _getTime = Date.now || function() {return new Date().getTime();},
17792                         _lastUpdate = _getTime();
17793
17794                 //now try to determine the requestAnimationFrame and cancelAnimationFrame functions and if none are found, we'll use a setTimeout()/clearTimeout() polyfill.
17795                 a = ["ms","moz","webkit","o"];
17796                 i = a.length;
17797                 while (--i > -1 && !_reqAnimFrame) {
17798                         _reqAnimFrame = window[a[i] + "RequestAnimationFrame"];
17799                         _cancelAnimFrame = window[a[i] + "CancelAnimationFrame"] || window[a[i] + "CancelRequestAnimationFrame"];
17800                 }
17801
17802                 _class("Ticker", function(fps, useRAF) {
17803                         var _self = this,
17804                                 _startTime = _getTime(),
17805                                 _useRAF = (useRAF !== false && _reqAnimFrame),
17806                                 _lagThreshold = 500,
17807                                 _adjustedLag = 33,
17808                                 _fps, _req, _id, _gap, _nextTime,
17809                                 _tick = function(manual) {
17810                                         var elapsed = _getTime() - _lastUpdate,
17811                                                 overlap, dispatch;
17812                                         if (elapsed > _lagThreshold) {
17813                                                 _startTime += elapsed - _adjustedLag;
17814                                         }
17815                                         _lastUpdate += elapsed;
17816                                         _self.time = (_lastUpdate - _startTime) / 1000;
17817                                         overlap = _self.time - _nextTime;
17818                                         if (!_fps || overlap > 0 || manual === true) {
17819                                                 _self.frame++;
17820                                                 _nextTime += overlap + (overlap >= _gap ? 0.004 : _gap - overlap);
17821                                                 dispatch = true;
17822                                         }
17823                                         if (manual !== true) { //make sure the request is made before we dispatch the "tick" event so that timing is maintained. Otherwise, if processing the "tick" requires a bunch of time (like 15ms) and we're using a setTimeout() that's based on 16.7ms, it'd technically take 31.7ms between frames otherwise.
17824                                                 _id = _req(_tick);
17825                                         }
17826                                         if (dispatch) {
17827                                                 _self.dispatchEvent("tick");
17828                                         }
17829                                 };
17830
17831                         EventDispatcher.call(_self);
17832                         _self.time = _self.frame = 0;
17833                         _self.tick = function() {
17834                                 _tick(true);
17835                         };
17836
17837                         _self.lagSmoothing = function(threshold, adjustedLag) {
17838                                 _lagThreshold = threshold || (1 / _tinyNum); //zero should be interpreted as basically unlimited
17839                                 _adjustedLag = Math.min(adjustedLag, _lagThreshold, 0);
17840                         };
17841
17842                         _self.sleep = function() {
17843                                 if (_id == null) {
17844                                         return;
17845                                 }
17846                                 if (!_useRAF || !_cancelAnimFrame) {
17847                                         clearTimeout(_id);
17848                                 } else {
17849                                         _cancelAnimFrame(_id);
17850                                 }
17851                                 _req = _emptyFunc;
17852                                 _id = null;
17853                                 if (_self === _ticker) {
17854                                         _tickerActive = false;
17855                                 }
17856                         };
17857
17858                         _self.wake = function() {
17859                                 if (_id !== null) {
17860                                         _self.sleep();
17861                                 } else if (_self.frame > 10) { //don't trigger lagSmoothing if we're just waking up, and make sure that at least 10 frames have elapsed because of the iOS bug that we work around below with the 1.5-second setTimout().
17862                                         _lastUpdate = _getTime() - _lagThreshold + 5;
17863                                 }
17864                                 _req = (_fps === 0) ? _emptyFunc : (!_useRAF || !_reqAnimFrame) ? function(f) { return setTimeout(f, ((_nextTime - _self.time) * 1000 + 1) | 0); } : _reqAnimFrame;
17865                                 if (_self === _ticker) {
17866                                         _tickerActive = true;
17867                                 }
17868                                 _tick(2);
17869                         };
17870
17871                         _self.fps = function(value) {
17872                                 if (!arguments.length) {
17873                                         return _fps;
17874                                 }
17875                                 _fps = value;
17876                                 _gap = 1 / (_fps || 60);
17877                                 _nextTime = this.time + _gap;
17878                                 _self.wake();
17879                         };
17880
17881                         _self.useRAF = function(value) {
17882                                 if (!arguments.length) {
17883                                         return _useRAF;
17884                                 }
17885                                 _self.sleep();
17886                                 _useRAF = value;
17887                                 _self.fps(_fps);
17888                         };
17889                         _self.fps(fps);
17890
17891                         //a bug in iOS 6 Safari occasionally prevents the requestAnimationFrame from working initially, so we use a 1.5-second timeout that automatically falls back to setTimeout() if it senses this condition.
17892                         setTimeout(function() {
17893                                 if (_useRAF && (!_id || _self.frame < 5)) {
17894                                         _self.useRAF(false);
17895                                 }
17896                         }, 1500);
17897                 });
17898
17899                 p = gs.Ticker.prototype = new gs.events.EventDispatcher();
17900                 p.constructor = gs.Ticker;
17901
17902
17903 /*
17904  * ----------------------------------------------------------------
17905  * Animation
17906  * ----------------------------------------------------------------
17907  */
17908                 var Animation = _class("core.Animation", function(duration, vars) {
17909                                 this.vars = vars = vars || {};
17910                                 this._duration = this._totalDuration = duration || 0;
17911                                 this._delay = Number(vars.delay) || 0;
17912                                 this._timeScale = 1;
17913                                 this._active = (vars.immediateRender === true);
17914                                 this.data = vars.data;
17915                                 this._reversed = (vars.reversed === true);
17916
17917                                 if (!_rootTimeline) {
17918                                         return;
17919                                 }
17920                                 if (!_tickerActive) { //some browsers (like iOS 6 Safari) shut down JavaScript execution when the tab is disabled and they [occasionally] neglect to start up requestAnimationFrame again when returning - this code ensures that the engine starts up again properly.
17921                                         _ticker.wake();
17922                                 }
17923
17924                                 var tl = this.vars.useFrames ? _rootFramesTimeline : _rootTimeline;
17925                                 tl.add(this, tl._time);
17926
17927                                 if (this.vars.paused) {
17928                                         this.paused(true);
17929                                 }
17930                         });
17931
17932                 _ticker = Animation.ticker = new gs.Ticker();
17933                 p = Animation.prototype;
17934                 p._dirty = p._gc = p._initted = p._paused = false;
17935                 p._totalTime = p._time = 0;
17936                 p._rawPrevTime = -1;
17937                 p._next = p._last = p._onUpdate = p._timeline = p.timeline = null;
17938                 p._paused = false;
17939
17940
17941                 //some browsers (like iOS) occasionally drop the requestAnimationFrame event when the user switches to a different tab and then comes back again, so we use a 2-second setTimeout() to sense if/when that condition occurs and then wake() the ticker.
17942                 var _checkTimeout = function() {
17943                                 if (_tickerActive && _getTime() - _lastUpdate > 2000) {
17944                                         _ticker.wake();
17945                                 }
17946                                 setTimeout(_checkTimeout, 2000);
17947                         };
17948                 _checkTimeout();
17949
17950
17951                 p.play = function(from, suppressEvents) {
17952                         if (from != null) {
17953                                 this.seek(from, suppressEvents);
17954                         }
17955                         return this.reversed(false).paused(false);
17956                 };
17957
17958                 p.pause = function(atTime, suppressEvents) {
17959                         if (atTime != null) {
17960                                 this.seek(atTime, suppressEvents);
17961                         }
17962                         return this.paused(true);
17963                 };
17964
17965                 p.resume = function(from, suppressEvents) {
17966                         if (from != null) {
17967                                 this.seek(from, suppressEvents);
17968                         }
17969                         return this.paused(false);
17970                 };
17971
17972                 p.seek = function(time, suppressEvents) {
17973                         return this.totalTime(Number(time), suppressEvents !== false);
17974                 };
17975
17976                 p.restart = function(includeDelay, suppressEvents) {
17977                         return this.reversed(false).paused(false).totalTime(includeDelay ? -this._delay : 0, (suppressEvents !== false), true);
17978                 };
17979
17980                 p.reverse = function(from, suppressEvents) {
17981                         if (from != null) {
17982                                 this.seek((from || this.totalDuration()), suppressEvents);
17983                         }
17984                         return this.reversed(true).paused(false);
17985                 };
17986
17987                 p.render = function(time, suppressEvents, force) {
17988                         //stub - we override this method in subclasses.
17989                 };
17990
17991                 p.invalidate = function() {
17992                         return this;
17993                 };
17994
17995                 p.isActive = function() {
17996                         var tl = this._timeline, //the 2 root timelines won't have a _timeline; they're always active.
17997                                 startTime = this._startTime,
17998                                 rawTime;
17999                         return (!tl || (!this._gc && !this._paused && tl.isActive() && (rawTime = tl.rawTime()) >= startTime && rawTime < startTime + this.totalDuration() / this._timeScale));
18000                 };
18001
18002                 p._enabled = function (enabled, ignoreTimeline) {
18003                         if (!_tickerActive) {
18004                                 _ticker.wake();
18005                         }
18006                         this._gc = !enabled;
18007                         this._active = this.isActive();
18008                         if (ignoreTimeline !== true) {
18009                                 if (enabled && !this.timeline) {
18010                                         this._timeline.add(this, this._startTime - this._delay);
18011                                 } else if (!enabled && this.timeline) {
18012                                         this._timeline._remove(this, true);
18013                                 }
18014                         }
18015                         return false;
18016                 };
18017
18018
18019                 p._kill = function(vars, target) {
18020                         return this._enabled(false, false);
18021                 };
18022
18023                 p.kill = function(vars, target) {
18024                         this._kill(vars, target);
18025                         return this;
18026                 };
18027
18028                 p._uncache = function(includeSelf) {
18029                         var tween = includeSelf ? this : this.timeline;
18030                         while (tween) {
18031                                 tween._dirty = true;
18032                                 tween = tween.timeline;
18033                         }
18034                         return this;
18035                 };
18036
18037                 p._swapSelfInParams = function(params) {
18038                         var i = params.length,
18039                                 copy = params.concat();
18040                         while (--i > -1) {
18041                                 if (params[i] === "{self}") {
18042                                         copy[i] = this;
18043                                 }
18044                         }
18045                         return copy;
18046                 };
18047
18048 //----Animation getters/setters --------------------------------------------------------
18049
18050                 p.eventCallback = function(type, callback, params, scope) {
18051                         if ((type || "").substr(0,2) === "on") {
18052                                 var v = this.vars;
18053                                 if (arguments.length === 1) {
18054                                         return v[type];
18055                                 }
18056                                 if (callback == null) {
18057                                         delete v[type];
18058                                 } else {
18059                                         v[type] = callback;
18060                                         v[type + "Params"] = (_isArray(params) && params.join("").indexOf("{self}") !== -1) ? this._swapSelfInParams(params) : params;
18061                                         v[type + "Scope"] = scope;
18062                                 }
18063                                 if (type === "onUpdate") {
18064                                         this._onUpdate = callback;
18065                                 }
18066                         }
18067                         return this;
18068                 };
18069
18070                 p.delay = function(value) {
18071                         if (!arguments.length) {
18072                                 return this._delay;
18073                         }
18074                         if (this._timeline.smoothChildTiming) {
18075                                 this.startTime( this._startTime + value - this._delay );
18076                         }
18077                         this._delay = value;
18078                         return this;
18079                 };
18080
18081                 p.duration = function(value) {
18082                         if (!arguments.length) {
18083                                 this._dirty = false;
18084                                 return this._duration;
18085                         }
18086                         this._duration = this._totalDuration = value;
18087                         this._uncache(true); //true in case it's a TweenMax or TimelineMax that has a repeat - we'll need to refresh the totalDuration.
18088                         if (this._timeline.smoothChildTiming) if (this._time > 0) if (this._time < this._duration) if (value !== 0) {
18089                                 this.totalTime(this._totalTime * (value / this._duration), true);
18090                         }
18091                         return this;
18092                 };
18093
18094                 p.totalDuration = function(value) {
18095                         this._dirty = false;
18096                         return (!arguments.length) ? this._totalDuration : this.duration(value);
18097                 };
18098
18099                 p.time = function(value, suppressEvents) {
18100                         if (!arguments.length) {
18101                                 return this._time;
18102                         }
18103                         if (this._dirty) {
18104                                 this.totalDuration();
18105                         }
18106                         return this.totalTime((value > this._duration) ? this._duration : value, suppressEvents);
18107                 };
18108
18109                 p.totalTime = function(time, suppressEvents, uncapped) {
18110                         if (!_tickerActive) {
18111                                 _ticker.wake();
18112                         }
18113                         if (!arguments.length) {
18114                                 return this._totalTime;
18115                         }
18116                         if (this._timeline) {
18117                                 if (time < 0 && !uncapped) {
18118                                         time += this.totalDuration();
18119                                 }
18120                                 if (this._timeline.smoothChildTiming) {
18121                                         if (this._dirty) {
18122                                                 this.totalDuration();
18123                                         }
18124                                         var totalDuration = this._totalDuration,
18125                                                 tl = this._timeline;
18126                                         if (time > totalDuration && !uncapped) {
18127                                                 time = totalDuration;
18128                                         }
18129                                         this._startTime = (this._paused ? this._pauseTime : tl._time) - ((!this._reversed ? time : totalDuration - time) / this._timeScale);
18130                                         if (!tl._dirty) { //for performance improvement. If the parent's cache is already dirty, it already took care of marking the ancestors as dirty too, so skip the function call here.
18131                                                 this._uncache(false);
18132                                         }
18133                                         //in case any of the ancestor timelines had completed but should now be enabled, we should reset their totalTime() which will also ensure that they're lined up properly and enabled. Skip for animations that are on the root (wasteful). Example: a TimelineLite.exportRoot() is performed when there's a paused tween on the root, the export will not complete until that tween is unpaused, but imagine a child gets restarted later, after all [unpaused] tweens have completed. The startTime of that child would get pushed out, but one of the ancestors may have completed.
18134                                         if (tl._timeline) {
18135                                                 while (tl._timeline) {
18136                                                         if (tl._timeline._time !== (tl._startTime + tl._totalTime) / tl._timeScale) {
18137                                                                 tl.totalTime(tl._totalTime, true);
18138                                                         }
18139                                                         tl = tl._timeline;
18140                                                 }
18141                                         }
18142                                 }
18143                                 if (this._gc) {
18144                                         this._enabled(true, false);
18145                                 }
18146                                 if (this._totalTime !== time || this._duration === 0) {
18147                                         this.render(time, suppressEvents, false);
18148                                         if (_lazyTweens.length) { //in case rendering caused any tweens to lazy-init, we should render them because typically when someone calls seek() or time() or progress(), they expect an immediate render.
18149                                                 _lazyRender();
18150                                         }
18151                                 }
18152                         }
18153                         return this;
18154                 };
18155
18156                 p.progress = p.totalProgress = function(value, suppressEvents) {
18157                         return (!arguments.length) ? this._time / this.duration() : this.totalTime(this.duration() * value, suppressEvents);
18158                 };
18159
18160                 p.startTime = function(value) {
18161                         if (!arguments.length) {
18162                                 return this._startTime;
18163                         }
18164                         if (value !== this._startTime) {
18165                                 this._startTime = value;
18166                                 if (this.timeline) if (this.timeline._sortChildren) {
18167                                         this.timeline.add(this, value - this._delay); //ensures that any necessary re-sequencing of Animations in the timeline occurs to make sure the rendering order is correct.
18168                                 }
18169                         }
18170                         return this;
18171                 };
18172
18173                 p.timeScale = function(value) {
18174                         if (!arguments.length) {
18175                                 return this._timeScale;
18176                         }
18177                         value = value || _tinyNum; //can't allow zero because it'll throw the math off
18178                         if (this._timeline && this._timeline.smoothChildTiming) {
18179                                 var pauseTime = this._pauseTime,
18180                                         t = (pauseTime || pauseTime === 0) ? pauseTime : this._timeline.totalTime();
18181                                 this._startTime = t - ((t - this._startTime) * this._timeScale / value);
18182                         }
18183                         this._timeScale = value;
18184                         return this._uncache(false);
18185                 };
18186
18187                 p.reversed = function(value) {
18188                         if (!arguments.length) {
18189                                 return this._reversed;
18190                         }
18191                         if (value != this._reversed) {
18192                                 this._reversed = value;
18193                                 this.totalTime(((this._timeline && !this._timeline.smoothChildTiming) ? this.totalDuration() - this._totalTime : this._totalTime), true);
18194                         }
18195                         return this;
18196                 };
18197
18198                 p.paused = function(value) {
18199                         if (!arguments.length) {
18200                                 return this._paused;
18201                         }
18202                         if (value != this._paused) if (this._timeline) {
18203                                 if (!_tickerActive && !value) {
18204                                         _ticker.wake();
18205                                 }
18206                                 var tl = this._timeline,
18207                                         raw = tl.rawTime(),
18208                                         elapsed = raw - this._pauseTime;
18209                                 if (!value && tl.smoothChildTiming) {
18210                                         this._startTime += elapsed;
18211                                         this._uncache(false);
18212                                 }
18213                                 this._pauseTime = value ? raw : null;
18214                                 this._paused = value;
18215                                 this._active = this.isActive();
18216                                 if (!value && elapsed !== 0 && this._initted && this.duration()) {
18217                                         this.render((tl.smoothChildTiming ? this._totalTime : (raw - this._startTime) / this._timeScale), true, true); //in case the target's properties changed via some other tween or manual update by the user, we should force a render.
18218                                 }
18219                         }
18220                         if (this._gc && !value) {
18221                                 this._enabled(true, false);
18222                         }
18223                         return this;
18224                 };
18225
18226
18227 /*
18228  * ----------------------------------------------------------------
18229  * SimpleTimeline
18230  * ----------------------------------------------------------------
18231  */
18232                 var SimpleTimeline = _class("core.SimpleTimeline", function(vars) {
18233                         Animation.call(this, 0, vars);
18234                         this.autoRemoveChildren = this.smoothChildTiming = true;
18235                 });
18236
18237                 p = SimpleTimeline.prototype = new Animation();
18238                 p.constructor = SimpleTimeline;
18239                 p.kill()._gc = false;
18240                 p._first = p._last = null;
18241                 p._sortChildren = false;
18242
18243                 p.add = p.insert = function(child, position, align, stagger) {
18244                         var prevTween, st;
18245                         child._startTime = Number(position || 0) + child._delay;
18246                         if (child._paused) if (this !== child._timeline) { //we only adjust the _pauseTime if it wasn't in this timeline already. Remember, sometimes a tween will be inserted again into the same timeline when its startTime is changed so that the tweens in the TimelineLite/Max are re-ordered properly in the linked list (so everything renders in the proper order).
18247                                 child._pauseTime = child._startTime + ((this.rawTime() - child._startTime) / child._timeScale);
18248                         }
18249                         if (child.timeline) {
18250                                 child.timeline._remove(child, true); //removes from existing timeline so that it can be properly added to this one.
18251                         }
18252                         child.timeline = child._timeline = this;
18253                         if (child._gc) {
18254                                 child._enabled(true, true);
18255                         }
18256                         prevTween = this._last;
18257                         if (this._sortChildren) {
18258                                 st = child._startTime;
18259                                 while (prevTween && prevTween._startTime > st) {
18260                                         prevTween = prevTween._prev;
18261                                 }
18262                         }
18263                         if (prevTween) {
18264                                 child._next = prevTween._next;
18265                                 prevTween._next = child;
18266                         } else {
18267                                 child._next = this._first;
18268                                 this._first = child;
18269                         }
18270                         if (child._next) {
18271                                 child._next._prev = child;
18272                         } else {
18273                                 this._last = child;
18274                         }
18275                         child._prev = prevTween;
18276                         if (this._timeline) {
18277                                 this._uncache(true);
18278                         }
18279                         return this;
18280                 };
18281
18282                 p._remove = function(tween, skipDisable) {
18283                         if (tween.timeline === this) {
18284                                 if (!skipDisable) {
18285                                         tween._enabled(false, true);
18286                                 }
18287                                 tween.timeline = null;
18288
18289                                 if (tween._prev) {
18290                                         tween._prev._next = tween._next;
18291                                 } else if (this._first === tween) {
18292                                         this._first = tween._next;
18293                                 }
18294                                 if (tween._next) {
18295                                         tween._next._prev = tween._prev;
18296                                 } else if (this._last === tween) {
18297                                         this._last = tween._prev;
18298                                 }
18299
18300                                 if (this._timeline) {
18301                                         this._uncache(true);
18302                                 }
18303                         }
18304                         return this;
18305                 };
18306
18307                 p.render = function(time, suppressEvents, force) {
18308                         var tween = this._first,
18309                                 next;
18310                         this._totalTime = this._time = this._rawPrevTime = time;
18311                         while (tween) {
18312                                 next = tween._next; //record it here because the value could change after rendering...
18313                                 if (tween._active || (time >= tween._startTime && !tween._paused)) {
18314                                         if (!tween._reversed) {
18315                                                 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
18316                                         } else {
18317                                                 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
18318                                         }
18319                                 }
18320                                 tween = next;
18321                         }
18322                 };
18323
18324                 p.rawTime = function() {
18325                         if (!_tickerActive) {
18326                                 _ticker.wake();
18327                         }
18328                         return this._totalTime;
18329                 };
18330
18331 /*
18332  * ----------------------------------------------------------------
18333  * TweenLite
18334  * ----------------------------------------------------------------
18335  */
18336                 var TweenLite = _class("TweenLite", function(target, duration, vars) {
18337                                 Animation.call(this, duration, vars);
18338                                 this.render = TweenLite.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method)
18339
18340                                 if (target == null) {
18341                                         throw "Cannot tween a null target.";
18342                                 }
18343
18344                                 this.target = target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;
18345
18346                                 var isSelector = (target.jquery || (target.length && target !== window && target[0] && (target[0] === window || (target[0].nodeType && target[0].style && !target.nodeType)))),
18347                                         overwrite = this.vars.overwrite,
18348                                         i, targ, targets;
18349
18350                                 this._overwrite = overwrite = (overwrite == null) ? _overwriteLookup[TweenLite.defaultOverwrite] : (typeof(overwrite) === "number") ? overwrite >> 0 : _overwriteLookup[overwrite];
18351
18352                                 if ((isSelector || target instanceof Array || (target.push && _isArray(target))) && typeof(target[0]) !== "number") {
18353                                         this._targets = targets = _slice.call(target, 0);
18354                                         this._propLookup = [];
18355                                         this._siblings = [];
18356                                         for (i = 0; i < targets.length; i++) {
18357                                                 targ = targets[i];
18358                                                 if (!targ) {
18359                                                         targets.splice(i--, 1);
18360                                                         continue;
18361                                                 } else if (typeof(targ) === "string") {
18362                                                         targ = targets[i--] = TweenLite.selector(targ); //in case it's an array of strings
18363                                                         if (typeof(targ) === "string") {
18364                                                                 targets.splice(i+1, 1); //to avoid an endless loop (can't imagine why the selector would return a string, but just in case)
18365                                                         }
18366                                                         continue;
18367                                                 } else if (targ.length && targ !== window && targ[0] && (targ[0] === window || (targ[0].nodeType && targ[0].style && !targ.nodeType))) { //in case the user is passing in an array of selector objects (like jQuery objects), we need to check one more level and pull things out if necessary. Also note that <select> elements pass all the criteria regarding length and the first child having style, so we must also check to ensure the target isn't an HTML node itself.
18368                                                         targets.splice(i--, 1);
18369                                                         this._targets = targets = targets.concat(_slice.call(targ, 0));
18370                                                         continue;
18371                                                 }
18372                                                 this._siblings[i] = _register(targ, this, false);
18373                                                 if (overwrite === 1) if (this._siblings[i].length > 1) {
18374                                                         _applyOverwrite(targ, this, null, 1, this._siblings[i]);
18375                                                 }
18376                                         }
18377
18378                                 } else {
18379                                         this._propLookup = {};
18380                                         this._siblings = _register(target, this, false);
18381                                         if (overwrite === 1) if (this._siblings.length > 1) {
18382                                                 _applyOverwrite(target, this, null, 1, this._siblings);
18383                                         }
18384                                 }
18385                                 if (this.vars.immediateRender || (duration === 0 && this._delay === 0 && this.vars.immediateRender !== false)) {
18386                                         this._time = -_tinyNum; //forces a render without having to set the render() "force" parameter to true because we want to allow lazying by default (using the "force" parameter always forces an immediate full render)
18387                                         this.render(-this._delay);
18388                                 }
18389                         }, true),
18390                         _isSelector = function(v) {
18391                                 return (v.length && v !== window && v[0] && (v[0] === window || (v[0].nodeType && v[0].style && !v.nodeType))); //we cannot check "nodeType" if the target is window from within an iframe, otherwise it will trigger a security error in some browsers like Firefox.
18392                         },
18393                         _autoCSS = function(vars, target) {
18394                                 var css = {},
18395                                         p;
18396                                 for (p in vars) {
18397                                         if (!_reservedProps[p] && (!(p in target) || p === "transform" || p === "x" || p === "y" || p === "width" || p === "height" || p === "className" || p === "border") && (!_plugins[p] || (_plugins[p] && _plugins[p]._autoCSS))) { //note: <img> elements contain read-only "x" and "y" properties. We should also prioritize editing css width/height rather than the element's properties.
18398                                                 css[p] = vars[p];
18399                                                 delete vars[p];
18400                                         }
18401                                 }
18402                                 vars.css = css;
18403                         };
18404
18405                 p = TweenLite.prototype = new Animation();
18406                 p.constructor = TweenLite;
18407                 p.kill()._gc = false;
18408
18409 //----TweenLite defaults, overwrite management, and root updates ----------------------------------------------------
18410
18411                 p.ratio = 0;
18412                 p._firstPT = p._targets = p._overwrittenProps = p._startAt = null;
18413                 p._notifyPluginsOfEnabled = p._lazy = false;
18414
18415                 TweenLite.version = "1.12.1";
18416                 TweenLite.defaultEase = p._ease = new Ease(null, null, 1, 1);
18417                 TweenLite.defaultOverwrite = "auto";
18418                 TweenLite.ticker = _ticker;
18419                 TweenLite.autoSleep = true;
18420                 TweenLite.lagSmoothing = function(threshold, adjustedLag) {
18421                         _ticker.lagSmoothing(threshold, adjustedLag);
18422                 };
18423                 TweenLite.selector = window.$ || window.jQuery || function(e) { if (window.$) { TweenLite.selector = window.$; return window.$(e); } return window.document ? window.document.getElementById((e.charAt(0) === "#") ? e.substr(1) : e) : e; };
18424
18425                 var _lazyTweens = [],
18426                         _lazyLookup = {},
18427                         _internals = TweenLite._internals = {isArray:_isArray, isSelector:_isSelector, lazyTweens:_lazyTweens}, //gives us a way to expose certain private values to other GreenSock classes without contaminating tha main TweenLite object.
18428                         _plugins = TweenLite._plugins = {},
18429                         _tweenLookup = _internals.tweenLookup = {},
18430                         _tweenLookupNum = 0,
18431                         _reservedProps = _internals.reservedProps = {ease:1, delay:1, overwrite:1, onComplete:1, onCompleteParams:1, onCompleteScope:1, useFrames:1, runBackwards:1, startAt:1, onUpdate:1, onUpdateParams:1, onUpdateScope:1, onStart:1, onStartParams:1, onStartScope:1, onReverseComplete:1, onReverseCompleteParams:1, onReverseCompleteScope:1, onRepeat:1, onRepeatParams:1, onRepeatScope:1, easeParams:1, yoyo:1, immediateRender:1, repeat:1, repeatDelay:1, data:1, paused:1, reversed:1, autoCSS:1, lazy:1},
18432                         _overwriteLookup = {none:0, all:1, auto:2, concurrent:3, allOnStart:4, preexisting:5, "true":1, "false":0},
18433                         _rootFramesTimeline = Animation._rootFramesTimeline = new SimpleTimeline(),
18434                         _rootTimeline = Animation._rootTimeline = new SimpleTimeline(),
18435                         _lazyRender = function() {
18436                                 var i = _lazyTweens.length;
18437                                 _lazyLookup = {};
18438                                 while (--i > -1) {
18439                                         a = _lazyTweens[i];
18440                                         if (a && a._lazy !== false) {
18441                                                 a.render(a._lazy, false, true);
18442                                                 a._lazy = false;
18443                                         }
18444                                 }
18445                                 _lazyTweens.length = 0;
18446                         };
18447
18448                 _rootTimeline._startTime = _ticker.time;
18449                 _rootFramesTimeline._startTime = _ticker.frame;
18450                 _rootTimeline._active = _rootFramesTimeline._active = true;
18451                 setTimeout(_lazyRender, 1); //on some mobile devices, there isn't a "tick" before code runs which means any lazy renders wouldn't run before the next official "tick".
18452
18453                 Animation._updateRoot = TweenLite.render = function() {
18454                                 var i, a, p;
18455                                 if (_lazyTweens.length) { //if code is run outside of the requestAnimationFrame loop, there may be tweens queued AFTER the engine refreshed, so we need to ensure any pending renders occur before we refresh again.
18456                                         _lazyRender();
18457                                 }
18458                                 _rootTimeline.render((_ticker.time - _rootTimeline._startTime) * _rootTimeline._timeScale, false, false);
18459                                 _rootFramesTimeline.render((_ticker.frame - _rootFramesTimeline._startTime) * _rootFramesTimeline._timeScale, false, false);
18460                                 if (_lazyTweens.length) {
18461                                         _lazyRender();
18462                                 }
18463                                 if (!(_ticker.frame % 120)) { //dump garbage every 120 frames...
18464                                         for (p in _tweenLookup) {
18465                                                 a = _tweenLookup[p].tweens;
18466                                                 i = a.length;
18467                                                 while (--i > -1) {
18468                                                         if (a[i]._gc) {
18469                                                                 a.splice(i, 1);
18470                                                         }
18471                                                 }
18472                                                 if (a.length === 0) {
18473                                                         delete _tweenLookup[p];
18474                                                 }
18475                                         }
18476                                         //if there are no more tweens in the root timelines, or if they're all paused, make the _timer sleep to reduce load on the CPU slightly
18477                                         p = _rootTimeline._first;
18478                                         if (!p || p._paused) if (TweenLite.autoSleep && !_rootFramesTimeline._first && _ticker._listeners.tick.length === 1) {
18479                                                 while (p && p._paused) {
18480                                                         p = p._next;
18481                                                 }
18482                                                 if (!p) {
18483                                                         _ticker.sleep();
18484                                                 }
18485                                         }
18486                                 }
18487                         };
18488
18489                 _ticker.addEventListener("tick", Animation._updateRoot);
18490
18491                 var _register = function(target, tween, scrub) {
18492                                 var id = target._gsTweenID, a, i;
18493                                 if (!_tweenLookup[id || (target._gsTweenID = id = "t" + (_tweenLookupNum++))]) {
18494                                         _tweenLookup[id] = {target:target, tweens:[]};
18495                                 }
18496                                 if (tween) {
18497                                         a = _tweenLookup[id].tweens;
18498                                         a[(i = a.length)] = tween;
18499                                         if (scrub) {
18500                                                 while (--i > -1) {
18501                                                         if (a[i] === tween) {
18502                                                                 a.splice(i, 1);
18503                                                         }
18504                                                 }
18505                                         }
18506                                 }
18507                                 return _tweenLookup[id].tweens;
18508                         },
18509
18510                         _applyOverwrite = function(target, tween, props, mode, siblings) {
18511                                 var i, changed, curTween, l;
18512                                 if (mode === 1 || mode >= 4) {
18513                                         l = siblings.length;
18514                                         for (i = 0; i < l; i++) {
18515                                                 if ((curTween = siblings[i]) !== tween) {
18516                                                         if (!curTween._gc) if (curTween._enabled(false, false)) {
18517                                                                 changed = true;
18518                                                         }
18519                                                 } else if (mode === 5) {
18520                                                         break;
18521                                                 }
18522                                         }
18523                                         return changed;
18524                                 }
18525                                 //NOTE: Add 0.0000000001 to overcome floating point errors that can cause the startTime to be VERY slightly off (when a tween's time() is set for example)
18526                                 var startTime = tween._startTime + _tinyNum,
18527                                         overlaps = [],
18528                                         oCount = 0,
18529                                         zeroDur = (tween._duration === 0),
18530                                         globalStart;
18531                                 i = siblings.length;
18532                                 while (--i > -1) {
18533                                         if ((curTween = siblings[i]) === tween || curTween._gc || curTween._paused) {
18534                                                 //ignore
18535                                         } else if (curTween._timeline !== tween._timeline) {
18536                                                 globalStart = globalStart || _checkOverlap(tween, 0, zeroDur);
18537                                                 if (_checkOverlap(curTween, globalStart, zeroDur) === 0) {
18538                                                         overlaps[oCount++] = curTween;
18539                                                 }
18540                                         } else if (curTween._startTime <= startTime) if (curTween._startTime + curTween.totalDuration() / curTween._timeScale > startTime) if (!((zeroDur || !curTween._initted) && startTime - curTween._startTime <= 0.0000000002)) {
18541                                                 overlaps[oCount++] = curTween;
18542                                         }
18543                                 }
18544
18545                                 i = oCount;
18546                                 while (--i > -1) {
18547                                         curTween = overlaps[i];
18548                                         if (mode === 2) if (curTween._kill(props, target)) {
18549                                                 changed = true;
18550                                         }
18551                                         if (mode !== 2 || (!curTween._firstPT && curTween._initted)) {
18552                                                 if (curTween._enabled(false, false)) { //if all property tweens have been overwritten, kill the tween.
18553                                                         changed = true;
18554                                                 }
18555                                         }
18556                                 }
18557                                 return changed;
18558                         },
18559
18560                         _checkOverlap = function(tween, reference, zeroDur) {
18561                                 var tl = tween._timeline,
18562                                         ts = tl._timeScale,
18563                                         t = tween._startTime;
18564                                 while (tl._timeline) {
18565                                         t += tl._startTime;
18566                                         ts *= tl._timeScale;
18567                                         if (tl._paused) {
18568                                                 return -100;
18569                                         }
18570                                         tl = tl._timeline;
18571                                 }
18572                                 t /= ts;
18573                                 return (t > reference) ? t - reference : ((zeroDur && t === reference) || (!tween._initted && t - reference < 2 * _tinyNum)) ? _tinyNum : ((t += tween.totalDuration() / tween._timeScale / ts) > reference + _tinyNum) ? 0 : t - reference - _tinyNum;
18574                         };
18575
18576
18577 //---- TweenLite instance methods -----------------------------------------------------------------------------
18578
18579                 p._init = function() {
18580                         var v = this.vars,
18581                                 op = this._overwrittenProps,
18582                                 dur = this._duration,
18583                                 immediate = !!v.immediateRender,
18584                                 ease = v.ease,
18585                                 i, initPlugins, pt, p, startVars;
18586                         if (v.startAt) {
18587                                 if (this._startAt) {
18588                                         this._startAt.render(-1, true); //if we've run a startAt previously (when the tween instantiated), we should revert it so that the values re-instantiate correctly particularly for relative tweens. Without this, a TweenLite.fromTo(obj, 1, {x:"+=100"}, {x:"-=100"}), for example, would actually jump to +=200 because the startAt would run twice, doubling the relative change.
18589                                         this._startAt.kill();
18590                                 }
18591                                 startVars = {};
18592                                 for (p in v.startAt) { //copy the properties/values into a new object to avoid collisions, like var to = {x:0}, from = {x:500}; timeline.fromTo(e, 1, from, to).fromTo(e, 1, to, from);
18593                                         startVars[p] = v.startAt[p];
18594                                 }
18595                                 startVars.overwrite = false;
18596                                 startVars.immediateRender = true;
18597                                 startVars.lazy = (immediate && v.lazy !== false);
18598                                 startVars.startAt = startVars.delay = null; //no nesting of startAt objects allowed (otherwise it could cause an infinite loop).
18599                                 this._startAt = TweenLite.to(this.target, 0, startVars);
18600                                 if (immediate) {
18601                                         if (this._time > 0) {
18602                                                 this._startAt = null; //tweens that render immediately (like most from() and fromTo() tweens) shouldn't revert when their parent timeline's playhead goes backward past the startTime because the initial render could have happened anytime and it shouldn't be directly correlated to this tween's startTime. Imagine setting up a complex animation where the beginning states of various objects are rendered immediately but the tween doesn't happen for quite some time - if we revert to the starting values as soon as the playhead goes backward past the tween's startTime, it will throw things off visually. Reversion should only happen in TimelineLite/Max instances where immediateRender was false (which is the default in the convenience methods like from()).
18603                                         } else if (dur !== 0) {
18604                                                 return; //we skip initialization here so that overwriting doesn't occur until the tween actually begins. Otherwise, if you create several immediateRender:true tweens of the same target/properties to drop into a TimelineLite or TimelineMax, the last one created would overwrite the first ones because they didn't get placed into the timeline yet before the first render occurs and kicks in overwriting.
18605                                         }
18606                                 }
18607                         } else if (v.runBackwards && dur !== 0) {
18608                                 //from() tweens must be handled uniquely: their beginning values must be rendered but we don't want overwriting to occur yet (when time is still 0). Wait until the tween actually begins before doing all the routines like overwriting. At that time, we should render at the END of the tween to ensure that things initialize correctly (remember, from() tweens go backwards)
18609                                 if (this._startAt) {
18610                                         this._startAt.render(-1, true);
18611                                         this._startAt.kill();
18612                                         this._startAt = null;
18613                                 } else {
18614                                         pt = {};
18615                                         for (p in v) { //copy props into a new object and skip any reserved props, otherwise onComplete or onUpdate or onStart could fire. We should, however, permit autoCSS to go through.
18616                                                 if (!_reservedProps[p] || p === "autoCSS") {
18617                                                         pt[p] = v[p];
18618                                                 }
18619                                         }
18620                                         pt.overwrite = 0;
18621                                         pt.data = "isFromStart"; //we tag the tween with as "isFromStart" so that if [inside a plugin] we need to only do something at the very END of a tween, we have a way of identifying this tween as merely the one that's setting the beginning values for a "from()" tween. For example, clearProps in CSSPlugin should only get applied at the very END of a tween and without this tag, from(...{height:100, clearProps:"height", delay:1}) would wipe the height at the beginning of the tween and after 1 second, it'd kick back in.
18622                                         pt.lazy = (immediate && v.lazy !== false);
18623                                         pt.immediateRender = immediate; //zero-duration tweens render immediately by default, but if we're not specifically instructed to render this tween immediately, we should skip this and merely _init() to record the starting values (rendering them immediately would push them to completion which is wasteful in that case - we'd have to render(-1) immediately after)
18624                                         this._startAt = TweenLite.to(this.target, 0, pt);
18625                                         if (!immediate) {
18626                                                 this._startAt._init(); //ensures that the initial values are recorded
18627                                                 this._startAt._enabled(false); //no need to have the tween render on the next cycle. Disable it because we'll always manually control the renders of the _startAt tween.
18628                                         } else if (this._time === 0) {
18629                                                 return;
18630                                         }
18631                                 }
18632                         }
18633                         if (!ease) {
18634                                 this._ease = TweenLite.defaultEase;
18635                         } else if (ease instanceof Ease) {
18636                                 this._ease = (v.easeParams instanceof Array) ? ease.config.apply(ease, v.easeParams) : ease;
18637                         } else {
18638                                 this._ease = (typeof(ease) === "function") ? new Ease(ease, v.easeParams) : _easeMap[ease] || TweenLite.defaultEase;
18639                         }
18640                         this._easeType = this._ease._type;
18641                         this._easePower = this._ease._power;
18642                         this._firstPT = null;
18643
18644                         if (this._targets) {
18645                                 i = this._targets.length;
18646                                 while (--i > -1) {
18647                                         if ( this._initProps( this._targets[i], (this._propLookup[i] = {}), this._siblings[i], (op ? op[i] : null)) ) {
18648                                                 initPlugins = true;
18649                                         }
18650                                 }
18651                         } else {
18652                                 initPlugins = this._initProps(this.target, this._propLookup, this._siblings, op);
18653                         }
18654
18655                         if (initPlugins) {
18656                                 TweenLite._onPluginEvent("_onInitAllProps", this); //reorders the array in order of priority. Uses a static TweenPlugin method in order to minimize file size in TweenLite
18657                         }
18658                         if (op) if (!this._firstPT) if (typeof(this.target) !== "function") { //if all tweening properties have been overwritten, kill the tween. If the target is a function, it's probably a delayedCall so let it live.
18659                                 this._enabled(false, false);
18660                         }
18661                         if (v.runBackwards) {
18662                                 pt = this._firstPT;
18663                                 while (pt) {
18664                                         pt.s += pt.c;
18665                                         pt.c = -pt.c;
18666                                         pt = pt._next;
18667                                 }
18668                         }
18669                         this._onUpdate = v.onUpdate;
18670                         this._initted = true;
18671                 };
18672
18673                 p._initProps = function(target, propLookup, siblings, overwrittenProps) {
18674                         var p, i, initPlugins, plugin, pt, v;
18675                         if (target == null) {
18676                                 return false;
18677                         }
18678
18679                         if (_lazyLookup[target._gsTweenID]) {
18680                                 _lazyRender(); //if other tweens of the same target have recently initted but haven't rendered yet, we've got to force the render so that the starting values are correct (imagine populating a timeline with a bunch of sequential tweens and then jumping to the end)
18681                         }
18682
18683                         if (!this.vars.css) if (target.style) if (target !== window && target.nodeType) if (_plugins.css) if (this.vars.autoCSS !== false) { //it's so common to use TweenLite/Max to animate the css of DOM elements, we assume that if the target is a DOM element, that's what is intended (a convenience so that users don't have to wrap things in css:{}, although we still recommend it for a slight performance boost and better specificity). Note: we cannot check "nodeType" on the window inside an iframe.
18684                                 _autoCSS(this.vars, target);
18685                         }
18686                         for (p in this.vars) {
18687                                 v = this.vars[p];
18688                                 if (_reservedProps[p]) {
18689                                         if (v) if ((v instanceof Array) || (v.push && _isArray(v))) if (v.join("").indexOf("{self}") !== -1) {
18690                                                 this.vars[p] = v = this._swapSelfInParams(v, this);
18691                                         }
18692
18693                                 } else if (_plugins[p] && (plugin = new _plugins[p]())._onInitTween(target, this.vars[p], this)) {
18694
18695                                         //t - target            [object]
18696                                         //p - property          [string]
18697                                         //s - start                     [number]
18698                                         //c - change            [number]
18699                                         //f - isFunction        [boolean]
18700                                         //n - name                      [string]
18701                                         //pg - isPlugin         [boolean]
18702                                         //pr - priority         [number]
18703                                         this._firstPT = pt = {_next:this._firstPT, t:plugin, p:"setRatio", s:0, c:1, f:true, n:p, pg:true, pr:plugin._priority};
18704                                         i = plugin._overwriteProps.length;
18705                                         while (--i > -1) {
18706                                                 propLookup[plugin._overwriteProps[i]] = this._firstPT;
18707                                         }
18708                                         if (plugin._priority || plugin._onInitAllProps) {
18709                                                 initPlugins = true;
18710                                         }
18711                                         if (plugin._onDisable || plugin._onEnable) {
18712                                                 this._notifyPluginsOfEnabled = true;
18713                                         }
18714
18715                                 } else {
18716                                         this._firstPT = propLookup[p] = pt = {_next:this._firstPT, t:target, p:p, f:(typeof(target[p]) === "function"), n:p, pg:false, pr:0};
18717                                         pt.s = (!pt.f) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();
18718                                         pt.c = (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) : (Number(v) - pt.s) || 0;
18719                                 }
18720                                 if (pt) if (pt._next) {
18721                                         pt._next._prev = pt;
18722                                 }
18723                         }
18724
18725                         if (overwrittenProps) if (this._kill(overwrittenProps, target)) { //another tween may have tried to overwrite properties of this tween before init() was called (like if two tweens start at the same time, the one created second will run first)
18726                                 return this._initProps(target, propLookup, siblings, overwrittenProps);
18727                         }
18728                         if (this._overwrite > 1) if (this._firstPT) if (siblings.length > 1) if (_applyOverwrite(target, this, propLookup, this._overwrite, siblings)) {
18729                                 this._kill(propLookup, target);
18730                                 return this._initProps(target, propLookup, siblings, overwrittenProps);
18731                         }
18732                         if (this._firstPT) if ((this.vars.lazy !== false && this._duration) || (this.vars.lazy && !this._duration)) { //zero duration tweens don't lazy render by default; everything else does.
18733                                 _lazyLookup[target._gsTweenID] = true;
18734                         }
18735                         return initPlugins;
18736                 };
18737
18738                 p.render = function(time, suppressEvents, force) {
18739                         var prevTime = this._time,
18740                                 duration = this._duration,
18741                                 prevRawPrevTime = this._rawPrevTime,
18742                                 isComplete, callback, pt, rawPrevTime;
18743                         if (time >= duration) {
18744                                 this._totalTime = this._time = duration;
18745                                 this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1;
18746                                 if (!this._reversed ) {
18747                                         isComplete = true;
18748                                         callback = "onComplete";
18749                                 }
18750                                 if (duration === 0) if (this._initted || !this.vars.lazy || force) { //zero-duration tweens are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
18751                                         if (this._startTime === this._timeline._duration) { //if a zero-duration tween is at the VERY end of a timeline and that timeline renders at its end, it will typically add a tiny bit of cushion to the render time to prevent rounding errors from getting in the way of tweens rendering their VERY end. If we then reverse() that timeline, the zero-duration tween will trigger its onReverseComplete even though technically the playhead didn't pass over it again. It's a very specific edge case we must accommodate.
18752                                                 time = 0;
18753                                         }
18754                                         if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time) {
18755                                                 force = true;
18756                                                 if (prevRawPrevTime > _tinyNum) {
18757                                                         callback = "onReverseComplete";
18758                                                 }
18759                                         }
18760                                         this._rawPrevTime = rawPrevTime = (!suppressEvents || time || prevRawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient.
18761                                 }
18762
18763                         } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
18764                                 this._totalTime = this._time = 0;
18765                                 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
18766                                 if (prevTime !== 0 || (duration === 0 && prevRawPrevTime > 0 && prevRawPrevTime !== _tinyNum)) {
18767                                         callback = "onReverseComplete";
18768                                         isComplete = this._reversed;
18769                                 }
18770                                 if (time < 0) {
18771                                         this._active = false;
18772                                         if (duration === 0) if (this._initted || !this.vars.lazy || force) { //zero-duration tweens are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
18773                                                 if (prevRawPrevTime >= 0) {
18774                                                         force = true;
18775                                                 }
18776                                                 this._rawPrevTime = rawPrevTime = (!suppressEvents || time || prevRawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient.
18777                                         }
18778                                 } else if (!this._initted) { //if we render the very beginning (time == 0) of a fromTo(), we must force the render (normal tweens wouldn't need to render at a time of 0 when the prevTime was also 0). This is also mandatory to make sure overwriting kicks in immediately.
18779                                         force = true;
18780                                 }
18781                         } else {
18782                                 this._totalTime = this._time = time;
18783
18784                                 if (this._easeType) {
18785                                         var r = time / duration, type = this._easeType, pow = this._easePower;
18786                                         if (type === 1 || (type === 3 && r >= 0.5)) {
18787                                                 r = 1 - r;
18788                                         }
18789                                         if (type === 3) {
18790                                                 r *= 2;
18791                                         }
18792                                         if (pow === 1) {
18793                                                 r *= r;
18794                                         } else if (pow === 2) {
18795                                                 r *= r * r;
18796                                         } else if (pow === 3) {
18797                                                 r *= r * r * r;
18798                                         } else if (pow === 4) {
18799                                                 r *= r * r * r * r;
18800                                         }
18801
18802                                         if (type === 1) {
18803                                                 this.ratio = 1 - r;
18804                                         } else if (type === 2) {
18805                                                 this.ratio = r;
18806                                         } else if (time / duration < 0.5) {
18807                                                 this.ratio = r / 2;
18808                                         } else {
18809                                                 this.ratio = 1 - (r / 2);
18810                                         }
18811
18812                                 } else {
18813                                         this.ratio = this._ease.getRatio(time / duration);
18814                                 }
18815                         }
18816
18817                         if (this._time === prevTime && !force) {
18818                                 return;
18819                         } else if (!this._initted) {
18820                                 this._init();
18821                                 if (!this._initted || this._gc) { //immediateRender tweens typically won't initialize until the playhead advances (_time is greater than 0) in order to ensure that overwriting occurs properly. Also, if all of the tweening properties have been overwritten (which would cause _gc to be true, as set in _init()), we shouldn't continue otherwise an onStart callback could be called for example.
18822                                         return;
18823                                 } else if (!force && this._firstPT && ((this.vars.lazy !== false && this._duration) || (this.vars.lazy && !this._duration))) {
18824                                         this._time = this._totalTime = prevTime;
18825                                         this._rawPrevTime = prevRawPrevTime;
18826                                         _lazyTweens.push(this);
18827                                         this._lazy = time;
18828                                         return;
18829                                 }
18830                                 //_ease is initially set to defaultEase, so now that init() has run, _ease is set properly and we need to recalculate the ratio. Overall this is faster than using conditional logic earlier in the method to avoid having to set ratio twice because we only init() once but renderTime() gets called VERY frequently.
18831                                 if (this._time && !isComplete) {
18832                                         this.ratio = this._ease.getRatio(this._time / duration);
18833                                 } else if (isComplete && this._ease._calcEnd) {
18834                                         this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1);
18835                                 }
18836                         }
18837                         if (this._lazy !== false) { //in case a lazy render is pending, we should flush it because the new render is occuring now (imagine a lazy tween instantiating and then immediately the user calls tween.seek(tween.duration()), skipping to the end - the end render would be forced, and then if we didn't flush the lazy render, it'd fire AFTER the seek(), rendering it at the wrong time.
18838                                 this._lazy = false;
18839                         }
18840                         if (!this._active) if (!this._paused && this._time !== prevTime && time >= 0) {
18841                                 this._active = true;  //so that if the user renders a tween (as opposed to the timeline rendering it), the timeline is forced to re-render and align it with the proper time/frame on the next rendering cycle. Maybe the tween already finished but the user manually re-renders it as halfway done.
18842                         }
18843                         if (prevTime === 0) {
18844                                 if (this._startAt) {
18845                                         if (time >= 0) {
18846                                                 this._startAt.render(time, suppressEvents, force);
18847                                         } else if (!callback) {
18848                                                 callback = "_dummyGS"; //if no callback is defined, use a dummy value just so that the condition at the end evaluates as true because _startAt should render AFTER the normal render loop when the time is negative. We could handle this in a more intuitive way, of course, but the render loop is the MOST important thing to optimize, so this technique allows us to avoid adding extra conditional logic in a high-frequency area.
18849                                         }
18850                                 }
18851                                 if (this.vars.onStart) if (this._time !== 0 || duration === 0) if (!suppressEvents) {
18852                                         this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
18853                                 }
18854                         }
18855
18856                         pt = this._firstPT;
18857                         while (pt) {
18858                                 if (pt.f) {
18859                                         pt.t[pt.p](pt.c * this.ratio + pt.s);
18860                                 } else {
18861                                         pt.t[pt.p] = pt.c * this.ratio + pt.s;
18862                                 }
18863                                 pt = pt._next;
18864                         }
18865
18866                         if (this._onUpdate) {
18867                                 if (time < 0) if (this._startAt && this._startTime) { //if the tween is positioned at the VERY beginning (_startTime 0) of its parent timeline, it's illegal for the playhead to go back further, so we should not render the recorded startAt values.
18868                                         this._startAt.render(time, suppressEvents, force); //note: for performance reasons, we tuck this conditional logic inside less traveled areas (most tweens don't have an onUpdate). We'd just have it at the end before the onComplete, but the values should be updated before any onUpdate is called, so we ALSO put it here and then if it's not called, we do so later near the onComplete.
18869                                 }
18870                                 if (!suppressEvents) if (this._time !== prevTime || isComplete) {
18871                                         this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
18872                                 }
18873                         }
18874
18875                         if (callback) if (!this._gc) { //check _gc because there's a chance that kill() could be called in an onUpdate
18876                                 if (time < 0 && this._startAt && !this._onUpdate && this._startTime) { //if the tween is positioned at the VERY beginning (_startTime 0) of its parent timeline, it's illegal for the playhead to go back further, so we should not render the recorded startAt values.
18877                                         this._startAt.render(time, suppressEvents, force);
18878                                 }
18879                                 if (isComplete) {
18880                                         if (this._timeline.autoRemoveChildren) {
18881                                                 this._enabled(false, false);
18882                                         }
18883                                         this._active = false;
18884                                 }
18885                                 if (!suppressEvents && this.vars[callback]) {
18886                                         this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
18887                                 }
18888                                 if (duration === 0 && this._rawPrevTime === _tinyNum && rawPrevTime !== _tinyNum) { //the onComplete or onReverseComplete could trigger movement of the playhead and for zero-duration tweens (which must discern direction) that land directly back on their start time, we don't want to fire again on the next render. Think of several addPause()'s in a timeline that forces the playhead to a certain spot, but what if it's already paused and another tween is tweening the "time" of the timeline? Each time it moves [forward] past that spot, it would move back, and since suppressEvents is true, it'd reset _rawPrevTime to _tinyNum so that when it begins again, the callback would fire (so ultimately it could bounce back and forth during that tween). Again, this is a very uncommon scenario, but possible nonetheless.
18889                                         this._rawPrevTime = 0;
18890                                 }
18891                         }
18892
18893                 };
18894
18895                 p._kill = function(vars, target) {
18896                         if (vars === "all") {
18897                                 vars = null;
18898                         }
18899                         if (vars == null) if (target == null || target === this.target) {
18900                                 this._lazy = false;
18901                                 return this._enabled(false, false);
18902                         }
18903                         target = (typeof(target) !== "string") ? (target || this._targets || this.target) : TweenLite.selector(target) || target;
18904                         var i, overwrittenProps, p, pt, propLookup, changed, killProps, record;
18905                         if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") {
18906                                 i = target.length;
18907                                 while (--i > -1) {
18908                                         if (this._kill(vars, target[i])) {
18909                                                 changed = true;
18910                                         }
18911                                 }
18912                         } else {
18913                                 if (this._targets) {
18914                                         i = this._targets.length;
18915                                         while (--i > -1) {
18916                                                 if (target === this._targets[i]) {
18917                                                         propLookup = this._propLookup[i] || {};
18918                                                         this._overwrittenProps = this._overwrittenProps || [];
18919                                                         overwrittenProps = this._overwrittenProps[i] = vars ? this._overwrittenProps[i] || {} : "all";
18920                                                         break;
18921                                                 }
18922                                         }
18923                                 } else if (target !== this.target) {
18924                                         return false;
18925                                 } else {
18926                                         propLookup = this._propLookup;
18927                                         overwrittenProps = this._overwrittenProps = vars ? this._overwrittenProps || {} : "all";
18928                                 }
18929
18930                                 if (propLookup) {
18931                                         killProps = vars || propLookup;
18932                                         record = (vars !== overwrittenProps && overwrittenProps !== "all" && vars !== propLookup && (typeof(vars) !== "object" || !vars._tempKill)); //_tempKill is a super-secret way to delete a particular tweening property but NOT have it remembered as an official overwritten property (like in BezierPlugin)
18933                                         for (p in killProps) {
18934                                                 if ((pt = propLookup[p])) {
18935                                                         if (pt.pg && pt.t._kill(killProps)) {
18936                                                                 changed = true; //some plugins need to be notified so they can perform cleanup tasks first
18937                                                         }
18938                                                         if (!pt.pg || pt.t._overwriteProps.length === 0) {
18939                                                                 if (pt._prev) {
18940                                                                         pt._prev._next = pt._next;
18941                                                                 } else if (pt === this._firstPT) {
18942                                                                         this._firstPT = pt._next;
18943                                                                 }
18944                                                                 if (pt._next) {
18945                                                                         pt._next._prev = pt._prev;
18946                                                                 }
18947                                                                 pt._next = pt._prev = null;
18948                                                         }
18949                                                         delete propLookup[p];
18950                                                 }
18951                                                 if (record) {
18952                                                         overwrittenProps[p] = 1;
18953                                                 }
18954                                         }
18955                                         if (!this._firstPT && this._initted) { //if all tweening properties are killed, kill the tween. Without this line, if there's a tween with multiple targets and then you killTweensOf() each target individually, the tween would technically still remain active and fire its onComplete even though there aren't any more properties tweening.
18956                                                 this._enabled(false, false);
18957                                         }
18958                                 }
18959                         }
18960                         return changed;
18961                 };
18962
18963                 p.invalidate = function() {
18964                         if (this._notifyPluginsOfEnabled) {
18965                                 TweenLite._onPluginEvent("_onDisable", this);
18966                         }
18967                         this._firstPT = null;
18968                         this._overwrittenProps = null;
18969                         this._onUpdate = null;
18970                         this._startAt = null;
18971                         this._initted = this._active = this._notifyPluginsOfEnabled = this._lazy = false;
18972                         this._propLookup = (this._targets) ? {} : [];
18973                         return this;
18974                 };
18975
18976                 p._enabled = function(enabled, ignoreTimeline) {
18977                         if (!_tickerActive) {
18978                                 _ticker.wake();
18979                         }
18980                         if (enabled && this._gc) {
18981                                 var targets = this._targets,
18982                                         i;
18983                                 if (targets) {
18984                                         i = targets.length;
18985                                         while (--i > -1) {
18986                                                 this._siblings[i] = _register(targets[i], this, true);
18987                                         }
18988                                 } else {
18989                                         this._siblings = _register(this.target, this, true);
18990                                 }
18991                         }
18992                         Animation.prototype._enabled.call(this, enabled, ignoreTimeline);
18993                         if (this._notifyPluginsOfEnabled) if (this._firstPT) {
18994                                 return TweenLite._onPluginEvent((enabled ? "_onEnable" : "_onDisable"), this);
18995                         }
18996                         return false;
18997                 };
18998
18999
19000 //----TweenLite static methods -----------------------------------------------------
19001
19002                 TweenLite.to = function(target, duration, vars) {
19003                         return new TweenLite(target, duration, vars);
19004                 };
19005
19006                 TweenLite.from = function(target, duration, vars) {
19007                         vars.runBackwards = true;
19008                         vars.immediateRender = (vars.immediateRender != false);
19009                         return new TweenLite(target, duration, vars);
19010                 };
19011
19012                 TweenLite.fromTo = function(target, duration, fromVars, toVars) {
19013                         toVars.startAt = fromVars;
19014                         toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
19015                         return new TweenLite(target, duration, toVars);
19016                 };
19017
19018                 TweenLite.delayedCall = function(delay, callback, params, scope, useFrames) {
19019                         return new TweenLite(callback, 0, {delay:delay, onComplete:callback, onCompleteParams:params, onCompleteScope:scope, onReverseComplete:callback, onReverseCompleteParams:params, onReverseCompleteScope:scope, immediateRender:false, useFrames:useFrames, overwrite:0});
19020                 };
19021
19022                 TweenLite.set = function(target, vars) {
19023                         return new TweenLite(target, 0, vars);
19024                 };
19025
19026                 TweenLite.getTweensOf = function(target, onlyActive) {
19027                         if (target == null) { return []; }
19028                         target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;
19029                         var i, a, j, t;
19030                         if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") {
19031                                 i = target.length;
19032                                 a = [];
19033                                 while (--i > -1) {
19034                                         a = a.concat(TweenLite.getTweensOf(target[i], onlyActive));
19035                                 }
19036                                 i = a.length;
19037                                 //now get rid of any duplicates (tweens of arrays of objects could cause duplicates)
19038                                 while (--i > -1) {
19039                                         t = a[i];
19040                                         j = i;
19041                                         while (--j > -1) {
19042                                                 if (t === a[j]) {
19043                                                         a.splice(i, 1);
19044                                                 }
19045                                         }
19046                                 }
19047                         } else {
19048                                 a = _register(target).concat();
19049                                 i = a.length;
19050                                 while (--i > -1) {
19051                                         if (a[i]._gc || (onlyActive && !a[i].isActive())) {
19052                                                 a.splice(i, 1);
19053                                         }
19054                                 }
19055                         }
19056                         return a;
19057                 };
19058
19059                 TweenLite.killTweensOf = TweenLite.killDelayedCallsTo = function(target, onlyActive, vars) {
19060                         if (typeof(onlyActive) === "object") {
19061                                 vars = onlyActive; //for backwards compatibility (before "onlyActive" parameter was inserted)
19062                                 onlyActive = false;
19063                         }
19064                         var a = TweenLite.getTweensOf(target, onlyActive),
19065                                 i = a.length;
19066                         while (--i > -1) {
19067                                 a[i]._kill(vars, target);
19068                         }
19069                 };
19070
19071
19072
19073 /*
19074  * ----------------------------------------------------------------
19075  * TweenPlugin   (could easily be split out as a separate file/class, but included for ease of use (so that people don't need to include another <script> call before loading plugins which is easy to forget)
19076  * ----------------------------------------------------------------
19077  */
19078                 var TweenPlugin = _class("plugins.TweenPlugin", function(props, priority) {
19079                                         this._overwriteProps = (props || "").split(",");
19080                                         this._propName = this._overwriteProps[0];
19081                                         this._priority = priority || 0;
19082                                         this._super = TweenPlugin.prototype;
19083                                 }, true);
19084
19085                 p = TweenPlugin.prototype;
19086                 TweenPlugin.version = "1.10.1";
19087                 TweenPlugin.API = 2;
19088                 p._firstPT = null;
19089
19090                 p._addTween = function(target, prop, start, end, overwriteProp, round) {
19091                         var c, pt;
19092                         if (end != null && (c = (typeof(end) === "number" || end.charAt(1) !== "=") ? Number(end) - start : parseInt(end.charAt(0) + "1", 10) * Number(end.substr(2)))) {
19093                                 this._firstPT = pt = {_next:this._firstPT, t:target, p:prop, s:start, c:c, f:(typeof(target[prop]) === "function"), n:overwriteProp || prop, r:round};
19094                                 if (pt._next) {
19095                                         pt._next._prev = pt;
19096                                 }
19097                                 return pt;
19098                         }
19099                 };
19100
19101                 p.setRatio = function(v) {
19102                         var pt = this._firstPT,
19103                                 min = 0.000001,
19104                                 val;
19105                         while (pt) {
19106                                 val = pt.c * v + pt.s;
19107                                 if (pt.r) {
19108                                         val = Math.round(val);
19109                                 } else if (val < min) if (val > -min) { //prevents issues with converting very small numbers to strings in the browser
19110                                         val = 0;
19111                                 }
19112                                 if (pt.f) {
19113                                         pt.t[pt.p](val);
19114                                 } else {
19115                                         pt.t[pt.p] = val;
19116                                 }
19117                                 pt = pt._next;
19118                         }
19119                 };
19120
19121                 p._kill = function(lookup) {
19122                         var a = this._overwriteProps,
19123                                 pt = this._firstPT,
19124                                 i;
19125                         if (lookup[this._propName] != null) {
19126                                 this._overwriteProps = [];
19127                         } else {
19128                                 i = a.length;
19129                                 while (--i > -1) {
19130                                         if (lookup[a[i]] != null) {
19131                                                 a.splice(i, 1);
19132                                         }
19133                                 }
19134                         }
19135                         while (pt) {
19136                                 if (lookup[pt.n] != null) {
19137                                         if (pt._next) {
19138                                                 pt._next._prev = pt._prev;
19139                                         }
19140                                         if (pt._prev) {
19141                                                 pt._prev._next = pt._next;
19142                                                 pt._prev = null;
19143                                         } else if (this._firstPT === pt) {
19144                                                 this._firstPT = pt._next;
19145                                         }
19146                                 }
19147                                 pt = pt._next;
19148                         }
19149                         return false;
19150                 };
19151
19152                 p._roundProps = function(lookup, value) {
19153                         var pt = this._firstPT;
19154                         while (pt) {
19155                                 if (lookup[this._propName] || (pt.n != null && lookup[ pt.n.split(this._propName + "_").join("") ])) { //some properties that are very plugin-specific add a prefix named after the _propName plus an underscore, so we need to ignore that extra stuff here.
19156                                         pt.r = value;
19157                                 }
19158                                 pt = pt._next;
19159                         }
19160                 };
19161
19162                 TweenLite._onPluginEvent = function(type, tween) {
19163                         var pt = tween._firstPT,
19164                                 changed, pt2, first, last, next;
19165                         if (type === "_onInitAllProps") {
19166                                 //sorts the PropTween linked list in order of priority because some plugins need to render earlier/later than others, like MotionBlurPlugin applies its effects after all x/y/alpha tweens have rendered on each frame.
19167                                 while (pt) {
19168                                         next = pt._next;
19169                                         pt2 = first;
19170                                         while (pt2 && pt2.pr > pt.pr) {
19171                                                 pt2 = pt2._next;
19172                                         }
19173                                         if ((pt._prev = pt2 ? pt2._prev : last)) {
19174                                                 pt._prev._next = pt;
19175                                         } else {
19176                                                 first = pt;
19177                                         }
19178                                         if ((pt._next = pt2)) {
19179                                                 pt2._prev = pt;
19180                                         } else {
19181                                                 last = pt;
19182                                         }
19183                                         pt = next;
19184                                 }
19185                                 pt = tween._firstPT = first;
19186                         }
19187                         while (pt) {
19188                                 if (pt.pg) if (typeof(pt.t[type]) === "function") if (pt.t[type]()) {
19189                                         changed = true;
19190                                 }
19191                                 pt = pt._next;
19192                         }
19193                         return changed;
19194                 };
19195
19196                 TweenPlugin.activate = function(plugins) {
19197                         var i = plugins.length;
19198                         while (--i > -1) {
19199                                 if (plugins[i].API === TweenPlugin.API) {
19200                                         _plugins[(new plugins[i]())._propName] = plugins[i];
19201                                 }
19202                         }
19203                         return true;
19204                 };
19205
19206                 //provides a more concise way to define plugins that have no dependencies besides TweenPlugin and TweenLite, wrapping common boilerplate stuff into one function (added in 1.9.0). You don't NEED to use this to define a plugin - the old way still works and can be useful in certain (rare) situations.
19207                 _gsDefine.plugin = function(config) {
19208                         if (!config || !config.propName || !config.init || !config.API) { throw "illegal plugin definition."; }
19209                         var propName = config.propName,
19210                                 priority = config.priority || 0,
19211                                 overwriteProps = config.overwriteProps,
19212                                 map = {init:"_onInitTween", set:"setRatio", kill:"_kill", round:"_roundProps", initAll:"_onInitAllProps"},
19213                                 Plugin = _class("plugins." + propName.charAt(0).toUpperCase() + propName.substr(1) + "Plugin",
19214                                         function() {
19215                                                 TweenPlugin.call(this, propName, priority);
19216                                                 this._overwriteProps = overwriteProps || [];
19217                                         }, (config.global === true)),
19218                                 p = Plugin.prototype = new TweenPlugin(propName),
19219                                 prop;
19220                         p.constructor = Plugin;
19221                         Plugin.API = config.API;
19222                         for (prop in map) {
19223                                 if (typeof(config[prop]) === "function") {
19224                                         p[map[prop]] = config[prop];
19225                                 }
19226                         }
19227                         Plugin.version = config.version;
19228                         TweenPlugin.activate([Plugin]);
19229                         return Plugin;
19230                 };
19231
19232
19233                 //now run through all the dependencies discovered and if any are missing, log that to the console as a warning. This is why it's best to have TweenLite load last - it can check all the dependencies for you.
19234                 a = window._gsQueue;
19235                 if (a) {
19236                         for (i = 0; i < a.length; i++) {
19237                                 a[i]();
19238                         }
19239                         for (p in _defLookup) {
19240                                 if (!_defLookup[p].func) {
19241                                         //window.console.log("GSAP encountered missing dependency: com.greensock." + p);
19242                                 }
19243                         }
19244                 }
19245
19246                 _tickerActive = false; //ensures that the first official animation forces a ticker.tick() to update the time when it is instantiated
19247
19248 })(window);
19249
19250 angular.module('b2b.att.collapse', ['b2b.att.transition'])
19251
19252 // The collapsible directive indicates a block of html that will expand and collapse
19253 .directive('b2bCollapse', ['$transition', function($transition) {
19254     // CSS transitions don't work with height: auto, so we have to manually change the height to a
19255     // specific value and then once the animation completes, we can reset the height to auto.
19256     // Unfortunately if you do this while the CSS transitions are specified (i.e. in the CSS class
19257     // "collapse") then you trigger a change to height 0 in between.
19258     // The fix is to remove the "collapse" CSS class while changing the height back to auto - phew!
19259
19260     var props = {
19261         open: {
19262             marginTop: null,
19263             marginBottom: null,
19264             paddingTop: null,
19265             paddingBottom: null,
19266             display: 'block'
19267         },
19268         closed: {
19269             marginTop: 0,
19270             marginBottom: 0,
19271             paddingTop: 0,
19272             paddingBottom: 0,
19273             display: 'none'
19274         }
19275     };
19276
19277     var fixUpHeight = function(scope, element, height) {
19278         // We remove the collapse CSS class to prevent a transition when we change to height: auto
19279         element.removeClass('b2bCollapse');
19280         element.css({height: height});
19281         //adjusting for any margin or padding
19282         if (height === 0) {
19283             element.css(props.closed);
19284         } else {
19285             element.css(props.open);
19286         }
19287         // It appears that  reading offsetWidth makes the browser realise that we have changed the
19288         // height already :-/
19289         var x = element[0].offsetWidth;
19290         element.addClass('b2bCollapse');
19291     };
19292
19293     return {
19294         link: function(scope, element, attrs) {
19295             var isCollapsed;
19296             var initialAnimSkip = true;
19297             scope.$watch(function() {
19298                 return element[0].scrollHeight;
19299             }, function(value) {
19300                 //The listener is called when scrollHeight changes
19301                 //It actually does on 2 scenarios: 
19302                 // 1. Parent is set to display none
19303                 // 2. angular bindings inside are resolved
19304                 //When we have a change of scrollHeight we are setting again the correct height if the group is opened
19305                 if (element[0].scrollHeight !== 0) {
19306                     if (!isCollapsed) {
19307                         if (initialAnimSkip) {
19308                             fixUpHeight(scope, element, element[0].scrollHeight + 'px');
19309                         } else {
19310                             fixUpHeight(scope, element, 'auto');
19311                             element.css({overflow: 'visible'});
19312                         }
19313                     }
19314                 }
19315             });
19316
19317             scope.$watch(attrs.b2bCollapse, function(value) {
19318                 if (value) {
19319                     collapse();
19320                 } else {
19321                     expand();
19322                 }
19323             });
19324
19325
19326             var currentTransition;
19327             var doTransition = function(change) {
19328                 if (currentTransition) {
19329                     currentTransition.cancel();
19330                 }
19331                 currentTransition = $transition(element, change);
19332                 currentTransition.then(
19333                         function() {
19334                             currentTransition = undefined;
19335                         },
19336                         function() {
19337                             currentTransition = undefined;
19338                         }
19339                 );
19340                 return currentTransition;
19341             };
19342
19343             var expand = function() {
19344                 scope.postTransition = true; 
19345                 if (initialAnimSkip) {
19346                     initialAnimSkip = false;
19347                     if (!isCollapsed) {
19348                         fixUpHeight(scope, element, 'auto');
19349                     }
19350                 } else {
19351                     //doTransition({ height : element[0].scrollHeight + 'px' })
19352                     doTransition(angular.extend({height: element[0].scrollHeight + 'px'}, props.open))
19353                             .then(function() {
19354                                 // This check ensures that we don't accidentally update the height if the user has closed
19355                                 // the group while the animation was still running
19356                                 if (!isCollapsed) {
19357                                     fixUpHeight(scope, element, 'auto');
19358                                 }
19359                             });
19360                 }
19361                 isCollapsed = false;
19362             };
19363
19364             var collapse = function() {
19365                 isCollapsed = true;
19366                 if (initialAnimSkip) {
19367                     initialAnimSkip = false;
19368                     fixUpHeight(scope, element, 0);
19369                 } else {
19370                     fixUpHeight(scope, element, element[0].scrollHeight + 'px');
19371                     doTransition(angular.extend({height: 0}, props.closed)).then(function() {
19372                         scope.postTransition = false;
19373                     });
19374                     element.css({overflow: 'hidden'});
19375                 }
19376             };
19377         }
19378     };
19379 }]);
19380 angular.module('b2b.att.position', [])
19381
19382 .factory('$position', ['$document', '$window', function ($document, $window) {
19383     function getStyle(el, cssprop) {
19384         if (el.currentStyle) { //IE
19385             return el.currentStyle[cssprop];
19386         } else if ($window.getComputedStyle) {
19387             return $window.getComputedStyle(el)[cssprop];
19388         }
19389         // finally try and get inline style
19390         return el.style[cssprop];
19391     }
19392
19393     /**
19394      * Checks if a given element is statically positioned
19395      * @param element - raw DOM element
19396      */
19397     function isStaticPositioned(element) {
19398         return (getStyle(element, "position") || 'static') === 'static';
19399     }
19400
19401     /**
19402      * returns the closest, non-statically positioned parentOffset of a given element
19403      * @param element
19404      */
19405     var parentOffsetEl = function (element) {
19406         var docDomEl = $document[0];
19407         var offsetParent = element.offsetParent || docDomEl;
19408         while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent)) {
19409             offsetParent = offsetParent.offsetParent;
19410         }
19411         return offsetParent || docDomEl;
19412     };
19413
19414     return {
19415         /**
19416          * Provides read-only equivalent of jQuery's position function:
19417          * http://api.jquery.com/position/
19418          */
19419         position: function (element) {
19420             var elBCR = this.offset(element);
19421             var offsetParentBCR = {
19422                 top: 0,
19423                 left: 0
19424             };
19425             var offsetParentEl = parentOffsetEl(element[0]);
19426             if (offsetParentEl !== $document[0]) {
19427                 offsetParentBCR = this.offset(angular.element(offsetParentEl));
19428                 offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop;
19429                 offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft;
19430             }
19431
19432             return {
19433                 width: element.prop('offsetWidth'),
19434                 height: element.prop('offsetHeight'),
19435                 top: elBCR.top - offsetParentBCR.top,
19436                 left: elBCR.left - offsetParentBCR.left
19437             };
19438         },
19439
19440         /**
19441          * Provides read-only equivalent of jQuery's offset function:
19442          * http://api.jquery.com/offset/
19443          */
19444         offset: function (element) {
19445             var boundingClientRect = element[0].getBoundingClientRect();
19446             return {
19447                 width: element.prop('offsetWidth'),
19448                 height: element.prop('offsetHeight'),
19449                 top: boundingClientRect.top + ($window.pageYOffset || $document[0].body.scrollTop || $document[0].documentElement.scrollTop),
19450                 left: boundingClientRect.left + ($window.pageXOffset || $document[0].body.scrollLeft || $document[0].documentElement.scrollLeft)
19451             };
19452         },
19453                 
19454                  /**
19455          * Provides functionality to check whether an element is in view port.
19456          */
19457         isElementInViewport: function (element) {
19458             if (element) {
19459                 var rect = element[0].getBoundingClientRect();
19460                 return (
19461                     rect.top >= 0 &&
19462                     rect.left >= 0 &&
19463                     rect.bottom <= ($window.innerHeight || $document[0].documentElement.clientHeight) &&
19464                     rect.right <= ($window.innerWidth || $document[0].documentElement.clientWidth)
19465                 );
19466             } else {
19467                 return false;
19468             }
19469         }
19470     };
19471 }])
19472
19473 .factory('$isElement', [function () {
19474     var isElement = function (currentElem, targetElem, alternateElem) {
19475         if (currentElem[0] === targetElem[0]) {
19476             return true;
19477         } else if (currentElem[0] === alternateElem[0]) {
19478             return false;
19479         } else {
19480             return isElement((currentElem.parent()[0] && currentElem.parent()) || targetElem, targetElem, alternateElem);
19481         }
19482     };
19483
19484     return isElement;
19485 }])
19486
19487 .directive('attPosition', ['$position', function ($position) {
19488     return {
19489         restrict: 'A',
19490         link: function (scope, elem, attr) {
19491             scope.$watchCollection(function () {
19492                 return $position.position(elem);
19493             }, function (value) {
19494                 scope[attr.attPosition] = value;
19495             });
19496         }
19497     };
19498 }]);
19499
19500 angular.module('b2b.att.transition', [])
19501
19502 .factory('$transition', ['$q', '$timeout', '$rootScope', function($q, $timeout, $rootScope) {
19503
19504   var $transition = function(element, trigger, options) {
19505     options = options || {};
19506     var deferred = $q.defer();
19507     var endEventName = $transition[options.animation ? "animationEndEventName" : "transitionEndEventName"];
19508
19509     var transitionEndHandler = function() {
19510       $rootScope.$apply(function() {
19511         element.unbind(endEventName, transitionEndHandler);
19512         deferred.resolve(element);
19513       });
19514     };
19515
19516     if (endEventName) {
19517       element.bind(endEventName, transitionEndHandler);
19518     }
19519
19520     // Wrap in a timeout to allow the browser time to update the DOM before the transition is to occur
19521     $timeout(function() {
19522       if ( angular.isString(trigger) ) {
19523         element.addClass(trigger);
19524       } else if ( angular.isFunction(trigger) ) {
19525         trigger(element);
19526       } else if ( angular.isObject(trigger) ) {
19527         element.css(trigger);
19528       }
19529       //If browser does not support transitions, instantly resolve
19530       if ( !endEventName ) {
19531         deferred.resolve(element);
19532       }
19533     }, 100);
19534
19535     // Add our custom cancel function to the promise that is returned
19536     // We can call this if we are about to run a new transition, which we know will prevent this transition from ending,
19537     // i.e. it will therefore never raise a transitionEnd event for that transition
19538     deferred.promise.cancel = function() {
19539       if ( endEventName ) {
19540         element.unbind(endEventName, transitionEndHandler);
19541       }
19542       deferred.reject('Transition cancelled');
19543     };
19544
19545     return deferred.promise;
19546   };
19547
19548   // Work out the name of the transitionEnd event
19549   var transElement = document.createElement('trans');
19550   var transitionEndEventNames = {
19551     'WebkitTransition': 'webkitTransitionEnd',
19552     'MozTransition': 'transitionend',
19553     'OTransition': 'oTransitionEnd',
19554     'transition': 'transitionend'
19555   };
19556   var animationEndEventNames = {
19557     'WebkitTransition': 'webkitAnimationEnd',
19558     'MozTransition': 'animationend',
19559     'OTransition': 'oAnimationEnd',
19560     'transition': 'animationend'
19561   };
19562   function findEndEventName(endEventNames) {
19563     for (var name in endEventNames){
19564       if (transElement.style[name] !== undefined) {
19565         return endEventNames[name];
19566       }
19567     }
19568   }
19569   $transition.transitionEndEventName = findEndEventName(transitionEndEventNames);
19570   $transition.animationEndEventName = findEndEventName(animationEndEventNames);
19571   return $transition;
19572 }])
19573
19574 .factory('$scrollTo', ['$window', function($window) {
19575     var $scrollTo = function(offsetLeft, offsetTop, duration) {
19576         TweenMax.to($window, duration || 1, {scrollTo: {y: offsetTop, x: offsetLeft}, ease: Power4.easeOut});
19577     };
19578     return $scrollTo;
19579 }])
19580 .factory('animation', function(){
19581     return TweenMax;
19582 })
19583 .factory('$progressBar', function(){
19584
19585    //Provides a function to pass in code for closure purposes
19586    var loadingAnimationCreator = function(onUpdateCallback){
19587
19588       //Use closure to setup some resuable code
19589       var loadingAnimation = function(callback, duration){
19590           TweenMax.to({}, duration, {
19591               onUpdateParams: ["{self}"],
19592               onUpdate: onUpdateCallback,
19593               onComplete: callback
19594           });
19595       };
19596       //Returns a function that takes a callback function and a duration for the animation
19597       return (function(){
19598         return loadingAnimation;
19599       })();
19600     };
19601
19602   return loadingAnimationCreator;
19603 })
19604 .factory('$height', function(){
19605   var heightAnimation = function(element,duration,height,alpha){
19606     TweenMax.to(element,
19607       duration,
19608       {height:height, autoAlpha:alpha},
19609       0);
19610   };
19611   return heightAnimation;
19612 });
19613 angular.module('b2b.att.utilities', ['ngSanitize'])
19614 .constant('b2bUtilitiesConfig', {
19615     prev: '37',
19616     up: '38',
19617     next: '39',
19618     down: '40',
19619     type: 'list',
19620     columns: 1,
19621     enableSearch: false,
19622     searchTimer: 200,
19623     circularTraversal: false
19624 })
19625 .constant('b2bWhenScrollEndsConstants', {
19626     'threshold': 100,
19627     'width': 0,
19628     'height': 0
19629 })
19630 // All breakpoints ranges from >= min and < max
19631 .constant('b2bAwdBreakpoints', {
19632     breakpoints: {
19633         mobile: {
19634             min: 1,
19635             max: 768
19636         },
19637         tablet: {
19638             min: 768,
19639             max: 1025
19640         },
19641         desktop: {
19642             min: 1025,
19643             max: 1920
19644         }
19645     }
19646 })
19647 .filter('groupBy', function ($timeout) {
19648     //Custom GroupBy Filter for treeNav, returns key string and value.childarray as set of grouped elements
19649     return function (data, key) {
19650         if (!key) return data;
19651         var outputPropertyName = '__groupBy__' + key;
19652         if (!data[outputPropertyName]) {
19653             var result = {};
19654             for (var i = 0; i < data.length; i++) {
19655                 if (!result[data[i][key]])
19656                     result[data[i][key]] = {};
19657                 if (!result[data[i][key]].childArray) {
19658                     result[data[i][key]].childArray = [];
19659                 }
19660                 result[data[i][key]].childArray.push(data[i]);
19661                 if (data[i].activeGrp && data[i].activeGrp == true) {
19662                     result[data[i][key]].showGroup = true;
19663                 }
19664             }
19665             Object.defineProperty(result, 'length', {enumerable: false,value: Object.keys(result).length});
19666             Object.defineProperty(data, outputPropertyName, {enumerable: false,configurable: true,writable:false,value:result});
19667             $timeout(function(){delete data[outputPropertyName];},0,false);
19668         }
19669         return data[outputPropertyName];
19670     };
19671 })
19672 .filter('searchObjectPropertiesFilter', [function() {
19673     return function(items, searchText, attrs) {
19674         if(!searchText){
19675             return items;
19676         }
19677         var filtered = [];
19678         searchText = searchText.toLowerCase();
19679         angular.forEach(items, function(item) {
19680             angular.forEach(attrs, function(attr) {
19681                 if (item.hasOwnProperty(attr) && (item[attr].toLowerCase().indexOf(searchText) != -1)) {
19682                     filtered.push(item);
19683                     return;
19684                 }
19685             });
19686         });
19687         return filtered;
19688     };
19689 }])
19690 .filter('unsafe',[ '$sce', function ($sce) { 
19691     return function(val){ 
19692        return $sce.trustAsHtml(val); 
19693     }; 
19694 }])
19695 .filter('b2bHighlight', function () {
19696     function escapeRegexp(queryToEscape) {
19697         return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
19698     }
19699     return function (matchItem, query, className) {
19700         return query && matchItem ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '<span class=\"' + className + '\">$&</span>') : matchItem;
19701     }
19702 })
19703 /*License (MIT)
19704 Copyright Â© 2013 Matt Diamond
19705 https://github.com/cwilso/AudioRecorder/blob/master/js/recorderjs/recorder.js
19706 */
19707 .factory('b2bRecorder', function() {
19708
19709     var Recorder = function(source, cfg) {
19710         var WORKER_PATH = 'recorderWorker.js';
19711         var config = cfg || {};
19712         var bufferLen = config.bufferLen || 4096;
19713         this.context = source.context;
19714         if(!this.context.createScriptProcessor) {
19715             this.node = this.context.createJavacriptProcessor(bufferLen, 2, 2);
19716         } else {
19717             this.node = this.context.createScriptProcessor(bufferLen, 2, 2);
19718         }
19719         var workerCode = 'function init(a){sampleRate=a.sampleRate}function record(a){recBuffersL.push(a[0]),recBuffersR.push(a[1]),recLength+=a[0].length}function exportWAV(a){var b=mergeBuffers(recBuffersL,recLength),c=mergeBuffers(recBuffersR,recLength),d=interleave(b,c),e=encodeWAV(d),f=new Blob([e],{type:a});this.postMessage(f)}function exportMonoWAV(a){var b=mergeBuffers(recBuffersL,recLength),c=encodeWAV(b,!0),d=new Blob([c],{type:a});this.postMessage(d)}function getBuffers(){var a=[];a.push(mergeBuffers(recBuffersL,recLength)),a.push(mergeBuffers(recBuffersR,recLength)),this.postMessage(a)}function clear(){recLength=0,recBuffersL=[],recBuffersR=[]}function mergeBuffers(a,b){for(var c=new Float32Array(b),d=0,e=0;e<a.length;e++)c.set(a[e],d),d+=a[e].length;return c}function interleave(a,b){for(var c=a.length+b.length,d=new Float32Array(c),e=0,f=0;e<c;)d[e++]=a[f],d[e++]=b[f],f++;return d}function floatTo16BitPCM(a,b,c){for(var d=0;d<c.length;d++,b+=2){var e=Math.max(-1,Math.min(1,c[d]));a.setInt16(b,e<0?32768*e:32767*e,!0)}}function writeString(a,b,c){for(var d=0;d<c.length;d++)a.setUint8(b+d,c.charCodeAt(d))}function encodeWAV(a,b){var c=new ArrayBuffer(44+2*a.length),d=new DataView(c);return writeString(d,0,"RIFF"),d.setUint32(4,32+2*a.length,!0),writeString(d,8,"WAVE"),writeString(d,12,"fmt "),d.setUint32(16,16,!0),d.setUint16(20,1,!0),d.setUint16(22,b?1:2,!0),d.setUint32(24,sampleRate,!0),d.setUint32(28,4*sampleRate,!0),d.setUint16(32,4,!0),d.setUint16(34,16,!0),writeString(d,36,"data"),d.setUint32(40,2*a.length,!0),floatTo16BitPCM(d,44,a),d}var recLength=0,recBuffersL=[],recBuffersR=[],sampleRate;this.onmessage=function(a){switch(a.data.command){case"init":init(a.data.config);break;case"record":record(a.data.buffer);break;case"exportWAV":exportWAV(a.data.type);break;case"exportMonoWAV":exportMonoWAV(a.data.type);break;case"getBuffers":getBuffers();break;case"clear":clear()}};';
19720         var blob = new Blob([workerCode]);
19721
19722         var worker = new Worker(window.URL.createObjectURL(blob)); //TODO: Use a blob instead
19723         worker.postMessage({
19724             command: 'init',
19725             config: {
19726                 sampleRate: this.context.sampleRate
19727             }
19728         });
19729         var recording = false,
19730             currCallback;
19731
19732         this.node.onaudioprocess = function(e) {
19733             if (!recording) return;
19734             worker.postMessage({
19735                 command: 'record',
19736                 buffer: [
19737                     e.inputBuffer.getChannelData(0),
19738                     e.inputBuffer.getChannelData(1)
19739                 ]
19740             });
19741         };
19742
19743         this.configure = function(cfg) {
19744             for (var prop in cfg) {//TODO: look into using angular.extend() here
19745                 if (cfg.hasOwnProperty(prop)) {
19746                     config[prop] = cfg[prop];
19747                 }
19748             }
19749         };
19750
19751         this.record = function() {
19752             recording = true;
19753         };
19754
19755         this.stop = function() {
19756             recording = false;
19757         };
19758
19759         this.clear = function() {
19760             worker.postMessage({ command: 'clear' });
19761             window.URL.revokeObjectURL(blob);
19762         };
19763
19764         this.getBuffers = function(cb) {
19765             currCallback = cb || config.callback;
19766             worker.postMessage({ command: 'getBuffers' });
19767         };
19768
19769         this.exportWAV = function(cb, type) {
19770             currCallback = cb || config.callback;
19771             type = type || config.type || 'audio/wav';
19772             if (!currCallback) throw new Error('[b2bRecorder]: Callback not set!');
19773             worker.postMessage({
19774                 command: 'exportWAV',
19775                 type: type
19776             });
19777         };
19778
19779         this.exportMonoWAV = function(cb, type) {
19780             currCallback = cb || config.callback;
19781             type = type || config.type || 'audio/wav';
19782             if (!currCallback) throw new Error('[b2bRecorder]: Callback not set!');
19783             worker.postMessage({
19784                 command: 'exportMonoWAV',
19785                 type: type
19786             });
19787         };
19788
19789         worker.onmessage = function(e) {
19790             var blob = e.data;
19791             currCallback(blob);
19792         };
19793
19794         source.connect(this.node);
19795         this.node.connect(this.context.destination); // if the script node is not connected to an output the "onaudioprocess" event is not triggerd in Chrome
19796
19797     };
19798
19799     return Recorder;
19800
19801 })
19802 .factory('b2bViewport', function() {
19803   /* Source: https://gist.github.com/bjankord/2399828 */
19804   var _viewportWidth = function() {
19805     var vpw;
19806     var webkit = (!(window.webkitConvertPointFromNodeToPage == null));
19807     
19808     // Webkit:
19809     if ( webkit ) {
19810       var vpwtest = document.createElement( "div" );
19811       // Sets test div to width 100%, !important overrides any other misc. box model styles that may be set in the CSS
19812       vpwtest.style.cssText = "width:100% !important; margin:0 !important; padding:0 !important; border:none !important;";
19813       document.documentElement.insertBefore( vpwtest, document.documentElement.firstChild );
19814       vpw = vpwtest.offsetWidth;
19815       document.documentElement.removeChild( vpwtest );
19816     }
19817     // IE 6-8:
19818     else if ( window.innerWidth === undefined ) { 
19819       vpw = document.documentElement.clientWidth; 
19820     }
19821     // Other:
19822     else{
19823       vpw =  window.innerWidth;
19824     }
19825
19826     return (vpw);
19827   }
19828   return {
19829     viewportWidth: _viewportWidth
19830   };
19831 })
19832 .directive('b2bWhenScrollEnds', function(b2bWhenScrollEndsConstants, $log) {
19833     return {
19834         restrict: 'A',
19835         link: function (scope, element, attrs) {
19836             /**
19837             * Exposed Attributes:
19838             *       threshold - integer - number of pixels before scrollbar hits end that callback is called
19839             *       width - integer - override for element's width (px)
19840             *       height - integer - override for element's height (px)
19841             *       axis - string - x/y for scroll bar axis
19842             */
19843             var threshold = parseInt(attrs.threshold, 10) || b2bWhenScrollEndsConstants.threshold;
19844
19845             if (!attrs.axis || attrs.axis === '') {
19846                 $log.warn('axis attribute must be defined for b2bWhenScrollEnds.');
19847                 return;
19848             }
19849
19850             if (attrs.axis === 'x') {
19851                 visibleWidth = parseInt(attrs.width, 10) || b2bWhenScrollEndsConstants.width;
19852                 if (element.css('width')) {
19853                     visibleWidth = element.css('width').split('px')[0];  
19854                 }
19855
19856                 element[0].addEventListener('scroll', function() {
19857                     var scrollableWidth = element.prop('scrollWidth');
19858                     if (scrollableWidth === undefined) {
19859                         scrollableWidth = 1;
19860                     }
19861                     var hiddenContentWidth = scrollableWidth - visibleWidth;
19862
19863                     if (hiddenContentWidth - element[0].scrollLeft <= threshold) {
19864                         /* Scroll almost at bottom, load more rows */
19865                         scope.$apply(attrs.b2bWhenScrollEnds);
19866                     }
19867                 });
19868             } else if (attrs.axis === 'y') {
19869                 visibleHeight = parseInt(attrs.height, 10) || b2bWhenScrollEndsConstants.height;
19870                 if (element.css('width')) {
19871                     visibleHeight = element.css('height').split('px')[0]; 
19872                 }
19873
19874                 element[0].addEventListener('scroll', function() {
19875                     var scrollableHeight = element.prop('scrollHeight');
19876                     if (scrollableHeight === undefined) {
19877                         scrollableHeight = 1;
19878                     }
19879                     var hiddenContentHeight = scrollableHeight - visibleHeight;
19880
19881                     if (hiddenContentHeight - element[0].scrollTop <= threshold) {
19882                         /* Scroll almost at bottom, load more rows */
19883                         scope.$apply(attrs.b2bWhenScrollEnds);
19884                     }
19885                 });
19886             }
19887         }
19888     };
19889 })
19890
19891 .factory('$windowBind', ['$window', '$timeout', function($window, $timeout) {
19892     var win = angular.element($window);
19893     var _scroll = function (flag, callbackFunc, scope) {
19894         scope.$watch(flag, function (val) {
19895             $timeout(function () {
19896                 if (val) {
19897                     win.bind('scroll', callbackFunc);
19898                 } else {
19899                     win.unbind('scroll', callbackFunc);
19900                 }
19901             });
19902         });
19903     };
19904
19905     var throttle = function(type, name, obj) {
19906         obj = obj || window;
19907         var running = false;
19908         var func = function() {
19909             if (running) { return; }
19910             running = true;
19911              requestAnimationFrame(function() {
19912                 obj.dispatchEvent(new CustomEvent(name));
19913                 running = false;
19914             });
19915         };
19916         obj.addEventListener(type, func);
19917     };
19918
19919     var _resize = function(callbackFunc, scope) {
19920         throttle("resize", "optimizedResize");
19921         window.addEventListener("optimizedResize", function(event) {
19922             callbackFunc();
19923             //win.bind(event, callbackFunc);
19924             if (!scope.$$phase) {
19925                 scope.$digest();
19926             }
19927         });
19928     };
19929
19930     var _click = function (flag, callbackFunc, scope) {
19931         scope.$watch(flag, function (val) {
19932             $timeout(function () {
19933                 if (val) {
19934                     win.bind('click', callbackFunc);
19935                 } else {
19936                     win.unbind('click', callbackFunc);
19937                 }
19938             });
19939         });
19940     };
19941
19942     var _event = function (event, flag, callbackFunc, scope, timeoutFlag, timeoutValue) {
19943         if (timeoutFlag) {
19944             if (!(timeoutValue)) {
19945                 timeoutValue = 0;
19946             }
19947             scope.$watch(flag, function (newVal, oldVal) {
19948                 if (newVal !== oldVal) {
19949                     $timeout(function () {
19950                         if (newVal) {
19951                             win.bind(event, callbackFunc);
19952                         } else {
19953                             win.unbind(event, callbackFunc);
19954                         }
19955                     }, timeoutValue);
19956                 }
19957             });
19958         } else {
19959             scope.$watch(flag, function (newVal, oldVal) {
19960                 if (newVal !== oldVal) {
19961                     if (newVal) {
19962                         win.bind(event, callbackFunc);
19963                     } else {
19964                         win.unbind(event, callbackFunc);
19965                     }
19966                 }
19967             });
19968         }
19969     };
19970
19971     return {
19972         click: _click,
19973         scroll: _scroll,
19974         event: _event, 
19975         resize: _resize
19976     };
19977 }])
19978
19979 .factory('keymap', function () {
19980     return {
19981         KEY: {
19982             TAB: 9,
19983             ENTER: 13,
19984             ESC: 27,
19985             SPACE: 32,
19986             LEFT: 37,
19987             UP: 38,
19988             RIGHT: 39,
19989             DOWN: 40,
19990             SHIFT: 16,
19991             CTRL: 17,
19992             ALT: 18,
19993             PAGE_UP: 33,
19994             PAGE_DOWN: 34,
19995             HOME: 36,
19996             END: 35,
19997             BACKSPACE: 8,
19998             DELETE: 46,
19999             COMMAND: 91
20000         },
20001         MAP: { 91 : "COMMAND", 8 : "BACKSPACE" , 9 : "TAB" , 13 : "ENTER" , 16 : "SHIFT" , 17 : "CTRL" , 18 : "ALT" , 19 : "PAUSEBREAK" , 20 : "CAPSLOCK" , 27 : "ESC" , 32 : "SPACE" , 33 : "PAGE_UP", 34 : "PAGE_DOWN" , 35 : "END" , 36 : "HOME" , 37 : "LEFT" , 38 : "UP" , 39 : "RIGHT" , 40 : "DOWN" , 43 : "+" , 44 : "PRINTSCREEN" , 45 : "INSERT" , 46 : "DELETE", 48 : "0" , 49 : "1" , 50 : "2" , 51 : "3" , 52 : "4" , 53 : "5" , 54 : "6" , 55 : "7" , 56 : "8" , 57 : "9" , 59 : ";", 61 : "=" , 65 : "A" , 66 : "B" , 67 : "C" , 68 : "D" , 69 : "E" , 70 : "F" , 71 : "G" , 72 : "H" , 73 : "I" , 74 : "J" , 75 : "K" , 76 : "L", 77 : "M" , 78 : "N" , 79 : "O" , 80 : "P" , 81 : "Q" , 82 : "R" , 83 : "S" , 84 : "T" , 85 : "U" , 86 : "V" , 87 : "W" , 88 : "X" , 89 : "Y" , 90 : "Z", 96 : "0" , 97 : "1" , 98 : "2" , 99 : "3" , 100 : "4" , 101 : "5" , 102 : "6" , 103 : "7" , 104 : "8" , 105 : "9", 106 : "*" , 107 : "+" , 109 : "-" , 110 : "." , 111 : "/", 112 : "F1" , 113 : "F2" , 114 : "F3" , 115 : "F4" , 116 : "F5" , 117 : "F6" , 118 : "F7" , 119 : "F8" , 120 : "F9" , 121 : "F10" , 122 : "F11" , 123 : "F12", 144 : "NUMLOCK" , 145 : "SCROLLLOCK" , 186 : ";" , 187 : "=" , 188 : "," , 189 : "-" , 190 : "." , 191 : "/" , 192 : "`" , 219 : "[" , 220 : "\\" , 221 : "]" , 222 : "'"
20002         },
20003         isControl: function (e) {
20004             var k = e.keyCode;
20005             switch (k) {
20006             case this.KEY.COMMAND:
20007             case this.KEY.SHIFT:
20008             case this.KEY.CTRL:
20009             case this.KEY.ALT:
20010                 return true;
20011             default:;
20012             }
20013
20014             if (e.metaKey) {
20015                 return true;
20016             }
20017
20018             return false;
20019         },
20020         isFunctionKey: function (k) {
20021             k = k.keyCode ? k.keyCode : k;
20022             return k >= 112 && k <= 123;
20023         },
20024         isVerticalMovement: function (k) {
20025             return ~[this.KEY.UP, this.KEY.DOWN].indexOf(k);
20026         },
20027         isHorizontalMovement: function (k) {
20028             return ~[this.KEY.LEFT, this.KEY.RIGHT, this.KEY.BACKSPACE, this.KEY.DELETE].indexOf(k);
20029         },
20030         isAllowedKey: function (k) {
20031             return (~[this.KEY.SPACE, this.KEY.ESC, this.KEY.ENTER].indexOf(k)) || this.isHorizontalMovement(k) || this.isVerticalMovement(k);
20032         },
20033         isNumericKey: function (e) {
20034             var k = e.keyCode;
20035             if ((k >= 48 && k <= 57) || (k >= 96 && k <= 105)) {
20036                 return true;
20037             } else {
20038                 return false;
20039             }
20040         },
20041         isAlphaNumericKey: function (e) {
20042             var k = e.keyCode;
20043             if ((k >= 48 && k <= 57) || (k >= 96 && k <= 105) || (k >= 65 && k <= 90)) {
20044                 return true;
20045             } else {
20046                 return false;
20047             }
20048         }
20049     };
20050 })
20051
20052 .factory('$isElement', [function () {
20053     var isElement = function (currentElem, targetElem, alternateElem) {
20054         if (currentElem[0] === targetElem[0]) {
20055             return true;
20056         } else if (currentElem[0] === alternateElem[0]) {
20057             return false;
20058         } else {
20059             return isElement((currentElem.parent()[0] && currentElem.parent()) || targetElem, targetElem, alternateElem);
20060         }
20061     };
20062
20063     return isElement;
20064 }])
20065
20066 .factory('events', function () {
20067     var _stopPropagation = function (evt) {
20068         if (evt.stopPropagation) {
20069             evt.stopPropagation();
20070         } else {
20071             evt.returnValue = false;
20072         }
20073     };
20074     var _preventDefault = function (evt) {
20075         if (evt.preventDefault) {
20076             evt.preventDefault();
20077         } else {
20078             evt.returnValue = false;
20079         }
20080     }
20081     return {
20082         stopPropagation: _stopPropagation,
20083         preventDefault: _preventDefault
20084     };
20085 })
20086
20087
20088 .factory('isHighContrast', function () {
20089     var _isHighContrast = function (idval)
20090
20091
20092      {
20093         var objDiv, objImage, strColor, strWidth, strReady;
20094         var strImageID = idval; // ID of image on the page
20095
20096         // Create a test div
20097         objDiv = document.createElement('div');
20098
20099         //Set its color style to something unusual
20100         objDiv.style.color = 'rgb(31, 41, 59)';
20101
20102         // Attach to body so we can inspect it
20103         document.body.appendChild(objDiv);
20104
20105         // Read computed color value
20106         strColor = document.defaultView ? document.defaultView.getComputedStyle(objDiv, null).color : objDiv.currentStyle.color;
20107         strColor = strColor.replace(/ /g, '');
20108
20109         // Delete the test DIV
20110         document.body.removeChild(objDiv);
20111
20112         // Check if we get the color back that we set. If not, we're in
20113         // high contrast mode.
20114         if (strColor !== 'rgb(31,41,59)') {
20115             return true;
20116         } else {
20117             return false;
20118         }
20119     };
20120
20121     return _isHighContrast;
20122 })
20123
20124 .run(['isHighContrast', '$document', function (isHighContrast, $document) {
20125     var html = $document.find('html').eq(0);
20126     if (isHighContrast()) {
20127         html.addClass('ds2-no-colors');
20128     } else {
20129         html.removeClass('ds2-no-colors');
20130     }
20131 }])
20132
20133 .factory('$documentBind', ['$document', '$timeout', function ($document, $timeout) {
20134     var _click = function (flag, callbackFunc, scope) {
20135         scope.$watch(flag, function (val) {
20136             $timeout(function () {
20137                 if (val) {
20138                     $document.bind('click', callbackFunc);
20139                 } else {
20140                     $document.unbind('click', callbackFunc);
20141                 }
20142             });
20143         });
20144     };
20145
20146     var _touch = function (flag, callbackFunc, scope) {
20147         scope.$watch(flag, function (val) {
20148             $timeout(function () {
20149                 if (val) {
20150                     $document.bind('touchstart', callbackFunc);
20151                 } else {
20152                     $document.unbind('touchstart', callbackFunc);
20153                 }
20154             });
20155         });
20156     };
20157
20158     var _scroll = function (flag, callbackFunc, scope) {
20159         scope.$watch(flag, function (val) {
20160             $timeout(function () {
20161                 if (val) {
20162                     $document.bind('scroll', callbackFunc);
20163                 } else {
20164                     $document.unbind('scroll', callbackFunc);
20165                 }
20166             });
20167         });
20168     };
20169
20170     var _event = function (event, flag, callbackFunc, scope, timeoutFlag, timeoutValue) {
20171         if (timeoutFlag) {
20172             if (!(timeoutValue)) {
20173                 timeoutValue = 0;
20174             }
20175             scope.$watch(flag, function (newVal, oldVal) {
20176                 if (newVal !== oldVal) {
20177                     $timeout(function () {
20178                         if (newVal) {
20179                             $document.bind(event, callbackFunc);
20180                         } else {
20181                             $document.unbind(event, callbackFunc);
20182                         }
20183                     }, timeoutValue);
20184                 }
20185             });
20186         } else {
20187             scope.$watch(flag, function (newVal, oldVal) {
20188                 if (newVal !== oldVal) {
20189                     if (newVal) {
20190                         $document.bind(event, callbackFunc);
20191                     } else {
20192                         $document.unbind(event, callbackFunc);
20193                     }
20194                 }
20195             });
20196         }
20197     };
20198
20199     return {
20200         click: _click,
20201         touch: _touch,
20202         scroll: _scroll,
20203         event: _event
20204     };
20205 }])
20206
20207 .directive('b2bOnlyNums', function (keymap) {
20208     return {
20209         restrict: 'A',
20210         require: 'ngModel',
20211         link: function (scope, elm, attrs, ctrl) {
20212             var maxChars = attrs.b2bOnlyNums ? attrs.b2bOnlyNums : 4;
20213             elm.on('keydown', function (event) {
20214                 if ((event.which >= 48 && event.which <= 57) || (event.which >= 96 && event.which <= 105)) {
20215                     // check for maximum characters allowed
20216                     if (elm.val().length < maxChars){
20217                         return true;
20218                     } else {
20219                         event.preventDefault();
20220                         return false;
20221                     }
20222                 } else if ([8, 9, 13, 27, 37, 38, 39, 40].indexOf(event.which) > -1) {
20223                     // to allow backspace, tab, enter, escape, arrows
20224                     return true;
20225                 } else if (event.altKey || event.ctrlKey) {
20226                     // to allow alter, control, and shift keys
20227                     return true;
20228                 } else {
20229                     // to stop others
20230                     event.preventDefault();
20231                     return false;
20232                 }
20233             });
20234
20235             var validateString = function (value) {
20236                 if (angular.isUndefined(value) || value === null || value === '') {
20237                     return ctrl.$modelValue;
20238                 }
20239                 return value;
20240             };
20241             ctrl.$parsers.unshift(validateString);
20242         }
20243     }
20244 })
20245
20246 .directive('b2bKeyupClick', [ function () {
20247     return {
20248         restrict: 'A',
20249         link: function (scope, elem, attr) {
20250             var keyCode = [];
20251             attr.$observe('b2bKeyupClick', function (value) {
20252                 if (value) {
20253                     keyCode = value.split(',');
20254                 }
20255             });
20256             elem.bind('keydown keyup', function (ev) {
20257                 var keyCodeCondition = function () {
20258                     var flag = false;
20259                     if (!(ev.keyCode)) {
20260                         if (ev.which) {
20261                             ev.keyCode = ev.which;
20262                         } else if (ev.charCode) {
20263                             ev.keyCode = ev.charCode;
20264                         }
20265                     }
20266                     if ((ev.keyCode && keyCode.indexOf(ev.keyCode.toString()) > -1)) {
20267                         flag = true;
20268                     }
20269                     return flag;
20270                 };
20271                 if (ev.type === 'keydown' && keyCodeCondition()) {
20272                     ev.preventDefault();
20273                 }
20274                 else if (ev.type === 'keyup' && keyCodeCondition()) {
20275                     elem[0].click();
20276                 }
20277             });
20278         }
20279     };
20280 }])
20281
20282 .factory('b2bDOMHelper', function() {
20283
20284     var _isTabable = function(node) {
20285         var element = angular.element(node);
20286         var tagName = element[0].tagName.toUpperCase();
20287
20288         if (isHidden(element)) {
20289             return false;
20290         }
20291         if (element.attr('tabindex') !== undefined) {
20292             return (parseInt(element.attr('tabindex'), 10) >= 0);
20293         }
20294         if (tagName === 'A' || tagName === 'AREA' || tagName === 'BUTTON' || tagName === 'INPUT' || tagName === 'TEXTAREA' || tagName === 'SELECT') {
20295             if (tagName === 'A' || tagName === 'AREA') {
20296                 // anchors/areas without href are not focusable
20297                 return (element[0].href !== '');
20298             }
20299             return !(element[0].disabled);
20300         }
20301         return false;
20302     };
20303
20304     function isValidChild(child) {
20305         return child.nodeType == 1 && child.nodeName != 'SCRIPT' && child.nodeName != 'STYLE';
20306     }
20307     
20308     function isHidden(obj) {
20309         var elem = angular.element(obj);
20310         var elemStyle = undefined;
20311         if(obj instanceof HTMLElement){
20312             elemStyle = window.getComputedStyle(obj);
20313         }
20314         else {
20315             elemStyle = window.getComputedStyle(obj[0]);
20316         }
20317         return elem.hasClass('ng-hide') || elem.css('display') === 'none' || elemStyle.display === 'none' || elemStyle.visibility === 'hidden' || elem.css('visibility') === 'hidden';
20318     }
20319
20320     function hasValidParent(obj) {
20321         return (isValidChild(obj) && obj.parentElement.nodeName !== 'BODY');
20322     }
20323
20324     function traverse(obj, fromTop) {
20325         var obj = obj || document.getElementsByTagName('body')[0];
20326         if (isValidChild(obj) && _isTabable(obj)) {
20327             return obj;
20328         }
20329         // If object is hidden, skip it's children
20330         if (isValidChild(obj) && isHidden(obj)) {
20331             return undefined;
20332         } 
20333         // If object is hidden, skip it's children
20334         if (angular.element(obj).hasClass('ng-hide')) {
20335             return undefined;
20336         }  
20337         if (obj.hasChildNodes()) {
20338             var child;
20339             if (fromTop) {
20340                 child = obj.firstChild;
20341             } else {
20342                 child = obj.lastChild;
20343             }
20344             while(child) {
20345                 var res =  traverse(child, fromTop);
20346                 if(res){
20347                     return res;
20348                 }
20349                 else{
20350                     if (fromTop) {
20351                         child = child.nextSibling;
20352                     } else {
20353                         child = child.previousSibling;
20354                     }
20355                 }
20356             }
20357         }
20358         else{
20359             return undefined;
20360         }
20361     }
20362
20363     var _previousElement = function(el, isFocusable){
20364
20365         var elem = el;
20366         if (el.hasOwnProperty('length')) {
20367             elem = el[0];
20368         }
20369
20370         var parent = elem.parentElement;
20371         var previousElem = undefined;
20372
20373         if(isFocusable) {
20374             if (hasValidParent(elem)) {
20375                 var siblings = angular.element(parent).children();
20376                 if (siblings.length > 0) {
20377                     // Good practice to splice out the elem from siblings if there, saving some time.
20378                     // We allow for a quick check for jumping to parent first before removing. 
20379                     if (siblings[0] === elem) {
20380                         // If we are looking at immidiate parent and elem is first child, we need to go higher
20381                         var e = _previousElement(angular.element(elem).parent(), isFocusable);
20382                         if (_isTabable(e)) {
20383                             return e;
20384                         }
20385                     } else {
20386                         // I need to filter myself and any nodes next to me from the siblings
20387                         var indexOfElem = Array.prototype.indexOf.call(siblings, elem);
20388                         siblings = Array.prototype.filter.call(siblings, function(item, itemIndex) {
20389                             if (!angular.equals(elem, item) && itemIndex < indexOfElem) {
20390                                 return true;
20391                             }
20392                         });
20393                     }
20394                     // We need to search backwards
20395                     for (var i = 0; i <= siblings.length-1; i++) {//for (var i = siblings.length-1; i >= 0; i--) {
20396                         var ret = traverse(siblings[i], false);
20397                         if (ret !== undefined) {
20398                             return ret;
20399                         }
20400                     }
20401
20402                     var e = _previousElement(angular.element(elem).parent(), isFocusable);
20403                     if (_isTabable(e)) {
20404                         return e;
20405                     }
20406                 }
20407             }
20408         } else {
20409             var siblings = angular.element(parent).children();
20410             if (siblings.length > 1) {
20411                 // Since indexOf is on Array.prototype and parent.children is a NodeList, we have to use call()
20412                 var index = Array.prototype.indexOf.call(siblings, elem);
20413                 previousElem = siblings[index-1];
20414             }
20415         }
20416         return previousElem;
20417     };
20418
20419     var _lastTabableElement = function(el) {
20420         /* This will return the first tabable element from the parent el */
20421         var elem = el;
20422         if (el.hasOwnProperty('length')) {
20423             elem = el[0];
20424         }
20425
20426         return traverse(elem, false);
20427     };
20428
20429     var _firstTabableElement = function(el) {
20430         /* This will return the first tabable element from the parent el */
20431         var elem = el;
20432         if (el.hasOwnProperty('length')) {
20433             elem = el[0];
20434         }
20435
20436         return traverse(elem, true);
20437     };
20438
20439     var _isInDOM = function(obj) {
20440       return document.documentElement.contains(obj);
20441     }
20442
20443     return {
20444         firstTabableElement: _firstTabableElement,
20445         lastTabableElement: _lastTabableElement,
20446         previousElement: _previousElement,
20447         isInDOM: _isInDOM,
20448         isTabable: _isTabable,
20449         isHidden: isHidden
20450     };
20451 })
20452
20453 .factory('windowOrientation', ['$window', function ($window) {
20454     var _isPotrait = function () {
20455         if ($window.innerHeight > $window.innerWidth) {
20456             return true;
20457         } else {
20458             return false;
20459         }
20460     };
20461     var _isLandscape = function () {
20462         if ($window.innerHeight < $window.innerWidth) {
20463             return true;
20464         } else {
20465             return false;
20466         }
20467     };
20468
20469     return {
20470         isPotrait: _isPotrait,
20471         isLandscape: _isLandscape
20472     };
20473 }])
20474 .directive('b2bNextElement', function() {
20475   return {
20476     restrict: 'A',
20477     transclude: false,
20478     link: function (scope, elem, attr, ctrls) {
20479
20480         var keys = attr.b2bNextElement.split(',');
20481
20482         elem.bind('keydown', function (e) {
20483             var nextElement = elem.next();
20484             if(e.keyCode == 39 || e.keyCode == 40){ // if e.keyCode in keys
20485                 if(nextElement.length) {
20486                     e.preventDefault();
20487                     nextElement[0].focus();
20488                 }
20489             }
20490         });
20491     }
20492   }
20493 })
20494
20495 .directive('b2bAccessibilityClick', [function () {
20496     return {
20497         restrict: 'A',
20498         link: function (scope, elem, attr, ctrl) {
20499             var keyCode = [];
20500             attr.$observe('b2bAccessibilityClick', function (value) {
20501                 if (value) {
20502                     keyCode = value.split(',');
20503                 }
20504             });
20505             elem.bind('keydown keypress', function (ev) {
20506                 var keyCodeCondition = function () {
20507                     var flag = false;
20508                     if (!(ev.keyCode)) {
20509                         if (ev.which) {
20510                             ev.keyCode = ev.which; 
20511                         } else if (ev.charCode) {
20512                             ev.keyCode = ev.charCode;
20513                         }
20514                     }
20515                     if ((ev.keyCode && keyCode.indexOf(ev.keyCode.toString()) > -1)) {
20516                         flag = true;
20517                     }
20518                     return flag;
20519                 };
20520                 if (keyCode.length > 0 && keyCodeCondition()) {
20521                     elem[0].click();
20522                     ev.preventDefault();
20523                 }
20524             });
20525         }
20526     };
20527 }])
20528
20529 .directive('b2bReset', ['$compile', function ($compile) {
20530         return {
20531             restrict: 'A',
20532             require: ['?ngModel', 'b2bReset'],
20533             controller: ['$scope', function ($scope) {
20534                 var resetButton = angular.element('<button type="button" class="reset-field" tabindex="-1" aria-label="Click to reset" aria-hidden="true" role="button"></button>');
20535
20536                 this.getResetButton = function () {
20537                     return resetButton;
20538                 };
20539             }],
20540             link: function (scope, element, attrs, ctrls) {
20541
20542                 var ngModelCtrl = ctrls[0];
20543                 var ctrl = ctrls[1];
20544
20545                 var resetButton = ctrl.getResetButton();
20546
20547
20548                 resetButton.on('click', function () {
20549                     element[0].value = '';
20550
20551                     if (ngModelCtrl) {
20552                         if (attrs.b2bReset) {
20553                             ngModelCtrl.$setViewValue(attrs.b2bReset);
20554                         } else {
20555                             ngModelCtrl.$setViewValue('');
20556                         }
20557                         element[0].value = ngModelCtrl.$viewValue;
20558                         ngModelCtrl.$render();
20559                         scope.$digest();
20560                     }
20561                     element[0].focus();
20562                     element[0].select();
20563                 });
20564
20565                 var addResetButton = function () {
20566                     element.after(resetButton);
20567                     element.unbind('focus input', addResetButton);
20568                 };
20569
20570                 element.bind('focus input', addResetButton);
20571             }
20572         };
20573     }])
20574
20575 .directive('b2bPrevElement', ['b2bDOMHelper', 'keymap', function (b2bDOMHelper, keymap) {
20576   return {
20577     restrict: 'A',
20578     transclude: false,
20579     link: function (scope, elem, attr) {
20580
20581         elem.bind('keydown', function (e) {
20582             if(e.keyCode == 37 || e.keyCode == 38){
20583                 var prev = b2bDOMHelper.previousElement(elem, false);
20584                 if(prev !== undefined) {
20585                     e.preventDefault();
20586                     prev.focus();
20587                 }
20588             }
20589         });
20590     }
20591   }
20592 }])
20593 /**
20594  * @param {integer} delay - Timeout before first and last focusable elements are found
20595  * @param {boolean} trigger - A variable on scope that will trigger refinding first/last focusable elements 
20596  */
20597 .directive('b2bTrapFocusInsideElement', ['$timeout', 'b2bDOMHelper', 'keymap', 'events', function ($timeout, b2bDOMHelper, keymap, events) {
20598     return {
20599         restrict: 'A',
20600         transclude: false,
20601         link: function (scope, elem, attr) {
20602
20603             var delay = parseInt(attr.delay, 10) || 10;
20604
20605             /* Before opening modal, find the focused element */
20606             var firstTabableElement = undefined,
20607                 lastTabableElement = undefined;
20608                 
20609             function init() {
20610                 $timeout(function () {
20611                     firstTabableElement = b2bDOMHelper.firstTabableElement(elem);
20612                     lastTabableElement = b2bDOMHelper.lastTabableElement(elem);
20613                     angular.element(firstTabableElement).bind('keydown', firstTabableElementKeyhandler);
20614                     angular.element(lastTabableElement).bind('keydown', lastTabableElementKeyhandler);
20615                 }, delay, false);
20616             }
20617
20618             if (attr.trigger !== undefined) {
20619                 scope.$watch('trigger', function() {
20620                     if (scope.trigger) {
20621                         init();
20622                     }
20623                 });
20624             }
20625
20626             var firstTabableElementKeyhandler = function(e) {
20627                 if (!e.keyCode) {
20628                     e.keyCode = e.which;
20629                 }
20630                 if (e.keyCode === keymap.KEY.TAB && e.shiftKey) {
20631                     if (attr.trapFocusInsideElement === 'true') {
20632                         var temp = b2bDOMHelper.lastTabableElement(elem);
20633                         if (lastTabableElement !== temp) {
20634                             // Unbind keydown handler on lastTabableElement
20635                             angular.element(lastTabableElement).unbind('keydown', lastTabableElementKeyhandler);
20636                             lastTabableElement = temp;
20637                             angular.element(lastTabableElement).bind('keydown', lastTabableElementKeyhandler);
20638                         }
20639                     }
20640                     lastTabableElement.focus();
20641                     events.preventDefault(e);
20642                     events.stopPropagation(e);
20643                 }
20644             };
20645
20646             var lastTabableElementKeyhandler = function(e) {
20647                 if (!e.keyCode) {
20648                     e.keyCode = e.which;
20649                 }
20650                 if (e.keyCode === keymap.KEY.TAB && !e.shiftKey) {
20651                     if (attr.trapFocusInsideElement === 'true') {
20652                         var temp = b2bDOMHelper.firstTabableElement(elem);
20653                         if (firstTabableElement !== temp) {
20654                             // Unbind keydown handler on firstTabableElement
20655                             angular.element(firstTabableElement).unbind('keydown', firstTabableElementKeyhandler);
20656                             firstTabableElement = temp;
20657                             angular.element(firstTabableElement).bind('keydown', firstTabableElementKeyhandler);
20658                         }
20659                     }
20660                     firstTabableElement.focus();
20661                     events.preventDefault(e);
20662                     events.stopPropagation(e);
20663                 }
20664             };
20665
20666             init();
20667         }
20668     };
20669 }])
20670
20671 .factory('trapFocusInElement', ['$document', '$isElement', 'b2bDOMHelper', 'keymap', '$interval', function ($document, $isElement, b2bDOMHelper, keymap, $interval) {
20672     var elementStack = [];
20673     var stackHead = undefined;
20674     var stopInterval = undefined;
20675     var intervalRequired = false;
20676     var interval = 1000;
20677     var firstTabableElement, lastTabableElement;
20678
20679     var trapKeyboardFocusInFirstElement = function (e) {
20680         if (!e.keyCode) {
20681             e.keyCode = e.which;
20682         }
20683
20684         if (e.shiftKey === true && e.keyCode === keymap.KEY.TAB) {
20685             lastTabableElement[0].focus();
20686             e.preventDefault(e);
20687             e.stopPropagation(e);
20688         }
20689
20690     };
20691
20692     var trapKeyboardFocusInLastElement = function (e) {
20693         if (!e.keyCode) {
20694             e.keyCode = e.which;
20695         }
20696
20697         if (e.shiftKey === false && e.keyCode === keymap.KEY.TAB) {
20698             firstTabableElement[0].focus();
20699             e.preventDefault(e);
20700             e.stopPropagation(e);
20701         }
20702     };
20703
20704     var trapFocusInElement = function (flag, firstTabableElementParam, lastTabableElementParam) {
20705         var bodyElements = $document.find('body').children();
20706
20707         firstTabableElement = firstTabableElementParam ? firstTabableElementParam : angular.element(b2bDOMHelper.firstTabableElement(stackHead));
20708         lastTabableElement = lastTabableElementParam ? lastTabableElementParam : angular.element(b2bDOMHelper.lastTabableElement(stackHead));
20709
20710         if (flag) {
20711             for (var i = 0; i < bodyElements.length; i++) {
20712                 if (bodyElements[i] !== stackHead[0]) {
20713                     bodyElements.eq(i).attr('aria-hidden', true);
20714                 }
20715             }
20716             firstTabableElement.bind('keydown', trapKeyboardFocusInFirstElement);
20717             lastTabableElement.bind('keydown', trapKeyboardFocusInLastElement);
20718         } else {
20719             for (var j = 0; j < bodyElements.length; j++) {
20720                 if (bodyElements[j] !== stackHead[0]) {
20721                     bodyElements.eq(j).removeAttr('aria-hidden');
20722                 }
20723             }
20724             firstTabableElement.unbind('keydown', trapKeyboardFocusInFirstElement);
20725             lastTabableElement.unbind('keydown', trapKeyboardFocusInLastElement);
20726         }
20727
20728         if (intervalRequired && flag) {
20729             stopInterval = $interval(function () {
20730                 var firstTabableElementTemp = angular.element(b2bDOMHelper.firstTabableElement(stackHead));
20731                 var lastTabableElementTemp = angular.element(b2bDOMHelper.lastTabableElement(stackHead));
20732                 if (firstTabableElementTemp[0] !== firstTabableElement[0] || lastTabableElementTemp[0] !== lastTabableElement[0]) {
20733                     $interval.cancel(stopInterval);
20734                     stopInterval = undefined;
20735                     trapFocusInElement(false, firstTabableElement, lastTabableElement);
20736                     trapFocusInElement(true, firstTabableElementTemp, lastTabableElementTemp);
20737                 }
20738             }, interval);
20739         } else {
20740             if (stopInterval) {
20741                 $interval.cancel(stopInterval);
20742                 stopInterval = undefined;
20743             }
20744         }
20745     };
20746     var toggleTrapFocusInElement = function (flag, element, intervalRequiredParam, intervalParam) {
20747         intervalRequired = intervalRequiredParam ? intervalRequiredParam : intervalRequired;
20748         interval = intervalParam ? intervalParam : interval;
20749         if (angular.isDefined(flag) && angular.isDefined(element)) {
20750             if (flag && angular.isUndefined(stackHead)) {
20751                 stackHead = element;
20752                 trapFocusInElement(flag);
20753             } else {
20754                 if (flag) {
20755                     trapFocusInElement(false);
20756                     elementStack.push(stackHead);
20757                     stackHead = element;
20758                     trapFocusInElement(true);
20759                 } else {
20760                     if (angular.isDefined(stackHead) && (stackHead[0] === element[0])) {
20761                         trapFocusInElement(false);
20762                         stackHead = elementStack.pop();
20763                         if (angular.isDefined(stackHead)) {
20764                             trapFocusInElement(true);
20765                         }
20766                     }
20767                 }
20768             }
20769         } else {
20770             if (angular.isDefined(stackHead)) {
20771                 trapFocusInElement(false, firstTabableElement, lastTabableElement);
20772                 trapFocusInElement(true);
20773             }
20774         }
20775     };
20776
20777     return toggleTrapFocusInElement;
20778 }])
20779 .factory('draggedElement', function(){
20780     var draggedElement;
20781     return {
20782         setElement: function(data){
20783             draggedElement = data;
20784         },
20785         getElement: function(){
20786             return draggedElement;
20787         }
20788     }
20789 })
20790
20791 .directive('draggable', ['draggedElement',function (draggedElement) { 
20792     return function(scope, element) { 
20793  
20794       element[0].draggable = true; 
20795  
20796       element.bind('dragstart', function(e) {
20797         draggedElement.setElement(this.parentElement.parentElement); 
20798         e.dataTransfer.effectAllowed = 'move'; 
20799         e.dataTransfer.setDragImage(this.parentElement.parentElement, 0, 0); 
20800         this.parentElement.parentElement.classList.add('b2-drag-element');
20801         return false; 
20802       }); 
20803  
20804       element.bind('dragend', function(e) { 
20805         draggedElement.setElement(e); 
20806         this.parentElement.parentElement.classList.remove('b2-drag-element'); 
20807         return false; 
20808       });
20809     }; 
20810 }]) 
20811  
20812 .directive('droppable', ['draggedElement',function (draggedElement) { 
20813     return { 
20814         restrict: 'EA', 
20815         replace: true, 
20816         scope: { 
20817           rowData: '=' 
20818         }, 
20819         link: function(scope, element, attr) {
20820             if(attr.droppable === 'true') {
20821               element.bind('dragover', function(e) { 
20822                 e.dataTransfer.dropEffect = 'move'; 
20823                 this.classList.add('b2b-drag-over') 
20824                 if (e.preventDefault) e.preventDefault(); // allows us to drop 
20825                 return false; 
20826               }); 
20827
20828               element.bind('dragstart', function(e) {
20829                 if(!e.target.parentElement.classList.contains('b2b-draggable')) {
20830                     e.preventDefault();
20831                     return false;
20832                 }
20833               }); 
20834
20835               element.bind('dragenter', function(e) { 
20836                 if(e.target.getAttribute('droppable') ==='true') {
20837                     this.click();
20838                 }
20839               });
20840
20841               element.bind('dragleave', function(e) { 
20842                 this.classList.remove('b2b-drag-over'); 
20843                 return false; 
20844               });
20845
20846               element.bind('drop', function(e) { 
20847                 var ele = draggedElement.getElement();
20848                 if (e.stopPropagation) e.stopPropagation(); 
20849                 if (e.preventDefault) e.preventDefault(); 
20850                 this.classList.remove('b2b-drag-over'); 
20851
20852                 if(ele && ele.hasAttribute('data-index')){
20853                     var element = scope.rowData[parseInt(ele.getAttribute('data-index'))]; 
20854                     if(element !== undefined) { 
20855                         scope.rowData.splice(parseInt(ele.getAttribute('data-index')), 1); 
20856                         scope.rowData.splice(parseInt(e.currentTarget.getAttribute('data-index')), 0 , element); 
20857                     }
20858                 }
20859                 scope.$apply(); 
20860      
20861                 return false; 
20862               }); 
20863           }
20864         } 
20865     } 
20866 }])
20867 .directive('b2bSetNextFocusOn', ['b2bDOMHelper', '$timeout', function(b2bDOMHelper, $timeout) {
20868     return {
20869         restrict: 'A',
20870         scope: true,
20871         link: function (scope, elem, attr) {
20872             elem.bind('click', function(){
20873                 var firstFocusableElement = undefined; 
20874                 var containerElem = undefined; 
20875                 var containerArray = [];
20876                 var timeout = parseInt(attr.setNextFocusTimeout, 0) | 100;
20877                 var index = parseInt(attr.b2bSetNextFocusIndex, 0) | 0;
20878
20879                                  /*
20880                                   *Fix for IE7 and lower 
20881                                   *polyfill src: https://github.com/HubSpot/pace/issues/102
20882                                   */
20883                                 if (!document.querySelectorAll) {
20884                                         document.querySelectorAll = function (selectors) {
20885                                                 var style = document.createElement('style'), elements = [], element;
20886                                                 document.documentElement.firstChild.appendChild(style);
20887                                                 document._qsa = [];
20888
20889                                                 style.styleSheet.cssText = selectors + '{x-qsa:expression(document._qsa && document._qsa.push(this))}';
20890                                                 window.scrollBy(0, 0);
20891                                                 style.parentNode.removeChild(style);
20892
20893                                                 while (document._qsa.length) {
20894                                                         element = document._qsa.shift();
20895                                                         element.style.removeAttribute('x-qsa');
20896                                                         elements.push(element);
20897                                                 }
20898                                                 document._qsa = null;
20899                                                 return elements;
20900                                         };
20901                                 }
20902
20903                 if (attr.b2bSetNextFocusOn === '') {
20904                     return;
20905                 } else {
20906                     containerArray = attr.b2bSetNextFocusOn.split(' ');
20907                 }
20908                 $timeout(function(){
20909                     var i = 0;
20910                     do { // cycles thru containerArray until finds a match in DOM to set focus to
20911                         containerElem = document.querySelectorAll(containerArray[i])[index]; 
20912                         i++;
20913                     } while ( (!containerElem) && (i < containerArray.length) );
20914                     if(containerElem){
20915                         if (!angular.isDefined(firstFocusableElement)) { 
20916                             firstFocusableElement = b2bDOMHelper.firstTabableElement(containerElem); 
20917                         }
20918                         firstFocusableElement.focus(); 
20919                     }
20920                 }, timeout, false)
20921             });
20922         }
20923
20924     };
20925 }])
20926
20927 .directive('b2bInputAllow', [function() {
20928     return {
20929         restrict: 'A',
20930         require: 'ngModel',
20931         link: function (scope, elem, attr, ctrl) {
20932             var regexExpression = null;
20933             attr.$observe('b2bInputAllow', function (value) {
20934                 if (value) {
20935                     regexExpression = new RegExp(value);
20936                 }
20937             });
20938             var isValid = function(str) {
20939                 if (regexExpression !== null) {
20940                     return regexExpression.test(str);
20941                 }
20942                 return false;
20943             };
20944             elem.bind('keypress', function($event) {
20945                 var charcode = String.fromCharCode($event.which || $event.keyCode);
20946                 if (!isValid(charcode)) {
20947                     $event.preventDefault();
20948                     $event.stopPropagation();
20949                 }
20950             });
20951             elem.bind('input', function (evt) {
20952                 var inputString = ctrl.$viewValue;
20953                 if (isValid(inputString)) {
20954                     ctrl.$setViewValue(inputString);
20955                     ctrl.$render();
20956                     scope.$apply();
20957                 }
20958             });
20959         }
20960     };
20961 }])
20962
20963 .directive('b2bInputDeny', [function() {
20964     return {
20965         restrict: 'A',
20966         require: 'ngModel',
20967         link: function (scope, elem, attr, ctrl) {
20968             var regexExpression = null;
20969             attr.$observe('b2bInputDeny', function (value) {
20970                 if (value) {
20971                     regexExpression = new RegExp(value, 'g');
20972                 }
20973             });
20974             elem.bind('input', function () {
20975                 var inputString = ctrl.$viewValue && ctrl.$viewValue.replace(regexExpression, '');
20976                 if (inputString !== ctrl.$viewValue) {
20977                     ctrl.$setViewValue(inputString);
20978                     ctrl.$render();
20979                     scope.$apply();
20980                 }
20981             });
20982         }
20983     };
20984 }])
20985
20986 .directive('b2bDragonInput', [function() {
20987     return {
20988         restrict: 'A',
20989         require: 'ngModel',
20990         link: function (scope, elem, attr, ctrl) {
20991             elem.on('focus keyup', function(){
20992                 elem.triggerHandler('change');
20993             });
20994         }
20995     };
20996 }])
20997
20998 .directive('b2bKey', ['b2bUtilitiesConfig', '$timeout', 'keymap', function (b2bUtilitiesConfig, $timeout, keymap) {
20999     return {
21000         restrict: 'EA',
21001         controller: ['$scope', '$element', '$attrs', function ($scope, $element,attr) {
21002             this.childElements = [];
21003             this.disableNodes = {};
21004             this.enableSearch = attr.enableSearch !== undefined ? true : b2bUtilitiesConfig.enableSearch;
21005             this.circularTraversal = attr.circularTraversal !== undefined ? true : b2bUtilitiesConfig.circularTraversal;
21006             this.counter = -1;
21007             if (this.enableSearch) {
21008                 this.searchKeys = [];
21009             }
21010             var searchString = '';
21011
21012             var selfCtrl = this;
21013
21014             this.childElementsList = [];
21015
21016             this.b2bKeyID = "";
21017
21018             if (angular.isDefined(attr.b2bKey)) {
21019                 this.b2bKeyID = attr.b2bKey;
21020             }
21021
21022             this.calculateChildElementsList = function () {
21023                 return $element[0].querySelectorAll("[b2b-key-item='" + this.b2bKeyID + "']:not([disabled])");
21024             };
21025
21026             this.resetChildElementsList = function () {
21027                 return $timeout(function () {
21028                     selfCtrl.childElementsList = selfCtrl.calculateChildElementsList();
21029                 });
21030             };
21031
21032             this.resetChildElementsList();
21033
21034             $scope.$on('b2b-key-reset-child-elements-list', function () {
21035                 selfCtrl.resetChildElementsList();
21036             });
21037
21038
21039             this.registerElement = function (childElement, searchKey) {
21040                 this.childElements.push(childElement);
21041                 if (this.enableSearch) {
21042                     this.searchKeys.push(searchKey);
21043                 }
21044                 var count = this.childElements.length - 1;
21045                 this.maxLength = count + 1;
21046                 return count;
21047             };
21048             this.toggleDisable = function (count, state) {
21049                 this.disableNodes[count] = state;
21050             };
21051             this.searchElement = function (searchExp) {
21052                 var regex = new RegExp("\\b" + searchExp, "gi");
21053                 var position = this.searchKeys.regexIndexOf(regex, this.counter + 1, true);
21054                 if (position > -1) {
21055                     this.counter = position;
21056                     this.moveFocus(this.counter);
21057                 }
21058             };
21059             this.startTimer = function (time) {
21060                 if (searchString === '') {
21061                     $timeout(function () {
21062                         searchString = '';
21063                     }, time);
21064                 }
21065             };
21066             this.resetCounter = function (count) {
21067                 this.counter = count;
21068             };
21069             this.moveNext = function (count) {
21070                 this.counter = (this.counter + count) < this.maxLength ? this.counter + count : (this.circularTraversal ? 0 : this.counter);
21071                 if (this.disableNodes[this.counter]) {
21072                     if ((this.counter + count) < this.maxLength) {
21073                         this.moveNext(count);
21074                     }
21075                 } else {
21076                     this.moveFocus(this.counter);
21077                 }
21078             };
21079             this.movePrev = function (count) {
21080                 this.counter = (this.counter - count) > -1 ? this.counter - count : (this.circularTraversal ? this.maxLength-1 : this.counter);
21081                 if (this.disableNodes[this.counter]) {
21082                     if ((this.counter - count) > -1) {
21083                         this.movePrev(count);
21084                     }
21085                 } else {
21086                     this.moveFocus(this.counter);
21087                 }
21088             };
21089             this.moveFocus = function (index) {
21090                 this.childElements[index][0].focus();
21091             };
21092
21093             this.keyDownHandler = function (ev, count) {
21094                 if (angular.isDefined(count) && !isNaN(count) && count !== this.counter) {
21095                     this.resetCounter(count);
21096                 }
21097                 if (!ev.keyCode) {
21098                     if (ev.which) {
21099                         ev.keyCode = ev.which;
21100                     } else if (ev.charCode) {
21101                         ev.keyCode = ev.charCode;
21102                     }
21103                 }
21104                 if (ev.keyCode) {
21105                     if (this.prev && this.prev.indexOf(ev.keyCode.toString()) > -1) {
21106                         this.movePrev(1);
21107                         ev.preventDefault();
21108                         ev.stopPropagation();
21109                     } else if (this.next && this.next.indexOf(ev.keyCode.toString()) > -1) {
21110                         this.moveNext(1);
21111                         ev.preventDefault();
21112                         ev.stopPropagation();
21113                     } else if (this.up && this.up.indexOf(ev.keyCode.toString()) > -1) {
21114                         if (this.type === 'table') {
21115                             this.movePrev(this.columns);
21116                             ev.preventDefault();
21117                             ev.stopPropagation();
21118                         }
21119                     } else if (this.down && this.down.indexOf(ev.keyCode.toString()) > -1) {
21120                         if (this.type === 'table') {
21121                             this.moveNext(this.columns);
21122                             ev.preventDefault();
21123                             ev.stopPropagation();
21124                         }
21125                     } else if (ev.keyCode === keymap.KEY.HOME) {
21126                         var firstIndex = 0;
21127                         while (this.disableNodes[firstIndex] !== false) {
21128                             firstIndex++;
21129                         };
21130                         var count = this.counter - firstIndex;
21131                         this.movePrev(count);
21132                         ev.preventDefault();
21133                         ev.stopPropagation();
21134                     } else if (ev.keyCode === keymap.KEY.END) {
21135                         var lastIndex = this.childElements.length - 1;
21136                         while (this.disableNodes[lastIndex] !== false) {
21137                             lastIndex--;
21138                         };
21139                         var count = lastIndex - this.counter;
21140                         this.moveNext(count);
21141                         ev.preventDefault();
21142                         ev.stopPropagation();
21143                     } else if (ev.keyCode >= 48 && ev.keyCode <= 105) {
21144                         if (this.enableSearch) {
21145                             this.startTimer(b2bUtilitiesConfig.searchTimer);
21146                             searchString = searchString + (keymap.MAP[ev.keyCode] || '');
21147                             this.searchElement(searchString);
21148                             ev.preventDefault();
21149                             ev.stopPropagation();
21150                         }
21151                     }
21152                 }
21153             };
21154         }],
21155         link: function (scope, elem, attr, ctrl) {
21156             ctrl.prev = attr.prev ? attr.prev.split(',') : b2bUtilitiesConfig.prev.split(',');
21157             ctrl.next = attr.next ? attr.next.split(',') : b2bUtilitiesConfig.next.split(',');
21158             ctrl.type = attr.type ? attr.type : b2bUtilitiesConfig.type;
21159             if (ctrl.type === 'table') {
21160                 ctrl.up = attr.up ? attr.up.split(',') : b2bUtilitiesConfig.up.split(',');
21161                 ctrl.down = attr.down ? attr.down.split(',') : b2bUtilitiesConfig.down.split(',');
21162                 ctrl.columns = attr.columns ? parseInt(attr.columns, 10) : b2bUtilitiesConfig.columns;
21163             }
21164
21165             elem.bind('keydown', function (ev) {
21166                 ctrl.keyDownHandler(ev);
21167             });
21168         }
21169     };
21170 }])
21171
21172 .directive('b2bKeyItem', [function () {
21173     return {
21174         restrict: 'EA',
21175         link: function (scope, elem, attr, ctrl) {
21176             var parentCtrl = (elem.parent() && elem.parent().controller('b2bKey')) || undefined;
21177             if (angular.isDefined(parentCtrl)) {
21178                 var count = parentCtrl.registerElement(elem, attr.searchKey);
21179                 elem.bind('keydown', function (ev) {
21180                     parentCtrl.keyDownHandler(ev, count);
21181                 });
21182                 scope.$watch(attr.b2bKeyItem, function (value) {
21183                     value = value === undefined ? true : value;
21184                     parentCtrl.toggleDisable(count, !value); 
21185                 });
21186                 scope.$on('$destroy', function () {
21187                     parentCtrl.toggleDisable(count, true);
21188                 });
21189             }
21190         }
21191     };
21192 }])
21193
21194 .directive('b2bElementFocus', [function () {
21195     return {
21196         restrict: 'A',
21197         link: function (scope, elem, attr, ctrl) {
21198             scope.$watch(attr.b2bElementFocus, function (value) {
21199                 if (value === true) {
21200                     elem[0].focus();
21201                 }
21202             });
21203         }
21204     };
21205 }])
21206
21207
21208 .directive('b2bAppendElement', ['$compile', function ($compile) {
21209     return {
21210         restrict: 'A',
21211         link: function (scope, elem, attr, ctrl) {
21212             var parameters = attr.b2bAppendElement.split(':');
21213             if (parameters.length === 1) {
21214                 elem.append(scope.$eval(parameters[0]));
21215             } else if (parameters.length === 2) {
21216                 if (parameters[1] === 'compile') {
21217                     var element = angular.element('<span>' + scope.$eval(parameters[0]) + '</span>');
21218                     elem.append($compile(element)(scope));
21219                 }
21220             }
21221
21222         }
21223     };
21224 }])
21225
21226 .directive('b2bKeyItemRefreshInNgRepeat', [function () {
21227     return {
21228         restrict: 'EA',
21229         require: '^^b2bKey',
21230         link: function (scope, elem, attr, parentCtrl) {
21231             if (angular.isDefined(parentCtrl)) {
21232
21233                 var attrToObserve = 'attrToObserve';
21234
21235                 if (attr.b2bKeyItemRefreshInNgRepeat) {
21236                     attrToObserve = 'b2bKeyItemRefreshInNgRepeat';
21237                 }
21238
21239                 attr.$observe(attrToObserve, function (newVal, oldVal) {
21240                     if (newVal && newVal !== oldVal) {
21241                         parentCtrl.resetChildElementsList();
21242                     }
21243                 });
21244             }
21245         }
21246     };
21247 }])
21248
21249 .constant('b2bMaskConfig', {
21250     maskDefinitions: {
21251         '9': /\d/,
21252         'A': /[a-zA-Z]/,
21253         '*': /[a-zA-Z0-9]/
21254     },
21255     clearOnBlur: false,
21256     clearOnBlurPlaceholder: false,
21257     escChar: '\\',
21258     eventsToHandle: ['input', 'keyup', 'click', 'focus'],
21259     addDefaultPlaceholder: true,
21260     allowInvalidValue: true
21261 })
21262 /**
21263  * @param {boolean} modelViewValue - If this is set to true, then the model value bound with ng-model will be the same as the $viewValue meaning it will contain any static mask characters present in the mask definition. This will not set the model value to a $viewValue that is considered invalid.
21264  * @param {String} maskPlaceholder - Allows customizing the mask placeholder when a user has focused the input element and while typing in their value
21265  * @param {String} maskPlaceholderChar - Allows customizing the mask placeholder character. The default mask placeholder is _.
21266  * @param {boolean} addDefaultPlaceholder - The default placeholder is constructed from the ui-mask definition so a mask of 999-9999 would have a default placeholder of ___-____; unless you have overridden the default placeholder character.
21267  */
21268 .directive('b2bMask', ['b2bMaskConfig', function(b2bMaskConfig) {
21269     return {
21270         require: 'ngModel',
21271         restrict: 'A',
21272         link: function(scope, element, attrs, ctrl) {
21273             var maskProcessed = false, eventsBound = false,
21274                 maskCaretMap, maskPatterns, maskPlaceholder, maskComponents,
21275                 // Minimum required length of the value to be considered valid
21276                 minRequiredLength,
21277                 value, valueMasked, isValid,
21278                 // Vars for initializing/uninitializing
21279                 originalPlaceholder = attrs.placeholder,
21280                 originalMaxlength = attrs.maxlength,
21281                 // Vars used exclusively in eventHandler()
21282                 oldValue, oldValueUnmasked, oldCaretPosition, oldSelectionLength,
21283                 // Used for communicating if a backspace operation should be allowed between
21284                 // keydownHandler and eventHandler
21285                 preventBackspace;
21286
21287             var options = b2bMaskConfig;
21288
21289             function isFocused (elem) {
21290               return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
21291             }
21292
21293             var originalIsEmpty = ctrl.$isEmpty;
21294             ctrl.$isEmpty = function(value) {
21295                 if (maskProcessed) {
21296                     return originalIsEmpty(unmaskValue(value || ''));
21297                 } else {
21298                     return originalIsEmpty(value);
21299                 }
21300             };
21301
21302             function initialize(maskAttr) {
21303                 if (!angular.isDefined(maskAttr)) {
21304                     return uninitialize();
21305                 }
21306                 processRawMask(maskAttr);
21307                 if (!maskProcessed) {
21308                     return uninitialize();
21309                 }
21310                 initializeElement();
21311                 bindEventListeners();
21312                 return true;
21313             }
21314
21315             function initPlaceholder(placeholderAttr) {
21316                 if ( ! placeholderAttr) {
21317                     return;
21318                 }
21319                 maskPlaceholder = placeholderAttr;
21320                 /* If the mask is processed, then we need to update the value
21321                    but don't set the value if there is nothing entered into the element
21322                    and there is a placeholder attribute on the element because that
21323                    will only set the value as the blank maskPlaceholder
21324                    and override the placeholder on the element */
21325                 if (maskProcessed && !(element.val().length === 0 && angular.isDefined(attrs.placeholder))) {
21326                     element.val(maskValue(unmaskValue(element.val())));
21327                 }
21328             }
21329
21330             function initPlaceholderChar() {
21331                 return initialize(attrs.uiMask);
21332             }
21333
21334             var modelViewValue = false;
21335
21336             attrs.$observe('modelViewValue', function(val) {
21337                 if (val === 'true') {
21338                     modelViewValue = true;
21339                 }
21340             });
21341
21342             attrs.$observe('allowInvalidValue', function(val) {
21343                 linkOptions.allowInvalidValue = val === ''? true : !!val;
21344                 formatter(ctrl.$modelValue);
21345             });
21346
21347             function formatter(fromModelValue) {
21348                 if (!maskProcessed) {
21349                     return fromModelValue;
21350                 }
21351                 value = unmaskValue(fromModelValue || '');
21352                 isValid = validateValue(value);
21353                 ctrl.$setValidity('mask', isValid);
21354
21355                 if (!value.length) return undefined;
21356                 if (isValid || linkOptions.allowInvalidValue) {
21357                     return maskValue(value);
21358                 } else {
21359                     return undefined;
21360                 }
21361             }
21362
21363             function parser(fromViewValue) {
21364                 if (!maskProcessed) {
21365                     return fromViewValue;
21366                 }
21367                 value = unmaskValue(fromViewValue || '');
21368                 isValid = validateValue(value);
21369                 /* We have to set viewValue manually as the reformatting of the input
21370                    value performed by eventHandler() doesn't happen until after
21371                    this parser is called, which causes what the user sees in the input
21372                    to be out-of-sync with what the ctrl's $viewValue is set to. */
21373                 ctrl.$viewValue = value.length ? maskValue(value) : '';
21374                 ctrl.$setValidity('mask', isValid);
21375
21376                 if (isValid || linkOptions.allowInvalidValue) {
21377                     return modelViewValue ? ctrl.$viewValue : value;
21378                 }
21379             }
21380
21381             var linkOptions = {};
21382
21383             // to do 
21384             if (attrs.b2bMaskOptions) {
21385                 linkOptions = scope.$eval('[' + attrs.b2bMaskOptions + ']');
21386                 if (angular.isObject(linkOptions[0])) {
21387                     // we can't use angular.copy nor angular.extend, they lack the power to do a deep merge
21388                     linkOptions = (function(original, current) {
21389                         for (var i in original) {
21390                             if (Object.prototype.hasOwnProperty.call(original, i)) {
21391                                 if (current[i] === undefined) {
21392                                     current[i] = angular.copy(original[i]);
21393                                 } else {
21394                                     if (angular.isObject(current[i]) && !angular.isArray(current[i])) {
21395                                         current[i] = angular.extend({}, original[i], current[i]);
21396                                     }
21397                                 }
21398                             }
21399                         }
21400                         return current;
21401                     })(options, linkOptions[0]);
21402                 } else {
21403                     linkOptions = options;  //gotta be a better way to do this..
21404                 }
21405             } else {
21406                 linkOptions = options;
21407             }
21408
21409             attrs.$observe('b2bMask', initialize);
21410             if (angular.isDefined(attrs.maskPlaceholder)) {
21411                 attrs.$observe('maskPlaceholder', initPlaceholder);
21412             }
21413             else {
21414                 attrs.$observe('placeholder', initPlaceholder);
21415             }
21416             if (angular.isDefined(attrs.maskPlaceholderChar)) {
21417                 attrs.$observe('maskPlaceholderChar', initPlaceholderChar);
21418             }
21419
21420             ctrl.$formatters.unshift(formatter);
21421             ctrl.$parsers.unshift(parser);
21422
21423             function uninitialize() {
21424                 maskProcessed = false;
21425                 unbindEventListeners();
21426
21427                 if (angular.isDefined(originalPlaceholder)) {
21428                     element.attr('placeholder', originalPlaceholder);
21429                 } else {
21430                     element.removeAttr('placeholder');
21431                 }
21432
21433                 if (angular.isDefined(originalMaxlength)) {
21434                     element.attr('maxlength', originalMaxlength);
21435                 } else {
21436                     element.removeAttr('maxlength');
21437                 }
21438
21439                 element.val(ctrl.$modelValue);
21440                 ctrl.$viewValue = ctrl.$modelValue;
21441                 return false;
21442             }
21443
21444             function initializeElement() {
21445                 value = oldValueUnmasked = unmaskValue(ctrl.$modelValue || '');
21446                 valueMasked = oldValue = maskValue(value);
21447                 isValid = validateValue(value);
21448                 if (attrs.maxlength) { // Double maxlength to allow pasting new val at end of mask
21449                     element.attr('maxlength', maskCaretMap[maskCaretMap.length - 1] * 2);
21450                 }
21451                 if ( ! originalPlaceholder && linkOptions.addDefaultPlaceholder) {
21452                     element.attr('placeholder', maskPlaceholder);
21453                 }
21454                 var viewValue = ctrl.$modelValue;
21455                 var idx = ctrl.$formatters.length;
21456                 while(idx--) {
21457                     viewValue = ctrl.$formatters[idx](viewValue);
21458                 }
21459                 ctrl.$viewValue = viewValue || '';
21460                 ctrl.$render();
21461             }
21462
21463             function bindEventListeners() {
21464                 if (eventsBound) {
21465                     return;
21466                 }
21467                 element.bind('blur', blurHandler);
21468                 element.bind('mousedown mouseup', mouseDownUpHandler);
21469                 element.bind('keydown', keydownHandler);
21470                 element.bind(linkOptions.eventsToHandle.join(' '), eventHandler);
21471                 eventsBound = true;
21472             }
21473
21474             function unbindEventListeners() {
21475                 if (!eventsBound) {
21476                     return;
21477                 }
21478                 element.unbind('blur', blurHandler);
21479                 element.unbind('mousedown', mouseDownUpHandler);
21480                 element.unbind('mouseup', mouseDownUpHandler);
21481                 element.unbind('keydown', keydownHandler);
21482                 element.unbind('input', eventHandler);
21483                 element.unbind('keyup', eventHandler);
21484                 element.unbind('click', eventHandler);
21485                 element.unbind('focus', eventHandler);
21486                 eventsBound = false;
21487             }
21488
21489             function validateValue(value) {
21490                 // Zero-length value validity is ngRequired's determination
21491                 return value.length ? value.length >= minRequiredLength : true;
21492             }
21493
21494              function unmaskValue(value) {
21495                 var valueUnmasked = '',
21496                     input = element[0],
21497                     maskPatternsCopy = maskPatterns.slice(),
21498                     selectionStart = oldCaretPosition,
21499                     selectionEnd = selectionStart + getSelectionLength(input),
21500                     valueOffset, valueDelta, tempValue = '';
21501                 // Preprocess by stripping mask components from value
21502                 value = value.toString();
21503                 valueOffset = 0;
21504                 valueDelta = value.length - maskPlaceholder.length;
21505                 angular.forEach(maskComponents, function(component) {
21506                     var position = component.position;
21507                     //Only try and replace the component if the component position is not within the selected range
21508                     //If component was in selected range then it was removed with the user input so no need to try and remove that component
21509                     if (!(position >= selectionStart && position < selectionEnd)) {
21510                         if (position >= selectionStart) {
21511                             position += valueDelta;
21512                         }
21513                         if (value.substring(position, position + component.value.length) === component.value) {
21514                             tempValue += value.slice(valueOffset, position);// + value.slice(position + component.value.length);
21515                             valueOffset = position + component.value.length;
21516                         }
21517                     }
21518                 });
21519                 value = tempValue + value.slice(valueOffset);
21520                 angular.forEach(value.split(''), function(chr) {
21521                     if (maskPatternsCopy.length && maskPatternsCopy[0].test(chr)) {
21522                         valueUnmasked += chr;
21523                         maskPatternsCopy.shift();
21524                     }
21525                 });
21526
21527                 return valueUnmasked;
21528             }
21529
21530             function maskValue(unmaskedValue) {
21531                 var valueMasked = '',
21532                         maskCaretMapCopy = maskCaretMap.slice();
21533
21534                 angular.forEach(maskPlaceholder.split(''), function(chr, i) {
21535                     if (unmaskedValue.length && i === maskCaretMapCopy[0]) {
21536                         valueMasked += unmaskedValue.charAt(0) || '_';
21537                         unmaskedValue = unmaskedValue.substr(1);
21538                         maskCaretMapCopy.shift();
21539                     }
21540                     else {
21541                         valueMasked += chr;
21542                     }
21543                 });
21544                 return valueMasked;
21545             }
21546
21547             function getPlaceholderChar(i) {
21548                 var placeholder = angular.isDefined(attrs.uiMaskPlaceholder) ? attrs.uiMaskPlaceholder : attrs.placeholder,
21549                     defaultPlaceholderChar;
21550
21551                 if (angular.isDefined(placeholder) && placeholder[i]) {
21552                     return placeholder[i];
21553                 } else {
21554                     defaultPlaceholderChar = angular.isDefined(attrs.uiMaskPlaceholderChar) && attrs.uiMaskPlaceholderChar ? attrs.uiMaskPlaceholderChar : '_';
21555                     return (defaultPlaceholderChar.toLowerCase() === 'space') ? ' ' : defaultPlaceholderChar[0];
21556                 }
21557             }
21558
21559             /* Generate array of mask components that will be stripped from a masked value
21560                before processing to prevent mask components from being added to the unmasked value.
21561                E.g., a mask pattern of '+7 9999' won't have the 7 bleed into the unmasked value. */
21562             function getMaskComponents() {
21563                 var maskPlaceholderChars = maskPlaceholder.split(''),
21564                         maskPlaceholderCopy, components;
21565
21566                 /* maskCaretMap can have bad values if the input has the ui-mask attribute implemented as an obversable property, e.g. the demo page */
21567                 if (maskCaretMap && !isNaN(maskCaretMap[0])) {
21568                     /* Instead of trying to manipulate the RegEx based on the placeholder characters
21569                        we can simply replace the placeholder characters based on the already built
21570                        maskCaretMap to underscores and leave the original working RegEx to get the proper
21571                        mask components */
21572                     angular.forEach(maskCaretMap, function(value) {
21573                         maskPlaceholderChars[value] = '_';
21574                     });
21575                 }
21576                 maskPlaceholderCopy = maskPlaceholderChars.join('');
21577                 components = maskPlaceholderCopy.replace(/[_]+/g, '_').split('_');
21578                 components = components.filter(function(s) {
21579                     return s !== '';
21580                 });
21581
21582                 /* need a string search offset in cases where the mask contains multiple identical components
21583                    E.g., a mask of 99.99.99-999.99 */
21584                 var offset = 0;
21585                 return components.map(function(c) {
21586                     var componentPosition = maskPlaceholderCopy.indexOf(c, offset);
21587                     offset = componentPosition + 1;
21588                     return {
21589                         value: c,
21590                         position: componentPosition
21591                     };
21592                 });
21593             }
21594
21595             function processRawMask(mask) {
21596                 var characterCount = 0;
21597
21598                 maskCaretMap = [];
21599                 maskPatterns = [];
21600                 maskPlaceholder = '';
21601
21602                 if (angular.isString(mask)) {
21603                     minRequiredLength = 0;
21604
21605                     var isOptional = false,
21606                             numberOfOptionalCharacters = 0,
21607                             splitMask = mask.split('');
21608
21609                     var inEscape = false;
21610                     angular.forEach(splitMask, function(chr, i) {
21611                         if (inEscape) {
21612                             inEscape = false;
21613                             maskPlaceholder += chr;
21614                             characterCount++;
21615                         }
21616                         else if (linkOptions.escChar === chr) {
21617                             inEscape = true;
21618                         }
21619                         else if (linkOptions.maskDefinitions[chr]) {
21620                             maskCaretMap.push(characterCount);
21621
21622                             maskPlaceholder += getPlaceholderChar(i - numberOfOptionalCharacters);
21623                             maskPatterns.push(linkOptions.maskDefinitions[chr]);
21624
21625                             characterCount++;
21626                             if (!isOptional) {
21627                                 minRequiredLength++;
21628                             }
21629
21630                             isOptional = false;
21631                         }
21632                         else if (chr === '?') {
21633                             isOptional = true;
21634                             numberOfOptionalCharacters++;
21635                         }
21636                         else {
21637                             maskPlaceholder += chr;
21638                             characterCount++;
21639                         }
21640                     });
21641                 }
21642                 // Caret position immediately following last position is valid.
21643                 maskCaretMap.push(maskCaretMap.slice().pop() + 1);
21644
21645                 maskComponents = getMaskComponents();
21646                 maskProcessed = maskCaretMap.length > 1 ? true : false;
21647             }
21648
21649             var prevValue = element.val();
21650             function blurHandler() {
21651                 if (linkOptions.clearOnBlur || ((linkOptions.clearOnBlurPlaceholder) && (value.length === 0) && attrs.placeholder)) {
21652                     oldCaretPosition = 0;
21653                     oldSelectionLength = 0;
21654                     if (!isValid || value.length === 0) {
21655                         valueMasked = '';
21656                         element.val('');
21657                         scope.$apply(function() {
21658                             //only $setViewValue when not $pristine to avoid changing $pristine state.
21659                             if (!ctrl.$pristine) {
21660                                 ctrl.$setViewValue('');
21661                             }
21662                         });
21663                     }
21664                 }
21665                 //Check for different value and trigger change.
21666                 if (value !== prevValue) {
21667                     var currentVal = element.val();
21668                     var isTemporarilyEmpty = value === '' && currentVal && angular.isDefined(attrs.uiMaskPlaceholderChar) && attrs.uiMaskPlaceholderChar === 'space';
21669                     if(isTemporarilyEmpty) {
21670                         element.val('');
21671                     }
21672                     triggerChangeEvent(element[0]);
21673                     if(isTemporarilyEmpty) {
21674                         element.val(currentVal);
21675                     }
21676                 }
21677                 prevValue = value;
21678             }
21679
21680             function triggerChangeEvent(element) {
21681                 var change;
21682                 if (angular.isFunction(window.Event) && !element.fireEvent) {
21683                     // modern browsers and Edge
21684                     try {
21685                         change = new Event('change', {
21686                             view: window,
21687                             bubbles: true,
21688                             cancelable: false
21689                         });
21690                     } catch (ex) {
21691                         //this is for certain mobile browsers that have the Event object
21692                         //but don't support the Event constructor 
21693                         change = document.createEvent('HTMLEvents');
21694                         change.initEvent('change', false, true);
21695                     } finally {
21696                         element.dispatchEvent(change);
21697                     }
21698                 } else if ('createEvent' in document) {
21699                     // older browsers
21700                     change = document.createEvent('HTMLEvents');
21701                     change.initEvent('change', false, true);
21702                     element.dispatchEvent(change);
21703                 }
21704                 else if (element.fireEvent) {
21705                     // IE <= 11
21706                     element.fireEvent('onchange');
21707                 }
21708             }
21709
21710             function mouseDownUpHandler(e) {
21711                 if (e.type === 'mousedown') {
21712                     element.bind('mouseout', mouseoutHandler);
21713                 } else {
21714                     element.unbind('mouseout', mouseoutHandler);
21715                 }
21716             }
21717
21718             element.bind('mousedown mouseup', mouseDownUpHandler);
21719
21720             function mouseoutHandler() {
21721                 oldSelectionLength = getSelectionLength(this);
21722                 element.unbind('mouseout', mouseoutHandler);
21723             }
21724
21725             function keydownHandler(e) {
21726                 var isKeyBackspace = e.which === 8,
21727                 caretPos = getCaretPosition(this) - 1 || 0, //value in keydown is pre change so bump caret position back to simulate post change
21728                 isCtrlZ = e.which === 90 && e.ctrlKey; //ctrl+z pressed
21729
21730                 if (isKeyBackspace) {
21731                     while(caretPos >= 0) {
21732                         if (isValidCaretPosition(caretPos)) {
21733                             //re-adjust the caret position.
21734                             //Increment to account for the initial decrement to simulate post change caret position
21735                             setCaretPosition(this, caretPos + 1);
21736                             break;
21737                         }
21738                         caretPos--;
21739                     }
21740                     preventBackspace = caretPos === -1;
21741                 }
21742
21743                 if (isCtrlZ) {
21744                     // prevent IE bug - value should be returned to initial state
21745                     element.val('');
21746                     e.preventDefault();
21747                 }
21748             }
21749
21750             function eventHandler(e) {
21751                 e = e || {};
21752                 // Allows more efficient minification
21753                 var eventWhich = e.which,
21754                         eventType = e.type;
21755
21756                 // Prevent shift and ctrl from mucking with old values
21757                 if (eventWhich === 16 || eventWhich === 91) {
21758                     return; 
21759                 }
21760
21761                 var val = element.val(),
21762                         valOld = oldValue,
21763                         valMasked,
21764                         valAltered = false,
21765                         valUnmasked = unmaskValue(val),
21766                         valUnmaskedOld = oldValueUnmasked,
21767                         caretPos = getCaretPosition(this) || 0,
21768                         caretPosOld = oldCaretPosition || 0,
21769                         caretPosDelta = caretPos - caretPosOld,
21770                         caretPosMin = maskCaretMap[0],
21771                         caretPosMax = maskCaretMap[valUnmasked.length] || maskCaretMap.slice().shift(),
21772                         selectionLenOld = oldSelectionLength || 0,
21773                         isSelected = getSelectionLength(this) > 0,
21774                         wasSelected = selectionLenOld > 0,
21775                         // Case: Typing a character to overwrite a selection
21776                         isAddition = (val.length > valOld.length) || (selectionLenOld && val.length > valOld.length - selectionLenOld),
21777                         // Case: Delete and backspace behave identically on a selection
21778                         isDeletion = (val.length < valOld.length) || (selectionLenOld && val.length === valOld.length - selectionLenOld),
21779                         isSelection = (eventWhich >= 37 && eventWhich <= 40) && e.shiftKey, // Arrow key codes
21780
21781                         isKeyLeftArrow = eventWhich === 37,
21782                         // Necessary due to "input" event not providing a key code
21783                         isKeyBackspace = eventWhich === 8 || (eventType !== 'keyup' && isDeletion && (caretPosDelta === -1)),
21784                         isKeyDelete = eventWhich === 46 || (eventType !== 'keyup' && isDeletion && (caretPosDelta === 0) && !wasSelected),
21785                         // Handles cases where caret is moved and placed in front of invalid maskCaretMap position. Logic below
21786                         // ensures that, on click or leftward caret placement, caret is moved leftward until directly right of
21787                         // non-mask character. Also applied to click since users are (arguably) more likely to backspace
21788                         // a character when clicking within a filled input.
21789                         caretBumpBack = (isKeyLeftArrow || isKeyBackspace || eventType === 'click') && caretPos > caretPosMin;
21790
21791                 oldSelectionLength = getSelectionLength(this);
21792
21793                 // These events don't require any action
21794                 if (isSelection || (isSelected && (eventType === 'click' || eventType === 'keyup' || eventType === 'focus'))) {
21795                     return;
21796                 }
21797
21798                 if (isKeyBackspace && preventBackspace) {
21799                     element.val(maskPlaceholder);
21800                     // This shouldn't be needed but for some reason after aggressive backspacing the ctrl $viewValue is incorrect.
21801                     // This keeps the $viewValue updated and correct.
21802                     scope.$apply(function () {
21803                         ctrl.$setViewValue(''); // $setViewValue should be run in angular context, otherwise the changes will be invisible to angular and user code.
21804                     });
21805                     setCaretPosition(this, caretPosOld);
21806                     return;
21807                 }
21808
21809                 // User attempted to delete but raw value was unaffected--correct this grievous offense
21810                 if ((eventType === 'input') && isDeletion && !wasSelected && valUnmasked === valUnmaskedOld) {
21811                     while (isKeyBackspace && caretPos > caretPosMin && !isValidCaretPosition(caretPos)) {
21812                         caretPos--;
21813                     }
21814                     while (isKeyDelete && caretPos < caretPosMax && maskCaretMap.indexOf(caretPos) === -1) {
21815                         caretPos++;
21816                     }
21817                     var charIndex = maskCaretMap.indexOf(caretPos);
21818                     // Strip out non-mask character that user would have deleted if mask hadn't been in the way.
21819                     valUnmasked = valUnmasked.substring(0, charIndex) + valUnmasked.substring(charIndex + 1);
21820
21821                     // If value has not changed, don't want to call $setViewValue, may be caused by IE raising input event due to placeholder
21822                     if (valUnmasked !== valUnmaskedOld)
21823                         valAltered = true;
21824                 }
21825
21826                 // Update values
21827                 valMasked = maskValue(valUnmasked);
21828
21829                 oldValue = valMasked;
21830                 oldValueUnmasked = valUnmasked;
21831
21832                 //additional check to fix the problem where the viewValue is out of sync with the value of the element.
21833                 //better fix for commit 2a83b5fb8312e71d220a497545f999fc82503bd9 (I think)
21834                 if (!valAltered && val.length > valMasked.length)
21835                     valAltered = true;
21836
21837                 element.val(valMasked);
21838
21839                 //we need this check.  What could happen if you don't have it is that you'll set the model value without the user
21840                 //actually doing anything.  Meaning, things like pristine and touched will be set.
21841                 if (valAltered) {
21842                     scope.$apply(function () {
21843                         ctrl.$setViewValue(valMasked); // $setViewValue should be run in angular context, otherwise the changes will be invisible to angular and user code.
21844                     });
21845                 }
21846
21847                 // Caret Repositioning
21848                 // Ensure that typing always places caret ahead of typed character in cases where the first char of
21849                 // the input is a mask char and the caret is placed at the 0 position.
21850                 if (isAddition && (caretPos <= caretPosMin)) {
21851                     caretPos = caretPosMin + 1;
21852                 }
21853
21854                 if (caretBumpBack) {
21855                     caretPos--;
21856                 }
21857
21858                 // Make sure caret is within min and max position limits
21859                 caretPos = caretPos > caretPosMax ? caretPosMax : caretPos < caretPosMin ? caretPosMin : caretPos;
21860
21861                 // Scoot the caret back or forth until it's in a non-mask position and within min/max position limits
21862                 while (!isValidCaretPosition(caretPos) && caretPos > caretPosMin && caretPos < caretPosMax) {
21863                     caretPos += caretBumpBack ? -1 : 1;
21864                 }
21865
21866                 if ((caretBumpBack && caretPos < caretPosMax) || (isAddition && !isValidCaretPosition(caretPosOld))) {
21867                     caretPos++;
21868                 }
21869                 oldCaretPosition = caretPos;
21870                 setCaretPosition(this, caretPos);
21871             }
21872
21873             function isValidCaretPosition(pos) {
21874                 return maskCaretMap.indexOf(pos) > -1;
21875             }
21876
21877             function getCaretPosition(input) {
21878                 if (!input)
21879                     return 0;
21880                 if (input.selectionStart !== undefined) {
21881                     return input.selectionStart;
21882                 } else if (document.selection) {
21883                     if (isFocused(element[0])) {
21884                         // For IE
21885                         input.focus();
21886                         var selection = document.selection.createRange();
21887                         selection.moveStart('character', input.value ? -input.value.length : 0);
21888                         return selection.text.length;
21889                     }
21890                 }
21891                 return 0;
21892             }
21893
21894             function setCaretPosition(input, pos) {
21895                 if (!input)
21896                     return 0;
21897                 if (input.offsetWidth === 0 || input.offsetHeight === 0) {
21898                     return; // Input's hidden
21899                 }
21900                 if (input.setSelectionRange) {
21901                     if (isFocused(element[0])) {
21902                         input.focus();
21903                         input.setSelectionRange(pos, pos);
21904                     }
21905                 }
21906                 else if (input.createTextRange) {
21907                     // For IE
21908                     var range = input.createTextRange();
21909                     range.collapse(true);
21910                     range.moveEnd('character', pos);
21911                     range.moveStart('character', pos);
21912                     range.select();
21913                 }
21914             }
21915
21916             function getSelectionLength(input) {
21917                 if (!input)
21918                     return 0;
21919                 if (input.selectionStart !== undefined) {
21920                     return (input.selectionEnd - input.selectionStart);
21921                 }
21922                 if (window.getSelection) {
21923                     return (window.getSelection().toString().length);
21924                 }
21925                 if (document.selection) {
21926                     return (document.selection.createRange().text.length);
21927                 }
21928                 return 0;
21929             }
21930         }
21931     };
21932 }])
21933 .filter('b2bMultiSepartorHighlight', function($sce) {
21934         return function(text, searchText, searchSeperator) {
21935             var splitText = function(string) {
21936                 if(angular.isDefined(searchSeperator)){
21937                     if (string.indexOf(searchSeperator) > -1) {
21938                         return string.split(searchSeperator);
21939                     } else {
21940                         return string
21941                     }
21942                 }else{
21943                     return string;
21944                 }
21945             }
21946             if (text) {
21947                 var newText = splitText(text);
21948                 var newPhrase = splitText(searchText);
21949                 if (angular.isArray(newPhrase)) {
21950                     for (var i = 0; i < newText.length; i++) {
21951                         if (i <= 0) {
21952                             text = newText[i].replace(new RegExp('(' + newPhrase[i] + ')', 'gi'),
21953                                 '<span class="b2b-search-hightlight">$1</span>');
21954                         } else {
21955                             text = text + searchSeperator + ' ' + (newPhrase[i] ? newText[i].replace(new RegExp('(' + newPhrase[i] + ')', 'gi'),
21956                                 '<span class="b2b-search-hightlight">$1</span>') : newText[i]);
21957                         }
21958                     }
21959                 } else {
21960                     text = text.replace(new RegExp('(' + searchText + ')', 'gi'),
21961                         '<span class="b2b-search-hightlight">$1</span>');
21962                 }
21963             }
21964             return $sce.trustAsHtml(text)
21965         }
21966     })
21967     
21968     .factory('b2bUserAgent', [function() {
21969         var _isMobile = function() {
21970             if(/Android/i.test(navigator.userAgent)){
21971                 return /Mobile/i.test(navigator.userAgent);
21972             }else{
21973                 return /Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
21974             }
21975             
21976         };
21977         var _notMobile = function() {
21978             if(/Android/i.test(navigator.userAgent)){
21979                 return !/Mobile/i.test(navigator.userAgent);
21980             }else{
21981                 return !/Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
21982             }
21983             
21984         };
21985         var _isIE = function() {
21986             return /msie|trident/i.test(navigator.userAgent);
21987         };
21988         var _isFF = function() {
21989             return /Firefox/.test(navigator.userAgent);
21990         };
21991         var _isChrome = function() {
21992             return /Chrome/.test(navigator.userAgent);
21993         };
21994         var _isSafari = function() {
21995             return /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent);
21996         };
21997
21998         return {
21999             isMobile: _isMobile,
22000             notMobile: _notMobile,
22001             isIE: _isIE,
22002             isFF: _isFF,
22003             isChrome: _isChrome,
22004             isSafari: _isSafari
22005         };
22006     }])
22007     .run(['$document', 'b2bUserAgent', function($document, b2bUserAgent) {
22008         var html = $document.find('html').eq(0);
22009         if (b2bUserAgent.isIE()) {
22010             html.addClass('isIE');
22011         } else {
22012             html.removeClass('isIE');
22013         }
22014     }]);
22015     
22016
22017 (function () {
22018     String.prototype.toSnakeCase = function () {
22019         return this.replace(/([A-Z])/g, function ($1) {
22020             return "-" + $1.toLowerCase();
22021         });
22022     };
22023     var concat = function (character, times) {
22024         character = character || '';
22025         times = (!isNaN(times) && times) || 0;
22026         var finalChar = '';
22027         for (var i = 0; i < times; i++) {
22028             finalChar += character;
22029         }
22030         return finalChar;
22031     };
22032
22033     // direction: true for left and false for right
22034     var pad = function (actualString, width, character, direction) {
22035         actualString = actualString || '';
22036         width = (!isNaN(width) && width) || 0;
22037         character = character || '';
22038         if (width > actualString.length) {
22039             if (direction) {
22040                 return concat(character, (width - actualString.length)) + actualString;
22041             } else {
22042                 return actualString + concat(character, (width - actualString.length));
22043             }
22044         }
22045         return actualString;
22046     };
22047
22048     String.prototype.lPad = function (width, character) {
22049         return pad(this, width, character, true);
22050     };
22051
22052     String.prototype.rPad = function (width, character) {
22053         return pad(this, width, character, false);
22054     };
22055
22056     if (!Array.prototype.indexOf) {
22057         Array.prototype.indexOf = function (val) {
22058             for (var index = 0; index < this.length; index++) {
22059                 if (this[index] === val) {
22060                     return index;
22061                 }
22062             }
22063             return -1;
22064         };
22065     }
22066
22067     if (!Array.prototype.regexIndexOf) {
22068         Object.defineProperty(Array.prototype, 'regexIndexOf', {
22069             enumerable: false,
22070             value: function (regex, startIndex, loop) {
22071                 startIndex = startIndex && startIndex > -1 ? startIndex : 0;
22072                 for (var index = startIndex; index < this.length; index++) {
22073                     if (this[index].toString().match(regex)) {
22074                         return index;
22075                     }
22076                 }
22077                 if (loop) {
22078                     for (var index = 0; index < startIndex; index++) {
22079                         if (this[index].toString().match(regex)) {
22080                             return index;
22081                         }
22082                     }
22083                 }
22084                 return -1;
22085             }
22086         })
22087     }
22088 })();
22089 angular.module("b2bTemplate/audioPlayer/audioPlayer.html", []).run(["$templateCache", function($templateCache) {
22090   $templateCache.put("b2bTemplate/audioPlayer/audioPlayer.html",
22091     "<div class=\"b2b-audio\">\n" +
22092     "   <audio preload=\"auto\">\n" +
22093     "           <source ng-src=\"{{audio.mp3 | trustedAudioUrl}}\" type=\"audio/mp3\"></source>\n" +
22094     "           <i>Your browser does not support the audio element.</i>\n" +
22095     "    </audio>\n" +
22096     "\n" +
22097     "    <div audio-play-pause-icon class=\"controls-wrapper\" ng-click=\"toggleAudio()\" tabindex=\"0\" b2b-accessibility-click=\"13,32\" role=\"button\" aria-label=\"{{isPlayInProgress?'pause':'play'}}\">\n" +
22098     "           <i class=\"icoControls-pointer\" ng-show='!isPlayInProgress'></i>\n" +
22099     "           <i class=\"icoControls-pause\" ng-show='isPlayInProgress'></i>\n" +
22100     "    </div>\n" +
22101     "\n" +
22102     "    <div class=\"seek-bar-container-wrapper\">\n" +
22103     "           <b2b-seek-bar min=\"0\" max=\"{{audio.duration}}\" step=\"1\" skip-interval=\"{{audio.timeShiftInSeconds}}\" no-aria-label ng-model=\"audio.currentTime\" on-drag-init=\"isAudioDragging=true\" on-drag-end=\"setAudioPosition(audio.currentTime)\"></b2b-seek-bar>\n" +
22104     "           <div class=\"timing-container\">\n" +
22105     "                   <span class=\"timing-container-left\">{{timeFormatter(audio.currentTime)}}</span>\n" +
22106     "                   <span class=\"timing-container-right\">{{timeFormatter(audio.duration)}}</span>\n" +
22107     "                   <div class=\"timing-container-spacer\"></div>\n" +
22108     "           </div>\n" +
22109     "    </div>\n" +
22110     "           \n" +
22111     "    <b2b-flyout>\n" +
22112     "           <div tabindex=\"0\" b2b-accessibility-click=\"13,32\" role=\"button\" aria-label=\"Volume pop-over. Volume set at {{audio.currentVolume}}%\" class=\"controls-wrapper audio-volume-control\" b2b-flyout-toggler>\n" +
22113     "                   <i class=\"icoControls-mutespeakers\" ng-show=\"audio.currentVolume === 0\"></i>\n" +
22114     "                   <i class=\"icoControls-volumedown\" ng-show=\"audio.currentVolume > 0 && audio.currentVolume <= 50\"></i>\n" +
22115     "                   <i class=\"icoControls-volumeup\" ng-show=\"audio.currentVolume > 50\"></i>\n" +
22116     "           </div> \n" +
22117     "           \n" +
22118     "           <b2b-flyout-content horizontal-placement=\"center\" flyout-style=\"width:70px; height:190px;\" vertical-placement=\"above\">\n" +
22119     "                   <div class=\"b2b-audio-popover text-center\">\n" +
22120     "                           <span>Max</span>\n" +
22121     "                           <b2b-seek-bar min=\"0\" max=\"100\" step=\"1\" skip-interval=\"10\" vertical data-ng-model=\"audio.currentVolume\" class='volume-popover'></b2b-seek-bar>\n" +
22122     "                           <div class=\"min-label\">Min</div>\n" +
22123     "                   </div>\n" +
22124     "           </b2b-flyout-content>\n" +
22125     "   </b2b-flyout>\n" +
22126     "</div>");
22127 }]);
22128
22129 angular.module("b2bTemplate/audioRecorder/audioRecorder.html", []).run(["$templateCache", function($templateCache) {
22130   $templateCache.put("b2bTemplate/audioRecorder/audioRecorder.html",
22131     "<div class=\"b2b-audio-recorder row\">\n" +
22132     "   <div class=\"b2b-elapsed-time span11\">\n" +
22133     "           <div ng-if=\"isRecording\">\n" +
22134     "                   <span style=\"padding-right: 25px;\">{{config.whileRecordingMessage}}</span>\n" +
22135     "                   <span>{{timeFormatter(elapsedTime)}}</span>\n" +
22136     "           </div>\n" +
22137     "           <span ng-if=\"!isRecording\">{{config.startRecordingMessage}}</span>\n" +
22138     "   </div>      \n" +
22139     "   <div class=\"b2b-controls\" title=\"{{isRecording ? 'Stop' : 'REC'}}\" b2b-accessibility-click=\"13,32\" ng-click=\"toggleRecording()\" role=\"button\">\n" +
22140     "           <i ng-if=\"isRecording\" class=\"icoControls-stop\" ></i>\n" +
22141     "           <i ng-if=\"!isRecording\" class=\"icoControls-record\"></i>\n" +
22142     "    </div>\n" +
22143     "</div>");
22144 }]);
22145
22146 angular.module("b2bTemplate/backToTop/backToTop.html", []).run(["$templateCache", function($templateCache) {
22147   $templateCache.put("b2bTemplate/backToTop/backToTop.html",
22148     "<button class=\"btn-arrow b2b-backtotop-button\" type=\"button\" aria-label=\"Back to top\">\n" +
22149     "    <div class=\"btn-secondary b2b-top-btn\">\n" +
22150     "        <i class=\"icoControls-upPRIMARY\" role=\"img\"></i>\n" +
22151     "    </div>\n" +
22152     "</button>\n" +
22153     "");
22154 }]);
22155
22156 angular.module("b2bTemplate/boardstrip/b2bAddBoard.html", []).run(["$templateCache", function($templateCache) {
22157   $templateCache.put("b2bTemplate/boardstrip/b2bAddBoard.html",
22158     "<div tabindex=\"0\" role=\"menuitem\" b2b-accessibility-click=\"13,32\" ng-click=\"addBoard()\" aria-label=\"Add Board\" class=\"boardstrip-item--add\">\n" +
22159     "    <div class=\"centered\"><i aria-hidden=\"true\" class=\"icoControls-add-maximize\"></i> Add board</div>\n" +
22160     "</div> ");
22161 }]);
22162
22163 angular.module("b2bTemplate/boardstrip/b2bBoard.html", []).run(["$templateCache", function($templateCache) {
22164   $templateCache.put("b2bTemplate/boardstrip/b2bBoard.html",
22165     "<li b2b-board-navigation tabindex=\"-1\" role=\"menuitem\" aria-label=\"{{boardLabel}} {{getCurrentIndex()===boardIndex?'selected':''}}\" b2b-accessibility-click=\"13,32\" ng-click=\"selectBoard(boardIndex)\" class=\"board-item\" ng-class=\"{'selected': getCurrentIndex()===boardIndex}\">\n" +
22166     "    <div ng-transclude></div>\n" +
22167     "    <div class=\"board-caret\" ng-if=\"getCurrentIndex()===boardIndex\">\n" +
22168     "        <div class=\"board-caret-indicator\"></div>\n" +
22169     "        <div class=\"board-caret-arrow-up\"></div>\n" +
22170     "    </div>\n" +
22171     "</li>");
22172 }]);
22173
22174 angular.module("b2bTemplate/boardstrip/b2bBoardstrip.html", []).run(["$templateCache", function($templateCache) {
22175   $templateCache.put("b2bTemplate/boardstrip/b2bBoardstrip.html",
22176     "<div class=\"b2b-boardstrip\">\n" +
22177     "   <div class=\"boardstrip-reel\" role=\"menu\">\n" +
22178     "           <div class=\"prev-items\">\n" +
22179     "                   <!-- <i tabindex=\"{{isPrevBoard() ? 0 : -1}}\" ng-class=\"{'disabled': !isPrevBoard()}\" role=\"menuitem\" aria-label=\"See previous boards\" b2b-accessibility-click=\"13,32\" ng-click=\"prevBoard()\" class=\"arrow icoControls-left\"></i> -->\n" +
22180     "                   <button class=\"btn-arrow arrow\" b2b-accessibility-click=\"13,32\" ng-click=\"prevBoard()\" ng-disabled=\"!isPrevBoard()\">\n" +
22181     "                       <div class=\"btn btn-small btn-alt\"><i class=\"icon-primary-left\"></i>\n" +
22182     "                       </div>\n" +
22183     "                       <span class=\"offscreen-text\">Previous boards</span>\n" +
22184     "                   </button>\n" +
22185     "           </div>\n" +
22186     "           <div b2b-add-board on-add-board=\"onAddBoard()\"></div>\n" +
22187     "           <div class=\"board-viewport\"><ul role=\"menu\" class=\"boardstrip-container\" ng-transclude></ul></div>\n" +
22188     "           <div class=\"next-items\">\n" +
22189     "                   <!-- <i tabindex=\"{{isNextBoard() ? 0 : -1}}\" ng-class=\"{'disabled': !isNextBoard()}\" role=\"menuitem\" aria-label=\"See next boards\" b2b-accessibility-click=\"13,32\" ng-click=\"nextBoard()\" class=\"arrow icoControls-right\"></i> -->\n" +
22190     "                   <button class=\"btn-arrow arrow\" b2b-accessibility-click=\"13,32\" ng-click=\"nextBoard()\" ng-disabled=\"!isNextBoard()\">\n" +
22191     "                       <div class=\"btn btn-small btn-alt\"><i class=\"icon-primary-right\"></i>\n" +
22192     "                       </div>\n" +
22193     "                       <span class=\"offscreen-text\">Next boards</span>\n" +
22194     "                   </button>\n" +
22195     "           </div>\n" +
22196     "   </div>\n" +
22197     "</div>\n" +
22198     "");
22199 }]);
22200
22201 angular.module("b2bTemplate/calendar/datepicker-popup.html", []).run(["$templateCache", function($templateCache) {
22202   $templateCache.put("b2bTemplate/calendar/datepicker-popup.html",
22203     "<div id=\"datepicker\" class=\"datepicker dropdown-menu\" ng-class=\"{'datepicker-dropdown datepicker-orient-top': !inline, 'datepicker-orient-left': !inline && orientation === 'left', 'datepicker-orient-right': !inline && orientation === 'right'}\" ng-style=\"{position: inline && 'relative', 'z-index': inline && '0', top: !inline && position.top + 'px' || 0, left: !inline && position.left + 'px'}\" style=\"display: block;\" aria-hidden=\"false\" role=\"dialog\" tabindex=\"-1\" b2b-key type=\"table\" columns=\"7\">\n" +
22204     "    <div class=\"datepicker-days\" style=\"display: block;\">\n" +
22205     "        <div ng-repeat=\"header in headers\" class=\"text-left\" style=\"width: 100%;\" b2b-append-element=\"header\"></div>\n" +
22206     "        <table class=\"table-condensed\">\n" +
22207     "            <thead>\n" +
22208     "                <tr>\n" +
22209     "                    <th id=\"prev\" class=\"prev\" tabindex=\"0\" b2b-accessibility-click=\"13,32\" aria-label=\"Previous Month\" role=\"button\" b2b-element-focus=\"!disablePrev && getFocus\" ng-style=\"{visibility: visibilityPrev}\" ng-click=\"!disablePrev && move(-1,$event)\"><i class=\"icon-primary-left\" aria-hidden=\"true\"></i></th>\n" +
22210     "                    <th id=\"month\" tabindex=\"-1\" aria-label=\"{{title}}\" class=\"datepicker-switch\" colspan=\"{{rows[0].length - 2}}\">{{title}}</th>\n" +
22211     "                    <th id=\"next\" class=\"next\" tabindex=\"0\" b2b-accessibility-click=\"13,32\" b2b-element-focus=\"disablePrev && getFocus\" aria-label=\"Next Month\" role=\"button\" ng-style=\"{visibility: visibilityNext}\" ng-click=\"!disableNext && move(1,$event)\"><i class=\"icon-primary-right\" aria-hidden=\"true\"></i></th>\n" +
22212     "                </tr>\n" +
22213     "                <tr ng-show=\"labels.length > 0\">\n" +
22214     "                    <th id=\"{{label.post}}\" class=\"dow\" ng-repeat=\"label in labels\" aria-hidden=\"true\"><span aria-hidden=\"true\">{{label.pre}}</span></th>\n" +
22215     "                </tr>\n" +
22216     "            </thead>\n" +
22217     "            <tbody>\n" +
22218     "                <tr ng-repeat=\"row in rows\">\n" +
22219     "                    <td headers=\"{{dt.header}}\" b2b-key-item=\"dt.focusable\" b2b-accessibility-click=\"13\" b2b-element-focus=\"disablePrev && disableNext && getFocus && (dt.selected || dt.firstFocus || dt.fromDate || dt.dateRange)\" tabindex=\"{{(!(dt.focusable && (dt.selected || dt.firstFocus || dt.fromDate || currFocus)) && -1) || 0}}\" aria-hidden=\"{{(!dt.focusable && true) || false}}\" role=\"{{(dt.focusable && 'gridcell') || ''}}\" aria-label=\"{{(dt.focusable && dt.date | date : 'EEEE, MMMM d') || ''}}\" aria-selected=\"{{(dt.focusable && (dt.selected || dt.dateRange) && true) || false}}\" ng-repeat=\"dt in row\" class=\"day magic\" ng-class=\"{'active': dt.focusable && dt.selected && !dt.dateRange, 'start-date': dt.focusable && dt.fromDate && dt.dateRange, 'between-date': dt.focusable && !dt.fromDate && !dt.selected && dt.dateRange, 'end-date': dt.focusable && dt.selected && dt.dateRange, 'old': dt.oldMonth, 'new': dt.nextMonth, 'disabled': dt.disabled, 'due-date': dt.dueDate, 'late-fee': dt.pastDue}\" ng-focus=\"currFocus=true; trapFocus();\" ng-blur=\"currFocus=false; trapFocus();\" title=\"{{(dt.focusable && dt.pastDue && legendMessage) || ''}}\" ng-click=\"!ngDisabled && !dt.disabled && select(dt.date)\">\n" +
22220     "                        <div aria-hidden=\"true\" tabindex=\"-1\" class=\"show-date\" ng-if=\"!(dt.oldMonth || dt.nextMonth)\">{{dt.label}}</div>{{(dt.focusable && dt.date | date : 'EEEE, MMMM d yyyy') || ''}}{{(dt.focusable && dt.dueDate && '. Bill-due-date.. ') || ''}}{{(dt.focusable && dt.pastDue && legendMessage) || ''}}</td>\n" +
22221     "                </tr>\n" +
22222     "            </tbody>\n" +
22223     "            <tfoot>\n" +
22224     "                <tr ng-repeat=\"footer in footers\">\n" +
22225     "                    <th colspan=\"7\" class=\"text-left\" style=\"width: 278px;\" b2b-append-element=\"footer\"></th>\n" +
22226     "                </tr>\n" +
22227     "            </tfoot>\n" +
22228     "        </table>\n" +
22229     "    </div>\n" +
22230     "</div>");
22231 }]);
22232
22233 angular.module("b2bTemplate/calendar/datepicker.html", []).run(["$templateCache", function($templateCache) {
22234   $templateCache.put("b2bTemplate/calendar/datepicker.html",
22235     "<div>\n" +
22236     "    <span class=\"icon-primary-calendar span12\" ng-class=\"{'disabled': ngDisabled}\" ng-transclude></span>\n" +
22237     "</div>");
22238 }]);
22239
22240 angular.module("b2bTemplate/coachmark/coachmark.html", []).run(["$templateCache", function($templateCache) {
22241   $templateCache.put("b2bTemplate/coachmark/coachmark.html",
22242     "<div class=\"b2b-coachmark-container\" tabindex=\"-1\" role=\"dialog\" aria-label=\"{{currentCoachmark.contentHeader}} {{currentCoachmark.content}} {{currentCoachmark.offscreenText}}\" ng-style=\"{'top':coackmarkElPos.top,'left':coackmarkElPos.left}\" aria-describeby=\"{{currentCoachmark}}\">\n" +
22243     "   <i class=\"b2b-coachmark-caret\"></i>\n" +
22244     "   <div class=\"b2b-coachmark-header\">\n" +
22245     "           <div class=\"b2b-coachmark-countlabel\"><span ng-if=\"coachmarkIndex !== 0\">{{coachmarkIndex}} of {{(coachmarks.length-1)}}<span></div>\n" +
22246     "           <div class=\"corner-button\">\n" +
22247     "                   <button type=\"button\" ng-focus=\"closeButtonFocus()\" class=\"close\" title=\"close\" aria-label=\"Close\" ng-click=\"closeCoachmark()\"></button>\n" +
22248     "           </div>\n" +
22249     "   </div>\n" +
22250     "   <div class=\"b2b-coachmark-content\">   \n" +
22251     "           <i class=\"icon-misc-dimmer\"></i>\n" +
22252     "           <div class=\"b2b-coachmark-content-header\"><span class=\"offscreen-text\">{{currentCoachmark.offscreenText}}</span>{{currentCoachmark.contentHeader}}</div>\n" +
22253     "           <div class=\"b2b-coachmark-description\">{{currentCoachmark.content}}</div>\n" +
22254     "           <div class=\"b2b-coachmark-btn-group\">\n" +
22255     "                   <a class=\"b2b-coachmark-link\" href=\"javascript:void(0)\" ng-if=\"currentCoachmark.linkLabel !== '' && currentCoachmark.linkLabel !== undefined\" ng-click=\"actionCoachmark(currentCoachmark.linkLabel)\">{{currentCoachmark.linkLabel}}</a>\n" +
22256     "                   <button class=\"btn btn-alt\" ng-if=\"currentCoachmark.buttonLabel !== '' && currentCoachmark.buttonLabel !== undefined\" ng-click=\"actionCoachmark(currentCoachmark.buttonLabel)\">{{currentCoachmark.buttonLabel}}</button>\n" +
22257     "           </div>  \n" +
22258     "   </div>  \n" +
22259     "</div>");
22260 }]);
22261
22262 angular.module("b2bTemplate/dropdowns/b2bDropdownDesktop.html", []).run(["$templateCache", function($templateCache) {
22263   $templateCache.put("b2bTemplate/dropdowns/b2bDropdownDesktop.html",
22264     "<span b2b-key prev=\"38\" next=\"40\" enable-search ng-class=\"{'large': (dropdownSize === 'large'), 'disabled': (disabled), 'selectWrap': (isInputDropdown), 'selectorModule': (dropdownType === 'menu'), 'linkSelectorModule': (dropdownType === 'link-menu')}\">\n" +
22265     "    <input b2b-dropdown-toggle b2b-dropdown-validation ng-disabled=\"disabled\" type=\"text\" id=\"{{dropdownId}}\" name=\"{{dropdownName}}\" class=\"awd-select isWrapped\" ng-required=\"dropdownRequired\" ng-model=\"currentSelected.text\" role=\"combobox\" aria-owns=\"listbox{{$id}}\" aria-expanded=\"{{toggleFlag}}\" ng-click=\"toggleDropdown()\" ng-blur=\"setBlur();\" ng-class=\"{'active': toggleFlag, 'closed': !toggleFlag, 'large': (dropdownSize === 'large')}\" style=\"width:100%;\" value=\"{{currentSelected.text}}\" ng-show=\"isInputDropdown\" aria-describedby=\"{{dropdownDescribedBy}}\" readonly=\"readonly\">\n" +
22266     "    <button type=\"button\" b2b-dropdown-toggle ng-disabled=\"disabled\" class=\"selectModule\" aria-label=\"{{labelText}} {{currentSelected.label}}\" aria-expanded=\"{{toggleFlag}}\" aria-haspopup=\"true\" ng-click=\"toggleDropdown()\" ng-blur=\"setBlur()\" ng-class=\"{'active opened': toggleFlag, 'closed': !toggleFlag, 'large': (dropdownSize === 'large')}\" ng-bind-html=\"currentSelected.text\" ng-show=\"!isInputDropdown\"></button>\n" +
22267     "    <div ng-class=\"{'selectWrapper': (isInputDropdown), 'moduleWrapper': (!isInputDropdown)}\">\n" +
22268     "        <ul id=\"listbox{{$id}}\" role=\"{{isInputDropdown?'listbox':'menu'}}\" ng-class=\"{'awd-select-list': (isInputDropdown), 'awd-module-list': (!isInputDropdown)}\" tabindex=\"-1\" ng-show=\"toggleFlag\" aria-label=\"Choose options\"></ul>\n" +
22269     "        <ul class=\"module-optinalcta\" ng-if=\"toggleFlag && optionalCta\" tabindex=\"-1\" aria-hidden=\"false\">\n" +
22270     "            <li class=\"module-list-item\" tabindex=\"-1\" role=\"menuitem\" value=\"\" aria-label=\"Optinal CTA\" aria-selected=\"true\">\n" +
22271     "                <span class=\"module-data\" b2b-append-element=\"optionalCta\"></span>\n" +
22272     "            </li>\n" +
22273     "        </ul>\n" +
22274     "</div>\n" +
22275     "<i class=\"icon-primary-down\" aria-hidden=\"true\"></i>\n" +
22276     "</span>");
22277 }]);
22278
22279 angular.module("b2bTemplate/dropdowns/b2bDropdownGroupDesktop.html", []).run(["$templateCache", function($templateCache) {
22280   $templateCache.put("b2bTemplate/dropdowns/b2bDropdownGroupDesktop.html",
22281     "<li b2b-dropdown-group-desktop class=\"optgroup-wrapper\">{{groupHeader}}\n" +
22282     "    <ul class=\"optgroup\" role=\"group\" aria-label=\"{{groupHeader}}\"></ul>\n" +
22283     "</li>");
22284 }]);
22285
22286 angular.module("b2bTemplate/dropdowns/b2bDropdownListDesktop.html", []).run(["$templateCache", function($templateCache) {
22287   $templateCache.put("b2bTemplate/dropdowns/b2bDropdownListDesktop.html",
22288     "<li b2b-dropdown-list-desktop b2b-key-item b2b-accessibility-click=\"13\" aria-selected=\"{{currentSelected.value === dropdownListValue}}\" data-hover=\"{{dropdown.highlightedValue === dropdownListValue}}\" ng-class=\"{'awd-select-list-item': (isInputDropdown), 'module-list-item': (!isInputDropdown)}\" tabindex=\"0\" role=\"{{isInputDropdown?'option':'menuitem'}}\" ng-click=\"selectDropdownItem()\" ng-focus=\"highlightDropdown()\"></li>");
22289 }]);
22290
22291 angular.module("b2bTemplate/fileUpload/fileUpload.html", []).run(["$templateCache", function($templateCache) {
22292   $templateCache.put("b2bTemplate/fileUpload/fileUpload.html",
22293     "<label class=\"b2b-file-container\">\n" +
22294     "   <span class=\"b2b-upload-link\" ng-transclude></span>\n" +
22295     "   <input type=\"file\" b2b-file-change>\n" +
22296     "</label>");
22297 }]);
22298
22299 angular.module("b2bTemplate/flyout/flyout.html", []).run(["$templateCache", function($templateCache) {
22300   $templateCache.put("b2bTemplate/flyout/flyout.html",
22301     "<span class=\"b2b-flyout\"  b2b-flyout-trap-focus-inside>\n" +
22302     "    <span ng-transclude></span>\n" +
22303     "</span>");
22304 }]);
22305
22306 angular.module("b2bTemplate/flyout/flyoutContent.html", []).run(["$templateCache", function($templateCache) {
22307   $templateCache.put("b2bTemplate/flyout/flyoutContent.html",
22308     "<div class=\"b2b-flyout-container\" aria-live=\"polite\" aria-atomic=\"false\" ng-class=\"{'b2b-flyout-left':horizontalPlacement==='left',\n" +
22309     "                'b2b-flyout-center':horizontalPlacement==='center', \n" +
22310     "                'b2b-flyout-right':horizontalPlacement==='right',\n" +
22311     "                'b2b-flyout-centerLeft':horizontalPlacement==='centerLeft',\n" +
22312     "                'b2b-flyout-centerRight':horizontalPlacement==='centerRight',  \n" +
22313     "                'b2b-flyout-above':verticalPlacement==='above', \n" +
22314     "                'b2b-flyout-below':verticalPlacement==='below',\n" +
22315     "                'open-flyout': openFlyout,\n" +
22316     "                'b2b-close-flyout': !openFlyout}\">\n" +
22317     "    <i class=\"b2b-flyout-caret\" ng-class=\"{'open-flyout': openFlyout, \n" +
22318     "                                   'b2b-flyout-caret-above':verticalPlacement==='above',\n" +
22319     "                                   'b2b-flyout-caret-below':verticalPlacement==='below'}\"></i>\n" +
22320     "    <span ng-transclude></span>\n" +
22321     "</div>");
22322 }]);
22323
22324 angular.module("b2bTemplate/footer/footer_column_switch_tpl.html", []).run(["$templateCache", function($templateCache) {
22325   $templateCache.put("b2bTemplate/footer/footer_column_switch_tpl.html",
22326     "<div class=\"footer-columns \" ng-class=\"{'five-column':footerColumns===5, 'four-column':footerColumns===4, 'three-column':footerColumns===3}\" ng-repeat=\"item in footerLinkItems\">\n" +
22327     "    <h3 class=\"b2b-footer-header\">{{item.categoryName}}</h3>\n" +
22328     "    <ul>\n" +
22329     "        <li ng-repeat=\"i in item.values\">\n" +
22330     "            <a href=\"{{i.href}}\" title=\"{{item.categoryName}} - {{i.displayLink}}\">{{i.displayLink}}</a>  \n" +
22331     "        </li>\n" +
22332     "    </ul>\n" +
22333     "\n" +
22334     "</div>\n" +
22335     "\n" +
22336     "<div ng-transclude></div>\n" +
22337     "");
22338 }]);
22339
22340 angular.module("b2bTemplate/horizontalTable/horizontalTable.html", []).run(["$templateCache", function($templateCache) {
22341   $templateCache.put("b2bTemplate/horizontalTable/horizontalTable.html",
22342     "<div class=\"b2b-horizontal-table\">\n" +
22343     "    <div class=\"b2b-horizontal-table-arrows row span12\">\n" +
22344     "        <div class=\"span4 b2b-prev-link\">\n" +
22345     "            <a href=\"javascript:void(0)\" ng-click=\"moveViewportLeft()\" ddh-accessibility-click=\"13,32\" ng-if=\"!disableLeft\">Previous</a>\n" +
22346     "            <span ng-if=\"disableLeft\" class=\"b2b-disabled-text\">Previous</span>\n" +
22347     "        </div>\n" +
22348     "        \n" +
22349     "        <span class=\"span5 b2b-horizontal-table-column-info\" aria-live=\"polite\" tabindex=\"-1\">\n" +
22350     "            Showing {{countDisplayText}} {{getColumnSet()[0]+1}}-{{getColumnSet()[1]+1}} of {{numOfCols}} columns\n" +
22351     "        </span>\n" +
22352     "\n" +
22353     "        <div ng-if=\"legendContent\" class=\"span2 b2b-horizontal-table-legend\">\n" +
22354     "           | <b2b-flyout>\n" +
22355     "                <div tabindex=\"0\" role=\"button\" aria-haspopup=\"true\" b2b-flyout-toggler b2b-accessibility-click=\"13,32\" aria-expanded=\"{{flyoutOpened ? 'true' : 'false'}}\">\n" +
22356     "                    Legend\n" +
22357     "                    <i class=\"icoControls-down\" role=\"img\"></i>\n" +
22358     "                </div>\n" +
22359     "              <b2b-flyout-content horizontal-placement=\"center\" vertical-placement=\"below\">\n" +
22360     "                <div ng-bind-html=\"legendContent\"></div>\n" +
22361     "              </b2b-flyout-content>\n" +
22362     "            </b2b-flyout>\n" +
22363     "        </div>\n" +
22364     "        \n" +
22365     "        <div class=\"span3 text-right b2b-next-link\">\n" +
22366     "            <a href=\"javascript:void(0)\" ng-click=\"moveViewportRight()\" ddh-accessibility-click=\"13,32\" ng-if=\"!disableRight\">Next</a>\n" +
22367     "            <span ng-if=\"disableRight\" class=\"b2b-disabled-text\">Next</span>\n" +
22368     "        </div>\n" +
22369     "    </div>\n" +
22370     "    <div class=\"b2b-horizontal-table-inner-container\">\n" +
22371     "        <span ng-transclude></span>\n" +
22372     "    </div>\n" +
22373     "</div>");
22374 }]);
22375
22376 angular.module("b2bTemplate/hourPicker/b2bHourpicker.html", []).run(["$templateCache", function($templateCache) {
22377   $templateCache.put("b2bTemplate/hourPicker/b2bHourpicker.html",
22378     "<div class=\"hp-container\">\n" +
22379     "    <div class=\"hp-selected\">\n" +
22380     "        <div b2b-hourpicker-value=\"$index\" days=\"value.days\" start-time=\"value.startTime\" start-meridiem=\"value.startMeridiem\" end-time=\"value.endTime\" end-meridiem=\"value.endMeridiem\" ng-repeat=\"value in finalHourpickerValues\"></div>\n" +
22381     "    </div>\n" +
22382     "    <div b2b-hourpicker-panel></div>\n" +
22383     "</div>");
22384 }]);
22385
22386 angular.module("b2bTemplate/hourPicker/b2bHourpickerPanel.html", []).run(["$templateCache", function($templateCache) {
22387   $templateCache.put("b2bTemplate/hourPicker/b2bHourpickerPanel.html",
22388     "<form name=\"{{'hourpickerForm' + $id}}\">\n" +
22389     "    <div class=\"hp-checkbox\" role=\"group\">\n" +
22390     "        <label class=\"checkbox\" for=\"checkbox_{{dayOption.title}}_{{$id}}\" ng-repeat=\"dayOption in hourpicker.dayOptions\">\n" +
22391     "            <input type=\"checkbox\" id=\"checkbox_{{dayOption.title}}_{{$id}}\" name=\"{{'hourpickerDays' + $id}}\" ng-model=\"hourpickerPanelValue.days[$index].value\" ng-disabled=\"dayOption.disabled\" /><i class=\"skin\"></i><span>{{dayOption.label}}</span>\n" +
22392     "        </label>\n" +
22393     "    </div>\n" +
22394     "    <div class=\"row hp-dropdowns\">\n" +
22395     "        <div class=\"span4\">\n" +
22396     "            <label for=\"{{'hourpickerStartTime' + $id}}\">From</label>\n" +
22397     "            <select id=\"{{'hourpickerStartTime' + $parent.$id}}\" b2b-dropdown type=\"\" ng-model=\"hourpickerPanelValue.startTime\">\n" +
22398     "                <option b2b-dropdown-list value=\"\">From</option>\n" +
22399     "                <option b2b-dropdown-list option-repeat=\"startTimeOption in hourpicker.startTimeOptions\" value=\"{{startTimeOption}}\">{{startTimeOption}}</option>\n" +
22400     "            </select>\n" +
22401     "        </div>\n" +
22402     "        <div class=\"span8 radio-buttons\" role=\"radiogroup\" aria-label=\"Select AM or PM\">\n" +
22403     "            <label class=\"radio\" for=\"hourpickerStartMeridiem_AM_{{$id}}\">\n" +
22404     "                <input type=\"radio\" id=\"hourpickerStartMeridiem_AM_{{$id}}\" name=\"{{'hourpickerStartMeridiem' + $id}}\" value=\"am\" ng-model=\"hourpickerPanelValue.startMeridiem\" /><i class=\"skin\"></i><span>AM</span>\n" +
22405     "            </label>\n" +
22406     "            <label class=\"radio\" for=\"hourpickerStartMeridiem_PM_{{$id}}\">\n" +
22407     "                <input type=\"radio\" id=\"hourpickerStartMeridiem_PM_{{$id}}\" name=\"{{'hourpickerStartMeridiem' + $id}}\" value=\"pm\" ng-model=\"hourpickerPanelValue.startMeridiem\" /><i class=\"skin\"></i><span>PM</span>\n" +
22408     "            </label>\n" +
22409     "        </div>\n" +
22410     "    </div>\n" +
22411     "    <div class=\"row hp-dropdowns\">\n" +
22412     "        <div class=\"span4\">\n" +
22413     "            <label for=\"{{'hourpickerEndTime' + $id}}\">To</label>\n" +
22414     "            <select id=\"{{'hourpickerEndTime' + $parent.$id}}\" b2b-dropdown ng-model=\"hourpickerPanelValue.endTime\">\n" +
22415     "                <option b2b-dropdown-list value=\"\">To</option>\n" +
22416     "                <option b2b-dropdown-list option-repeat=\"endTimeOption in hourpicker.endTimeOptions\" value=\"{{endTimeOption}}\">{{endTimeOption}}</option>\n" +
22417     "            </select>\n" +
22418     "        </div>\n" +
22419     "        <div class=\"span8 radio-buttons\" role=\"radiogroup\" aria-label=\"Select AM or PM\">\n" +
22420     "            <label class=\"radio\" for=\"hourpickerEndMeridiem_AM_{{$id}}\">\n" +
22421     "                <input type=\"radio\" id=\"hourpickerEndMeridiem_AM_{{$id}}\" name=\"{{'hourpickerEndMeridiem' + $id}}\" value=\"am\" ng-model=\"hourpickerPanelValue.endMeridiem\" /><i class=\"skin\"></i><span>AM</span>\n" +
22422     "            </label>\n" +
22423     "            <label class=\"radio\" for=\"hourpickerEndMeridiem_PM_{{$id}}\">\n" +
22424     "                <input type=\"radio\" id=\"hourpickerEndMeridiem_PM_{{$id}}\" name=\"{{'hourpickerEndMeridiem' + $id}}\" value=\"pm\" ng-model=\"hourpickerPanelValue.endMeridiem\" /><i class=\"skin\"></i><span>PM</span>\n" +
22425     "            </label>\n" +
22426     "        </div>\n" +
22427     "    </div>\n" +
22428     "    <div class=\"row hp-buttons\">\n" +
22429     "        <div class=\"span12\">\n" +
22430     "            <div style=\"float:right\">\n" +
22431     "                <button class=\"btn btn-secondary btn-small\" ng-click=\"resetHourpickerPanelValue()\">Clear</button>\n" +
22432     "                <button class=\"btn btn-alt btn-small\" ng-disabled = \"disableAddBtn\" ng-click=\"updateHourpickerValue()\">{{hourpicker.editMode > -1 ? 'Update' : 'Add'}}</button>\n" +
22433     "            </div>\n" +
22434     "        </div>\n" +
22435     "    </div>\n" +
22436     "</form>");
22437 }]);
22438
22439 angular.module("b2bTemplate/hourPicker/b2bHourpickerValue.html", []).run(["$templateCache", function($templateCache) {
22440   $templateCache.put("b2bTemplate/hourPicker/b2bHourpickerValue.html",
22441     "<div class=\"selected-days\">\n" +
22442     "    <span class=\"day\">{{hourpickerValue.days}} &nbsp; {{hourpickerValue.startTime}} {{hourpickerValue.startMeridiem}} - {{hourpickerValue.endTime}} {{hourpickerValue.endMeridiem}}</span>\n" +
22443     "    <span style=\"float:right\">\n" +
22444     "        <i class=\"icon-misc-pen\" role=\"button\" aria-label=\"Edit {{hourpickerValue.days}} {{hourpickerValue.startTime}} {{hourpickerValue.startMeridiem}} - {{hourpickerValue.endTime}} {{hourpickerValue.endMeridiem}}\" title=\"Edit\" tabindex=\"0\" b2b-accessibility-click=\"13,32\" ng-click=\"editHourpickerValue(hourpickerValue.index)\"></i>\n" +
22445     "        <i class=\"icon-misc-trash\" role=\"button\" aria-label=\"Delete {{hourpickerValue.days}} {{hourpickerValue.startTime}} {{hourpickerValue.startMeridiem}} - {{hourpickerValue.endTime}} {{hourpickerValue.endMeridiem}}\" title=\"Delete\" tabindex=\"0\" b2b-accessibility-click=\"13,32\" ng-click=\"deleteHourpickerValue(hourpickerValue.index)\"></i>\n" +
22446     "    </span>\n" +
22447     "    <div style=\"clear:both\"></div>\n" +
22448     "</div>");
22449 }]);
22450
22451 angular.module("b2bTemplate/leftNavigation/leftNavigation.html", []).run(["$templateCache", function($templateCache) {
22452   $templateCache.put("b2bTemplate/leftNavigation/leftNavigation.html",
22453     "<div class=\"b2b-nav-menu\">\n" +
22454     "    <div class=\"b2b-subnav-container\">\n" +
22455     "        <ul class=\"b2b-subnav-content\">\n" +
22456     "            <li ng-repeat=\"menu in menuData\" ng-click=\"toggleNav($index)\"><a ng-class=\"{'expand': idx==$index}\" aria-label=\"{{menu.name}}\" title=\" \" aria-expanded=\"{{(idx==$index)?true:false;}}\" href=\"javascript:void(0);\">{{menu.name}}<i class=\"b2b-icon-primary-plus-minus\" ng-class=\"idx==$index ? 'icon-primary-expanded' : 'icon-primary-collapsed'\"></i></a>\n" +
22457     "                <ul ng-class=\"{expand: idx==$index}\">\n" +
22458     "                    <li ng-repeat=\"menuItem in menu.menuItems\" ng-click=\"liveLink($event, $index, $parent.$index)\"><a aria-hidden=\"{{!(idx==$parent.$index)}}\" aria-label=\"{{menuItem.name}}\" title=\" \" href=\"{{menuItem.href}}\" tabindex=\"{{(idx==$parent.$index)?0:-1;}}\" ng-class=\"{active: itemIdx==$index && navIdx==$parent.$index}\">{{menuItem.name}}</a></li>\n" +
22459     "                </ul>\n" +
22460     "            </li>\n" +
22461     "        </ul>\n" +
22462     "    </div>\n" +
22463     "</div>");
22464 }]);
22465
22466 angular.module("b2bTemplate/listbox/listbox.html", []).run(["$templateCache", function($templateCache) {
22467   $templateCache.put("b2bTemplate/listbox/listbox.html",
22468     "<div class=\"b2b-list-box\" tabindex=\"0\" role=\"listbox\" ng-transclude>\n" +
22469     "</div>");
22470 }]);
22471
22472 angular.module("b2bTemplate/modalsAndAlerts/b2b-backdrop.html", []).run(["$templateCache", function($templateCache) {
22473   $templateCache.put("b2bTemplate/modalsAndAlerts/b2b-backdrop.html",
22474     "<div class=\"b2b-modal-backdrop fade in hidden-by-modal\" aria-hidden=\"true\" tabindex=\"-1\"></div>");
22475 }]);
22476
22477 angular.module("b2bTemplate/modalsAndAlerts/b2b-window.html", []).run(["$templateCache", function($templateCache) {
22478   $templateCache.put("b2bTemplate/modalsAndAlerts/b2b-window.html",
22479     "<div class=\"modalwrapper active {{windowClass}}\" ng-class=\"{'modal-landscape': isModalLandscape}\" role=\"{{isNotifDialog?'alertdialog':'dialog'}}\" tabindex=\"-1\" aria-labelledby=\"{{title}}\" aria-describedby=\"{{content}}\">\n" +
22480     "    <div class=\"modal fade in {{sizeClass}}\" ng-transclude></div>\n" +
22481     "</div>");
22482 }]);
22483
22484 angular.module("b2bTemplate/monthSelector/monthSelector-popup.html", []).run(["$templateCache", function($templateCache) {
22485   $templateCache.put("b2bTemplate/monthSelector/monthSelector-popup.html",
22486     "<div id=\"monthselector{{$id}}\" class=\"datepicker dropdown-menu monthselector\" \n" +
22487     "     ng-class=\"{'datepicker-dropdown datepicker-orient-top': !inline, 'datepicker-orient-left': !inline && orientation === 'left', 'datepicker-orient-right': !inline && orientation === 'right'}\" \n" +
22488     "     ng-style=\"{position: inline && 'relative', 'z-index': inline && '0', top: !inline && position.top + 'px' || 0, left: !inline && position.left + 'px'}\" \n" +
22489     "     style=\"display: block;\" aria-hidden=\"false\" role=\"dialog presentation\" tabindex=\"-1\">\n" +
22490     "    <div class=\"datepicker-days\" style=\"display: block;\">\n" +
22491     "        <span class=\"offscreen-text\" aria-live=\"polite\" aria-atomic=\"true\">{{title}} displaying</span>\n" +
22492     "        <table class=\"table-condensed\" role=\"grid\">\n" +
22493     "            <thead>\n" +
22494     "                <tr ng-repeat=\"header in headers\">\n" +
22495     "                    <th colspan=\"7\" class=\"text-left\" style=\"width: 278px;\" b2b-append-element=\"header\"></th>\n" +
22496     "                </tr>\n" +
22497     "                <tr>\n" +
22498     "                    <th id=\"prev{{$id}}\" role=\"button\" tabindex=\"0\" b2b-accessibility-click=\"13\" aria-label=\"Previous Year\" ng-class=\"{'prev': !disablePrev}\" ng-style=\"{visibility: visibilityPrev}\" ng-click=\"!disablePrev && move(-1,$event)\"><i class=\"icon-primary-left\"></i></th>\n" +
22499     "                    <th id=\"year{{$id}}\" role=\"heading\" tabindex=\"-1\" aria-label=\"{{title}}\" class=\"datepicker-switch b2b-monthSelector-label\" colspan=\"{{rows[0].length - 2}}\">{{title}}</th>\n" +
22500     "                    <th id=\"next{{$id}}\" role=\"button\" tabindex=\"0\" b2b-accessibility-click=\"13\" aria-label=\"Next Year\" ng-class=\"{'next': !disableNext}\" ng-style=\"{visibility: visibilityNext}\" ng-click=\"!disableNext && move(1,$event)\"><i class=\"icon-primary-right\"></i></th>\n" +
22501     "                </tr>\n" +
22502     "                <tr ng-show=\"labels.length > 0\">\n" +
22503     "                    <th id=\"{{label.post}}\" class=\"dow\" ng-repeat=\"label in labels\" aria-hidden=\"true\"><span aria-hidden=\"true\">{{label.pre}}</span></th>\n" +
22504     "                </tr>\n" +
22505     "            </thead>\n" +
22506     "            <tbody b2b-key type=\"table\" columns=\"4\" >\n" +
22507     "                <tr ng-repeat=\"row in rows\">\n" +
22508     "                    <td headers=\"{{dt.header}}\" b2b-key-item=\"dt.focusable\" b2b-accessibility-click=\"13,32\" tabindex=\"{{(!(dt.focusable && (dt.selected || dt.firstFocus || currFocus)) && -1) || 0}}\" aria-hidden=\"{{(!dt.focusable && true) || false}}\" role=\"{{(dt.focusable && 'gridcell') || ''}}\" aria-label=\"{{(dt.focusable && dt.date | date : 'MMMM, y') || ''}}\" aria-selected=\"{{(dt.focusable && (dt.selected || dt.dateRange) && true) || false}}\" ng-repeat=\"dt in row\" class=\"day magic\" ng-class=\"{'active': dt.focusable && dt.selected && !dt.dateRange, 'start-date': dt.focusable && dt.fromDate && dt.dateRange, 'between-date': dt.focusable && !dt.fromDate && !dt.selected && dt.dateRange, 'end-date': dt.focusable && dt.selected && dt.dateRange, 'old': dt.oldMonth, 'new': dt.nextMonth, 'disabled': dt.disabled, 'due-date': dt.dueDate, 'late-fee': dt.pastDue}\" ng-focus=\"currFocus=true\" ng-blur=\"currFocus=false\" title=\"{{(dt.focusable && dt.pastDue && legendMessage) || ''}}\" b2b-element-focus=\"inline && dt.focusable && dt.selected && !dt.dateRange\" ng-click=\"!ngDisabled && !dt.disabled && select(dt.date)\">\n" +
22509     "                        <div aria-hidden=\"true\"  tabindex=\"-1\" class=\"show-date\" ng-if=\"!(dt.oldMonth || dt.nextMonth)\">{{dt.label | limitTo: 3}}</div>\n" +
22510     "                    </td>\n" +
22511     "                </tr>\n" +
22512     "            </tbody>\n" +
22513     "            <tfoot>\n" +
22514     "                <tr ng-repeat=\"footer in footers\">\n" +
22515     "                    <th colspan=\"7\" class=\"text-left\" b2b-append-element=\"footer\"></th>\n" +
22516     "                </tr>\n" +
22517     "            </tfoot>\n" +
22518     "        </table>\n" +
22519     "    </div>\n" +
22520     "</div>");
22521 }]);
22522
22523 angular.module("b2bTemplate/monthSelector/monthSelector.html", []).run(["$templateCache", function($templateCache) {
22524   $templateCache.put("b2bTemplate/monthSelector/monthSelector.html",
22525     "<div>\n" +
22526     "    <span class=\"icon-primary-calendar span12\" ng-class=\"{'disabled': ngDisabled}\" ng-transclude></span>\n" +
22527     "</div>");
22528 }]);
22529
22530 angular.module("b2bTemplate/monthSelector/monthSelectorLink.html", []).run(["$templateCache", function($templateCache) {
22531   $templateCache.put("b2bTemplate/monthSelector/monthSelectorLink.html",
22532     "<div>\n" +
22533     "    <span class=\"span12\" ng-transclude></span>\n" +
22534     "</div>");
22535 }]);
22536
22537 angular.module("b2bTemplate/pagination/b2b-pagination.html", []).run(["$templateCache", function($templateCache) {
22538   $templateCache.put("b2bTemplate/pagination/b2b-pagination.html",
22539     "<div class=\"b2b-pager\">\n" +
22540     "    <div ng-if=\"notMobile && totalPages > 1\">\n" +
22541     "        <a  tabindex=\"{{currentPage <= 1 ? -1 : 0 }}\" class=\"b2b-pager__item--prev\" b2b-accessibility-click=\"13,32\" title=\"Previous Page\" ng-click=\"prev($event)\" ng-if=\"totalPages > 10\" ng-class=\"currentPage <= 1 ? 'b2b-pager__item--prev-disabled': '' \">\n" +
22542     "            <i class=\"icon-primary-left\"></i>\n" +
22543     "        </a>\n" +
22544     "        <a droppable=\"{{droppableAttribute}}\" tabindex=\"{{currentPage === 1 ? -1 : 0}}\" ng-class=\"{'b2b-pager__item--noclick': currentPage === 1}\" class=\"b2b-pager__item b2b-pager__item--link\" title=\"Page 1{{checkSelectedPage(page) ? ' selected' : '' }}\" ng-if=\"totalPages > 10 && currentPage > 6\" b2b-accessibility-click=\"13,32\" ng-click=\"selectPage(1, $event)\" aria-atomic=\"true\" aria-live=\"polite\">\n" +
22545     "            1<span class=\"offscreen-text\" ng-if=\"currentPage === 1\"> is selected</span>\n" +
22546     "        </a>\n" +
22547     "\n" +
22548     "        <span class=\"b2b-pager__item\" ng-if=\"totalPages > 10 && currentPage > 6\">...</span>\n" +
22549     "\n" +
22550     "        <a droppable=\"{{droppableAttribute}}\" tabindex=\"{{checkSelectedPage(page) ? -1 : 0}}\" href=\"javascript:void(0);\" class=\"b2b-pager__item b2b-pager__item--link\" title=\"Page {{page}}\" b2b-element-focus=\"isFocused(page)\" ng-repeat=\"page in pages\" ng-class=\"{'b2b-pager__item--active': checkSelectedPage(page), 'b2b-pager__item--noclick': checkSelectedPage(page),'b2b-pager__item--droppable': droppableAttribute == true}\" b2b-accessibility-click=\"13,32\" ng-click=\"!checkSelectedPage(page) && selectPage(page, $event)\" aria-atomic=\"true\" aria-live=\"polite\">\n" +
22551     "            {{page}}<span class=\"offscreen-text\" ng-if=\"checkSelectedPage(page)\"> is selected</span>\n" +
22552     "        </a>\n" +
22553     "\n" +
22554     "        <span class=\"b2b-pager__item\" ng-if=\"totalPages > 10 && currentPage <= (totalPages - boundary)\">...</span>\n" +
22555     "\n" +
22556     "        <a droppable=\"{{droppableAttribute}}\" tabindex=\"{{currentPage === totalPages ? -1 : 0}}\" href=\"javascript:void(0);\" ng-class=\"{'b2b-pager__item--noclick': currentPage === totalPages}\" class=\"b2b-pager__item b2b-pager__item--link\" title=\"Page {{totalPages}}\" ng-if=\"totalPages > 10 && currentPage <= (totalPages - boundary)\" b2b-accessibility-click=\"13,32\" ng-click=\"selectPage(totalPages, $event)\" aria-atomic=\"true\" aria-live=\"polite\">\n" +
22557     "          {{totalPages}}<span class=\"offscreen-text\" ng-if=\"checkSelectedPage(page)\"> is selected</span>\n" +
22558     "        </a>\n" +
22559     "\n" +
22560     "\n" +
22561     "        <a tabindex=\"{{currentPage >= totalPages ? -1 : 0 }}\" href=\"javascript:void(0);\" class=\"b2b-pager__item--next\" b2b-accessibility-click=\"13,32\" title=\"Next Page\" ng-click=\"next($event)\" ng-if=\"totalPages > 10\" ng-class=\"currentPage >= totalPages ? 'b2b-pager__item--next-disabled' :'' \">\n" +
22562     "            <i class=\"icon-primary-right\"></i>\n" +
22563     "        </a>\n" +
22564     "        \n" +
22565     "        <div class=\"fieldLabel b2b-go-to-page\" ng-class=\"{'b2b-go-to-page-inline' : inputClass !== undefined }\" ng-show=\"totalPages > 20\">    \n" +
22566     "            <label for=\"{{inputId}}\">Go to Page:</label>\n" +
22567     "            <input id=\"{{inputId}}\" class=\"b2b-pager__item--input\" type=\"number\" ng-blur=\"onfocusOut($event)\" ng-focus=\"onfocusIn($event)\" ng-keypress=\"gotoKeyClick($event)\" b2b-only-nums=\"4\" ng-model=\"$parent.gotoPage\" />\n" +
22568     "            <button class=\"btn-arrow\" ng-click=\"gotoBtnClick()\" ng-disabled=\"$parent.gotoPage !== 0 || $parent.gotoPage !== undefined\" aria-label=\"Go to\">\n" +
22569     "                <div class=\"btn btn-small btn-secondary\">\n" +
22570     "                    <i class=\"icon-primary-right\"></i>\n" +
22571     "                </div>\n" +
22572     "            </button>\n" +
22573     "        </div>\n" +
22574     "    </div>\n" +
22575     "    <div ng-if=\"isMobile && totalPages > 1\" ng-swipe-right=\"prev()\" ng-swipe-left=\"next()\" ng-class=\"isMobile ? 'b2b-mobile-view': '' \">\n" +
22576     "        <a droppable=\"{{droppableAttribute}}\" tabindex=\"{{checkSelectedPage(page) ? -1 : 0}}\" href=\"javascript:void(0);\" class=\"b2b-pager__item b2b-pager__item--link\" title=\"Page {{page}}\" b2b-element-focus=\"isFocused(page)\" ng-repeat=\"page in pages\" ng-class=\"{'b2b-pager__item--active': checkSelectedPage(page), fade1: ($index == 0 && currentPage > meanVal+1),  fade2: ($index == 1 && currentPage > meanVal+1), fadesl: ($index == pages.length-2 && currentPage < totalPages - meanVal),  fadel: ($last && currentPage < totalPages - meanVal), 'b2b-pager__item--noclick': checkSelectedPage(page)}\" b2b-accessibility-click=\"13,32\" ng-click=\"selectPage(page, $event)\">{{page}}</a>\n" +
22577     "    </div>\n" +
22578     "</div>\n" +
22579     "");
22580 }]);
22581
22582 angular.module("b2bTemplate/paneSelector/paneSelector.html", []).run(["$templateCache", function($templateCache) {
22583   $templateCache.put("b2bTemplate/paneSelector/paneSelector.html",
22584     "<div class=\"panes\" ng-transclude></div>");
22585 }]);
22586
22587 angular.module("b2bTemplate/paneSelector/paneSelectorPane.html", []).run(["$templateCache", function($templateCache) {
22588   $templateCache.put("b2bTemplate/paneSelector/paneSelectorPane.html",
22589     "<div class=\"pane-block\" ng-transclude></div>");
22590 }]);
22591
22592 angular.module("b2bTemplate/profileCard/profileCard-addUser.html", []).run(["$templateCache", function($templateCache) {
22593   $templateCache.put("b2bTemplate/profileCard/profileCard-addUser.html",
22594     "<div  class=\"span3 b2b-profile-card b2b-add-user\">\n" +
22595     "    <div class=\"atcenter\">\n" +
22596     "        <div class=\"circle\"><i class=\"icon-primary-add-maximize\"></i></div>\n" +
22597     "        <div>Create new user</div>\n" +
22598     "    </div>\n" +
22599     "</div>");
22600 }]);
22601
22602 angular.module("b2bTemplate/profileCard/profileCard.html", []).run(["$templateCache", function($templateCache) {
22603   $templateCache.put("b2bTemplate/profileCard/profileCard.html",
22604     "<div class=\"span3 b2b-profile-card\">\n" +
22605     "    <div class=\"top-block\">\n" +
22606     "       <div class=\"profile-image\">\n" +
22607     "            <img ng-if=\"image\" profile-name=\"{{profile.name}}\" ng-src=\"{{profile.img}}\" alt=\"{{profile.name}}\">\n" +
22608     "            <span ng-if=\"!image\" class=\"default-img\">{{initials}}</span>\n" +
22609     "\n" +
22610     "            <h4 class=\"name\">{{profile.name}}</h4>\n" +
22611     "\n" +
22612     "            <p class=\"status\">\n" +
22613     "                <span class=\"status-icon\" ng-class=\"{'status-green':colorIcon==='green','status-red':colorIcon==='red','status-blue':colorIcon==='blue','status-yellow':colorIcon==='yellow'}\">   \n" +
22614     "                </span>\n" +
22615     "                <span>{{profile.state}}<span ng-if=\"badge\" class=\"status-badge\">Admin</span></span>\n" +
22616     "            </p>\n" +
22617     "        </div>\n" +
22618     "    </div>\n" +
22619     "    <div class=\"bottom-block\">\n" +
22620     "         <div class=\"profile-details\">\n" +
22621     "            <label>Username</label>\n" +
22622     "            <div ng-if=\"shouldClip(profile.userName)\" ng-mouseover=\"showUserNameTooltip = true;\" ng-mouseleave=\"showUserNameTooltip = false;\">\n" +
22623     "                <div ng-if=\"shouldClip(profile.userName)\" class=\"tooltip\" b2b-tooltip show-tooltip=\"showUserNameTooltip\">\n" +
22624     "                    {{profile.userName.slice(0, 25)+'...'}}\n" +
22625     "                    <div class=\"arrow\"></div>\n" +
22626     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +
22627     "                        <div class=\"tooltip-size-control\">\n" +
22628     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +
22629     "                                {{profile.userName}}\n" +
22630     "                            </div>\n" +
22631     "                        </div>\n" +
22632     "                    </div>\n" +
22633     "                </div>\n" +
22634     "            </div>\n" +
22635     "            <div ng-if=\"!shouldClip(profile.userName)\">\n" +
22636     "                {{profile.userName}}\n" +
22637     "            </div>\n" +
22638     "            <label>Email</label>\n" +
22639     "            <div ng-if=\"shouldClip(profile.email)\" ng-mouseover=\"showEmailTooltip = true;\" ng-mouseleave=\"showEmailTooltip = false;\">\n" +
22640     "                <div ng-if=\"shouldClip(profile.email)\" class=\"tooltip\" data-placement=\"bottom\" b2b-tooltip show-tooltip=\"showEmailTooltip\">\n" +
22641     "                    {{profile.email.slice(0, 25)+'...'}}\n" +
22642     "                    <div class=\"arrow\"></div>\n" +
22643     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +
22644     "                        <div class=\"tooltip-size-control\">\n" +
22645     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +
22646     "                                {{profile.email}}\n" +
22647     "                            </div>\n" +
22648     "                        </div>\n" +
22649     "                    </div>\n" +
22650     "                </div>\n" +
22651     "            </div>\n" +
22652     "            <div ng-if=\"!shouldClip(profile.email)\">\n" +
22653     "                {{profile.email}}\n" +
22654     "            </div>\n" +
22655     "            <label>Role</label>\n" +
22656     "            <div ng-if=\"shouldClip(profile.role)\" ng-mouseover=\"showRoleTooltip = true;\" ng-mouseleave=\"showRoleTooltip = false;\">\n" +
22657     "                <div ng-if=\"shouldClip(profile.role)\" class=\"tooltip\" b2b-tooltip show-tooltip=\"showRoleTooltip\">\n" +
22658     "                    {{profile.role.slice(0, 25)+'...'}}\n" +
22659     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +
22660     "                        <div class=\"tooltip-size-control\">\n" +
22661     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +
22662     "                                {{profile.role}}\n" +
22663     "                            </div>\n" +
22664     "                        </div>\n" +
22665     "                    </div>\n" +
22666     "                </div>\n" +
22667     "            </div>\n" +
22668     "            <div ng-if=\"!shouldClip(profile.role)\">\n" +
22669     "                {{profile.role}}\n" +
22670     "            </div>\n" +
22671     "            <label>Last login</label>\n" +
22672     "            <div ng-if=\"shouldClip(profile.lastLogin)\" ng-mouseover=\"showLastLoginTooltip = true;\" ng-mouseleave=\"showLastLoginTooltip = false;\">\n" +
22673     "                <div ng-if=\"shouldClip(profile.lastLogin)\" class=\"tooltip\" b2b-tooltip show-tooltip=\"showLastLoginTooltip\">\n" +
22674     "                    {{profile.lastLogin.slice(0, 25)+'...'}}\n" +
22675     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +
22676     "                        <div class=\"tooltip-size-control\">\n" +
22677     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +
22678     "                                {{profile.lastLogin}}\n" +
22679     "                            </div>\n" +
22680     "                        </div>\n" +
22681     "                    </div>\n" +
22682     "                </div>\n" +
22683     "            </div>\n" +
22684     "            <div ng-if=\"!shouldClip(profile.lastLogin)\">\n" +
22685     "                {{profile.lastLogin}}\n" +
22686     "            </div>\n" +
22687     "         </div>\n" +
22688     "    </div>\n" +
22689     "</div>");
22690 }]);
22691
22692 angular.module("b2bTemplate/searchField/searchField.html", []).run(["$templateCache", function($templateCache) {
22693   $templateCache.put("b2bTemplate/searchField/searchField.html",
22694     "<div class=\"search-bar\">\n" +
22695     "    <div class='input-container' ng-blur=\"blurInput()\">\n" +
22696     "        <input type=\"text\" class=\"innershadow b2b-search-input-field\" id=\"{{configObj.labelId}}\" b2b-search-input ng-model=\"inputModel\" ng-disabled=\"disabled\" b2b-reset ng-keydown=\"selectionIndex($event)\" placeholder=\"{{configObj.ghostText}}\" style=\"width:100%\" maxlength=\"{{configObj.maxLength}}\" title=\"{{inputModel}}\" aria-label=\"{{inputModel.length>0?inputModel:configObj.ghostText}}\" />\n" +
22697     "            <button class=\"btn-search\" ng-disabled=\"disabled\" ng-click=\"startSearch()\" b2b-accessibility-click=\"13,32\" aria-label=\"Search\" ng-focus=\"showListFlag = false\" type=\"button\"><i class=\"icoControls-magnifyingglass\"></i></button>\n" +
22698     "    </div>\n" +
22699     "    <div class=\"search-suggestion-wrapper\" ng-if=\"filterList.length >=0\" ng-show=\"showListFlag\">\n" +
22700     "        <ul class=\"search-suggestion-list\" role=\"listbox\">      \n" +
22701     "            <li class=\"no-result\" ng-if=\"filterList.length == 0 && configObj.display\">{{configObj.resultText}}</li>\n" +
22702     "            <li class=\"search-suggestion-item\" ng-if=\"filterList.length\" ng-repeat=\"item in filterList | limitTo:configObj.noOfItemsDisplay track by $index\" ng-bind-html=\"item.title | b2bMultiSepartorHighlight:inputModel:configObj.searchSeperator\" ng-class=\"{active:isActive($index,filterList.length)}\" ng-click=\"selectItem($index,item.title)\">\n" +
22703     "                {{item.title}}     \n" +
22704     "            </li>\n" +
22705     "        </ul>\n" +
22706     "    </div>\n" +
22707     "</div>");
22708 }]);
22709
22710 angular.module("b2bTemplate/seekBar/seekBar.html", []).run(["$templateCache", function($templateCache) {
22711   $templateCache.put("b2bTemplate/seekBar/seekBar.html",
22712     "<div class=\"b2b-seek-bar-container\" ng-class=\"{vertical:verticalSeekBar}\">\n" +
22713     "    <div class=\"b2b-seek-bar-track-container\">\n" +
22714     "        <div class=\"b2b-seek-bar-track\"></div>\n" +
22715     "        <div class=\"b2b-seek-bar-track-fill\"></div>\n" +
22716     "    </div>\n" +
22717     "    <div class=\"b2b-seek-bar-knob-container\" role=\"menu\"  >\n" +
22718     "        <div class=\"b2b-seek-bar-knob\" tabindex=\"0\" role=\"menuitem\"></div>\n" +
22719     "    </div>\n" +
22720     "</div>");
22721 }]);
22722
22723 angular.module("b2bTemplate/slider/slider.html", []).run(["$templateCache", function($templateCache) {
22724   $templateCache.put("b2bTemplate/slider/slider.html",
22725     "<div class=\"b2b-slider-container\" ng-class=\"{'vertical':verticalSlider}\">\n" +
22726     "    <div class=\"slider-track-container\">\n" +
22727     "        <div class=\"slider-track\"></div>\n" +
22728     "        <div class=\"slider-track-fill\" ng-style=\"{backgroundColor:trackFillColor}\"></div>\n" +
22729     "    </div>\n" +
22730     "    <div class=\"slider-knob-container\" ng-class=\"{'slider-knob-hidden':hideKnob}\">\n" +
22731     "        <div class=\"slider-knob\" role=\"slider\" aria-valuemin=\"{{min}}\" aria-valuemax=\"{{max}}\" aria-labelledby=\"{{labelId}}\" aria-valuenow=\"{{currentModelValue}}\" aria-valuetext=\"{{currentModelValue}}{{postAriaLabel}}\" aria-orientation=\"{{verticalSlider ? 'vertical' : 'horizontal'}}\"></div>\n" +
22732     "    </div>\n" +
22733     "</div>");
22734 }]);
22735
22736 angular.module("b2bTemplate/spinButton/spinButton.html", []).run(["$templateCache", function($templateCache) {
22737   $templateCache.put("b2bTemplate/spinButton/spinButton.html",
22738     "<div class=\"btn-group btn-spinbutton-toggle\" ng-class=\"{'disabled': disabledFlag}\">\n" +
22739     "    <button type=\"button\" tabindex=\"{{isMobile?'0':'-1'}}\" aria-hidden=\"{{notMobile}}\" class=\"btn btn-secondary btn-prev icon-primary-subtractminimize\" ng-click=\"minus();focusInputSpinButton($event)\" aria-label=\"Remove {{step}}\" aria-controls=\"{{spinButtonId}}\" ng-class=\"{'disabled': isMinusDisabled()}\" ng-disabled=\"isMinusDisabled()\" aria-disabled=\"{{isMinusDisabled()}}\" role=\"spinbutton\"></button>\n" +
22740     "    <input class=\"btn pull-left\" id=\"{{spinButtonId}}\" type=\"tel\" b2b-only-nums=\"3\" maxlength=\"3\" min={{min}} max={{max}} data-max-value=\"{{max}}\" ng-model=\"inputValue[inputModelKey]\" value=\"{{inputValue[inputModelKey]}}\" aria-live=\"polite\" aria-valuenow=\"{{inputValue[inputModelKey]}}\" aria-valuemin=\"{{min}}\" aria-valuemax=\"{{max}}\" ng-disabled=\"disabledFlag\">\n" +
22741     "    <button type=\"button\" tabindex=\"{{isMobile?'0':'-1'}}\" aria-hidden=\"{{notMobile}}\" class=\"btn btn-secondary btn-next icon-primary-add-maximize\" ng-click=\"plus();focusInputSpinButton($event)\" aria-label=\"Add {{step}}\" aria-controls=\"{{spinButtonId}}\" ng-class=\"{'disabled': isPlusDisabled()}\" ng-disabled=\"isPlusDisabled()\" aria-disabled=\"{{isPlusDisabled()}}\" role=\"spinbutton\"></button>\n" +
22742     "</div>");
22743 }]);
22744
22745 angular.module("b2bTemplate/statusTracker/statusTracker.html", []).run(["$templateCache", function($templateCache) {
22746   $templateCache.put("b2bTemplate/statusTracker/statusTracker.html",
22747     "<div class=\"b2b-status-tracker row\">\n" +
22748     "   <button tabindex=\"0\" ng-disabled=\"currentViewIndex === 0\" ng-if=\"statuses.length > b2bStatusTrackerConfig.maxViewItems\" class=\"btn-arrow\" type=\"button\" aria-label=\"Previous status\" ng-click=\"previousStatus()\">\n" +
22749     "       <div class=\"btn btn-small btn-secondary\">\n" +
22750     "           <i class=\"icon-primary-left\"></i>\n" +
22751     "       </div>\n" +
22752     "   </button>\n" +
22753     "   <div ng-repeat=\"status in statuses\" class=\"b2b-status-tracker-step {{ status.state }}\" ng-show=\"isInViewport($index)\">\n" +
22754     "       <p class=\"b2b-status-tracker-heading\">{{status.heading}}</p>\n" +
22755     "       <div class=\"progress\">\n" +
22756     "           <div class=\"progress-bar\">\n" +
22757     "                   <span class=\"hidden-spoken\">\n" +
22758     "                   {{ removeCamelCase(status.state) }}\n" +
22759     "                   </span>\n" +
22760     "           </div>\n" +
22761     "       </div>\n" +
22762     "       <div class=\"b2b-status-tracker-estimate {{status.state}}\">\n" +
22763     "           <i ng-show=\"status.estimate !== '' && status.estimate !== undefined\" ng-class=\"b2bStatusTrackerConfig.icons[status.state]\"></i>\n" +
22764     "           &nbsp;\n" +
22765     "           <span ng-bind-html=\"status.estimate\"></span>\n" +
22766     "       </div>\n" +
22767     "       \n" +
22768     "       <div class=\"b2b-status-tracker-description\" ng-bind-html=\"status.description\"> \n" +
22769     "       </div>\n" +
22770     "   </div>\n" +
22771     "   <button tabindex=\"0\" ng-disabled=\"currentViewIndex + b2bStatusTrackerConfig.maxViewItems === statuses.length\" ng-if=\"statuses.length > b2bStatusTrackerConfig.maxViewItems\" class=\"btn-arrow\" type=\"button\" aria-label=\"Next status\" ng-click=\"nextStatus()\">\n" +
22772     "       <div class=\"btn btn-small btn-secondary\">\n" +
22773     "           <i class=\"icon-primary-right\"></i>\n" +
22774     "       </div>\n" +
22775     "   </button>\n" +
22776     "</div>");
22777 }]);
22778
22779 angular.module("b2bTemplate/stepTracker/stepTracker.html", []).run(["$templateCache", function($templateCache) {
22780   $templateCache.put("b2bTemplate/stepTracker/stepTracker.html",
22781     "<div class=\"b2b-step-tracker\">\n" +
22782     "    <button class=\"btn-arrow b2b-left-arrow\" ng-click=\"previousStatus()\" ng-disabled=\"currentViewIndex === 0\" ng-if=\"stepsItemsObject.length > b2bStepTrackerConfig.maxViewItems\" aria-label=\"Previous step\">\n" +
22783     "           <div class=\"btn btn-left btn-small btn-secondary\"><i class=\"icon-primary-left\"></i></div>\n" +
22784     "   </button>\n" +
22785     "    <button class=\"btn-arrow b2b-right-arrow\" ng-click=\"nextStatus()\" ng-disabled=\"currentViewIndex + b2bStepTrackerConfig.maxViewItems === stepsItemsObject.length\" ng-if=\"stepsItemsObject.length > b2bStepTrackerConfig.maxViewItems\" aria-label=\"Next step\">\n" +
22786     "           <div class=\"btn btn-small btn-right btn-secondary\"><i class=\"icon-primary-right\"></i></div>\n" +
22787     "   </button>\n" +
22788     "    <ul class=\"b2b-steps\">\n" +
22789     "        <li ng-class=\"{'b2b-step-done':$index < currentIndex - 1 ,'b2b-step-on':$index == currentIndex - 1}\" \n" +
22790     "            ng-repeat=\"stepsItem in stepsItemsObject\" ng-show=\"isInViewport($index)\">\n" +
22791     "                   <p class=\"b2b-step-text\" data-sm-text=\"{{stepsItem.dataMobile}}\" data-large-text=\"{{stepsItem.dataDesktop}}\">{{stepsItem.text}}</p>\n" +
22792     "            <span class=\"hidden-spoken\">\n" +
22793     "                {{($index < currentIndex - 1)? 'Complete. '+stepsItem.text+' '+stepsItem.dataMobile:''}} \n" +
22794     "                {{($index == currentIndex - 1)? 'In Progress. '+stepsItem.text+' '+stepsItem.dataMobile:''}} \n" +
22795     "                {{($index > currentIndex - 1)? 'Incomplete. '+stepsItem.text+' '+stepsItem.dataMobile:''}}\n" +
22796     "            </span>\n" +
22797     "        </li>\n" +
22798     "    </ul>\n" +
22799     "</div>");
22800 }]);
22801
22802 angular.module("b2bTemplate/switches/switches-spanish.html", []).run(["$templateCache", function($templateCache) {
22803   $templateCache.put("b2bTemplate/switches/switches-spanish.html",
22804     "<div class=\"switch-overlay\" aria-hidden=\"true\">\n" +
22805     "    <span class=\"btn-slider-on\"><span class=\"hidden-spoken\">seleccione para hacer </span><i class=\"activo\">activo</i></span>\n" +
22806     "    <span class=\"switch-handle\"></span>\n" +
22807     "    <span class=\"btn-slider-off\"><span class=\"hidden-spoken\">seleccione para hacer </span><i class=\"inactivo\">inactivo</i></span>\n" +
22808     "</div>");
22809 }]);
22810
22811 angular.module("b2bTemplate/switches/switches.html", []).run(["$templateCache", function($templateCache) {
22812   $templateCache.put("b2bTemplate/switches/switches.html",
22813     "<div class=\"switch-overlay\" aria-hidden=\"true\">\n" +
22814     "    <span class=\"btn-slider-on\">On</span>\n" +
22815     "    <span class=\"switch-handle\"></span>\n" +
22816     "    <span class=\"btn-slider-off\">Off</span>\n" +
22817     "</div>");
22818 }]);
22819
22820 angular.module("b2bTemplate/tableMessages/tableMessage.html", []).run(["$templateCache", function($templateCache) {
22821   $templateCache.put("b2bTemplate/tableMessages/tableMessage.html",
22822     "<div class=\"b2b-table-message\">\n" +
22823     "    <div class=\"b2b-message\" ng-if=\"msgType === 'noMatchingResults'\">\n" +
22824     "        <div class=\"b2b-magnify-glass\"></div>\n" +
22825     "        <div>\n" +
22826     "            <div ng-transclude></div>\n" +
22827     "        </div>\n" +
22828     "    </div>\n" +
22829     "    <div class=\"b2b-message\" ng-if=\"msgType == 'infoCouldNotLoad'\">\n" +
22830     "        <div class=\"icon-primary-alert b2b-alert\" aria-label=\"Oops! The information could not load at this time. Please click link to refresh the page.\"></div>\n" +
22831     "        <div>Oops!</div>\n" +
22832     "        <div>The information could not load at this time.</div>\n" +
22833     "        <div>Please <a href=\"javascript:void(0)\" title=\"Refresh the page\" ng-click=\"refreshAction($event)\">refresh the page</a>\n" +
22834     "        </div>\n" +
22835     "    </div>\n" +
22836     "    <div class=\"b2b-message\" ng-if=\"msgType == 'magnifySearch'\">\n" +
22837     "        <div class=\"b2b-magnify-glass\"></div>\n" +
22838     "        <div>\n" +
22839     "            <p class=\"b2b-message-title\">Please input values to\n" +
22840     "                <br/> begin your search.</p>\n" +
22841     "        </div>\n" +
22842     "    </div>\n" +
22843     "    <div class=\"b2b-message\" ng-if=\"msgType === 'loadingTable'\">\n" +
22844     "        <div class=\"icon-primary-spinner-ddh b2b-loading-dots\"></div>\n" +
22845     "        <div ng-transclude></div>\n" +
22846     "    </div>\n" +
22847     "</div>\n" +
22848     "");
22849 }]);
22850
22851 angular.module("b2bTemplate/tableScrollbar/tableScrollbar.html", []).run(["$templateCache", function($templateCache) {
22852   $templateCache.put("b2bTemplate/tableScrollbar/tableScrollbar.html",
22853     "<div class=\"b2b-table-scrollbar\">\n" +
22854     "    <div class=\"b2b-scrollbar-arrows\">\n" +
22855     "        <button class=\"btn-arrow  b2b-scrollbar-arrow-left\" type=\"button\" ng-attr-aria-label=\"{{disableLeft ? 'Scroll Left Disabled' : 'Scroll Left'}}\" ng-click=\"scrollLeft()\" ng-disabled=\"disableLeft\"><div class=\"btn btn-alt\"><i class=\"icon-primary-left\"></i></div></button>\n" +
22856     "        <button class=\"btn-arrow b2b-scrollbar-arrow-right\" ng-attr-aria-label=\"{{disableRight ? 'Scroll Right Disabled' : 'Scroll Right'}}\" ng-click=\"scrollRight()\" ng-disabled=\"disableRight\" type=\"button\"><div class=\"btn btn-alt\"><i class=\"icon-primary-right\"></i></div></button>\n" +
22857     "    </div>\n" +
22858     "    <div class=\"b2b-table-inner-container\">\n" +
22859     "        <span ng-transclude></span>\n" +
22860     "    </div>\n" +
22861     "</div>");
22862 }]);
22863
22864 angular.module("b2bTemplate/tables/b2bTable.html", []).run(["$templateCache", function($templateCache) {
22865   $templateCache.put("b2bTemplate/tables/b2bTable.html",
22866     "<table ng-class=\"{'striped': responsive, 'complex-table': responsive && active}\" ng-transclude></table>");
22867 }]);
22868
22869 angular.module("b2bTemplate/tables/b2bTableBody.html", []).run(["$templateCache", function($templateCache) {
22870   $templateCache.put("b2bTemplate/tables/b2bTableBody.html",
22871     "<td ng-hide=\"isHidden()\" ng-transclude></td>");
22872 }]);
22873
22874 angular.module("b2bTemplate/tables/b2bTableHeaderSortable.html", []).run(["$templateCache", function($templateCache) {
22875   $templateCache.put("b2bTemplate/tables/b2bTableHeaderSortable.html",
22876     "<th scope=\"col\" role=\"columnheader\" aria-sort=\"{{sortPattern !== 'null' && 'none' || sortPattern}}\" aria-label=\"{{headerName}} {{sortable !== 'false' && ': activate to sort' || ' '}} {{sortPattern !== 'null' && '' || sortPattern}}\" tabindex=\"{{sortable !== 'false' && '0' || '-1'}}\" b2b-accessibility-click=\"13,32\" ng-click=\"(sortable !== 'false') && sort();\" ng-hide=\"isHidden()\">\n" +
22877     "    <span ng-transclude></span>\n" +
22878     "    <i ng-class=\"{'icoArrows-sort-arrow active': sortPattern === 'ascending', 'icoArrows-sort-arrow active down': sortPattern === 'descending'}\"></i>\n" +
22879     "</th>");
22880 }]);
22881
22882 angular.module("b2bTemplate/tables/b2bTableHeaderUnsortable.html", []).run(["$templateCache", function($templateCache) {
22883   $templateCache.put("b2bTemplate/tables/b2bTableHeaderUnsortable.html",
22884     "<th scope=\"col\" ng-hide=\"isHidden()\" ng-transclude></th>");
22885 }]);
22886
22887 angular.module("b2bTemplate/tabs/b2bTab.html", []).run(["$templateCache", function($templateCache) {
22888   $templateCache.put("b2bTemplate/tabs/b2bTab.html",
22889     "<li role=\"tab\" aria-selected=\"{{isTabActive()}}\" aria-controls=\"{{tabPanelId}}\" class=\"tab\" \n" +
22890     "    ng-class=\"{'active': isTabActive()}\" ng-click=\"clickTab()\" ng-hide=\"tabItem.disabled\">\n" +
22891     "    <a href=\"javascript:void(0)\"  tabindex=\"{{(isTabActive() && tabItem.disabled)?-1:0}}\"\n" +
22892     "       ng-disabled=\"tabItem.disabled\" aria-expanded=\"{{(isTabActive() && !tabItem.disabled)}}\" \n" +
22893     "       b2b-accessibility-click=\"13,32\" ng-transclude></a>\n" +
22894     "    <span class=\"hidden-spoken\" ng-if=\"isTabActive()\">Active tab</span>\n" +
22895     "</li>");
22896 }]);
22897
22898 angular.module("b2bTemplate/tabs/b2bTabset.html", []).run(["$templateCache", function($templateCache) {
22899   $templateCache.put("b2bTemplate/tabs/b2bTabset.html",
22900     "<ul class=\"tabs promo-tabs\" role=\"tablist\" ng-transclude></ul>");
22901 }]);
22902
22903 angular.module("b2bTemplate/treeNav/groupedTree.html", []).run(["$templateCache", function($templateCache) {
22904   $templateCache.put("b2bTemplate/treeNav/groupedTree.html",
22905     "<ul role=\"group\">\n" +
22906     "    <li aria-expanded=\"{{(member.active?true:false)}}\" role=\"treeitem\" aria-label=\"{{key}}\" ng-repeat='(key,value) in collection | groupBy : \"grpChild\"' b2b-tree-link><a class=\"grp\" ng-class=\"{'active': value.showGroup == true}\" tabindex=\"-1\" href='javascript:void(0);'>{{(key)?key:''}}<span class=\"b2b-tree-node-icon\"><i ng-class=\"{'icon-primary-expanded': value.showGroup == true, 'icon-primary-collapsed': value.showGroup == undefined || value.showGroup == false }\"></i></span></a>\n" +
22907     "        <ul role=\"group\">\n" +
22908     "            <b2b-member ng-repeat='member in value.childArray' member='member' time-delay='{{timeDelay}}' group-it='groupIt'></b2b-member>\n" +
22909     "        </ul>\n" +
22910     "    </li>\n" +
22911     "</ul>");
22912 }]);
22913
22914 angular.module("b2bTemplate/treeNav/treeMember.html", []).run(["$templateCache", function($templateCache) {
22915   $templateCache.put("b2bTemplate/treeNav/treeMember.html",
22916     "<li role=\"treeitem\" aria-expanded=\"{{(member.active?true:false)}}\" aria-label=\"{{member.tooltipContent ? member.tooltipContent : member.name}}\" aria-describedby=\"description_{{$id}}\" ng-class=\"{'bg':member.selected}\"  b2b-tree-link>\n" +
22917     "    <a tabindex=\"-1\" title=\"{{member.tooltipContent ? member.tooltipContent : member.name}}\" href=\"javascript:void(0)\" ng-class=\"{'active':member.active,'b2b-locked-node':member.locked}\">           <span class=\"b2b-tree-node-name\">{{member.name}}</span>\n" +
22918     "        <span class=\"{{!member.child?'end':''}} b2b-tree-node-icon\">\n" +
22919     "            <i class=\"b2b-tree-expandCollapse-icon\" ng-class=\"{'icon-primary-expanded':member.active}\"></i>\n" +
22920     "        </span>\n" +
22921     "         <div id=\"description_{{$id}}\" class=\"offscreen-text\">\n" +
22922     "           {{member.descriptionText}}\n" +
22923     "        </div>\n" +
22924     "        <div class=\"b2b-tree-tooltip\" ng-if=\"member.showTooltip\">\n" +
22925     "           <span class=\"b2b-tree-arrow-left\"></span>\n" +
22926     "           <div class=\"b2b-tree-tooltip-content\">\n" +
22927     "                   {{member.tooltipContent}}\n" +
22928     "           </div>  \n" +
22929     "        </div>\n" +
22930     "    </a>\n" +
22931     "</li>");
22932 }]);
22933
22934 angular.module("b2bTemplate/treeNav/ungroupedTree.html", []).run(["$templateCache", function($templateCache) {
22935   $templateCache.put("b2bTemplate/treeNav/ungroupedTree.html",
22936     "<ul role=\"{{setRole}}\"><b2b-member ng-repeat='member in collection' member='member' group-it='groupIt'></b2b-member></ul>");
22937 }]);
22938
22939 angular.module("b2bTemplate/treeNodeCheckbox/groupedTree.html", []).run(["$templateCache", function($templateCache) {
22940   $templateCache.put("b2bTemplate/treeNodeCheckbox/groupedTree.html",
22941     "<ul role=\"group\">\n" +
22942     "    <li aria-expanded=\"{{(member.active?true:false)}}\" role=\"treeitem\" aria-label=\"{{key}}\" ng-repeat='(key,value) in collection | groupBy : \"grpChild\"' b2b-tree-node-link><a class=\"grp\" ng-class=\"{'active': value.showGroup == true}\" tabindex=\"-1\" href='javascript:void(0);'>\n" +
22943     "        <span class=\"ng-hide\">\n" +
22944     "            <label class=\"checkbox\">\n" +
22945     "                <input type=\"checkbox\" tabindex=\"-1\" class=\"treeCheckBox grpTreeCheckbox\" style=\"margin-top:2px;\"/><i class=\"skin\"></i><span> {{(key)?key:''}}</span>\n" +
22946     "            </label>\n" +
22947     "        </span>\n" +
22948     "        <span>\n" +
22949     "            {{(key)?key:''}}    \n" +
22950     "        </span>\n" +
22951     "        <span class=\"nodeIcon\"><i class=\"expandCollapseIcon\" ng-class=\"{'icon-primary-expanded': value.showGroup == true, 'icon-primary-collapsed': value.showGroup == undefined || value.showGroup == false }\"></i></span></a>\n" +
22952     "        <ul role=\"group\">\n" +
22953     "            <b2b-tree-member ng-repeat='member in value.childArray' member='member' group-it='groupIt'></b2b-tree-member>\n" +
22954     "        </ul>\n" +
22955     "    </li>\n" +
22956     "</ul>");
22957 }]);
22958
22959 angular.module("b2bTemplate/treeNodeCheckbox/treeMember.html", []).run(["$templateCache", function($templateCache) {
22960   $templateCache.put("b2bTemplate/treeNodeCheckbox/treeMember.html",
22961     "<li role=\"treeitem\" aria-expanded=\"{{(member.active?true:false)}}\" aria-label=\"{{member.name}}\" ng-class=\"{'bg':member.selected}\"  b2b-tree-node-link>\n" +
22962     "    <a tabindex=\"-1\" title=\"{{member.name}}\" href=\"javascript:void(0)\" ng-class=\"{'active':member.active}\">\n" +
22963     "           <span ng-show=\"member.displayCheckbox\">\n" +
22964     "                           <label class=\"checkbox\">\n" +
22965     "                <input type=\"checkbox\" tabindex=\"-1\" ng-model=\"member.isSelected\" ng-class=\"{'treeCheckBox': (member.displayCheckbox !== undefined)}\" style=\"margin-top:2px;\"/><i class=\"skin\"></i><span> {{member.name}}</span>\n" +
22966     "            </label>\n" +
22967     "        </span>\n" +
22968     "           <span ng-show=\"!member.displayCheckbox\">\n" +
22969     "                   {{member.name}} \n" +
22970     "           </span>\n" +
22971     "        <span class=\"nodeIcon {{!member.child?'end':''}}\">\n" +
22972     "            <i class=\"expandCollapseIcon\" ng-class=\"{'icon-primary-expanded':member.active}\"></i>\n" +
22973     "        </span>\n" +
22974     "    </a>\n" +
22975     "</li>");
22976 }]);
22977
22978 angular.module("b2bTemplate/treeNodeCheckbox/ungroupedTree.html", []).run(["$templateCache", function($templateCache) {
22979   $templateCache.put("b2bTemplate/treeNodeCheckbox/ungroupedTree.html",
22980     "<ul role=\"{{setRole}}\"><b2b-tree-member ng-repeat='member in collection' member='member' group-it='groupIt'></b2b-tree-member></ul>");
22981 }]);