39824ec3584de3a7a4105eb412c483fecb895bca
[portal/sdk.git] /
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                     var childNodes = elem.parent().parent().find('ul').eq(0).children('li');
11900                     checkedCount = 0;
11901                     nonCheckedCount = 0;
11902                     checkBoxesCount = 0;    
11903                     for(i=0; i<childNodes.length; i++){
11904                         if(findCheckbox(childNodes[i])){
11905                             isGroupNode(childNodes[i]);
11906                             isCheckboxSelected(childNodes[i]);
11907                             checkBoxesCount++;
11908                             if(checkedTreeNode){
11909                                 checkedCount++;
11910                             }else if(!angular.element(angular.element(angular.element(childNodes[i]).find('a').eq(0))[0].querySelector('input.treeCheckBox')).prop('indeterminate')){
11911                                 nonCheckedCount++;
11912                             }
11913                         }
11914                     }
11915                     var parentNodeScope;
11916                     parentNodeScope = angular.element(elem.parent().parent()).scope();
11917                     if(findCheckbox(elem.parent().parent())){
11918                         if(nonCheckedCount == checkBoxesCount){
11919                             angular.element(findCheckbox(elem.parent().parent())).prop('indeterminate', false);
11920                             if(parentNodeScope &&  parentNodeScope.member){
11921                                 parentNodeScope.member.isSelected = false;
11922                                 parentNodeScope.member.indeterminate = false;
11923                             }else{
11924                                 updateGrpNodeCheckboxes(elem.parent().parent(),false);
11925                             }
11926                             angular.element(elem.parent().parent()).attr('aria-checked',false);
11927                         }else if(checkedCount == checkBoxesCount){
11928                             angular.element(findCheckbox(elem.parent().parent())).prop('indeterminate', false);
11929                             if(parentNodeScope &&  parentNodeScope.member){
11930                                 parentNodeScope.member.isSelected = true;
11931                                 parentNodeScope.member.indeterminate = false;
11932                             }else{
11933                                 updateGrpNodeCheckboxes(elem.parent().parent(),true);
11934                             }
11935                             angular.element(elem.parent().parent()).attr('aria-checked',true);
11936                         }else{
11937                             angular.element(findCheckbox(elem.parent().parent())).prop('indeterminate', true);
11938                             if(parentNodeScope &&  parentNodeScope.member){
11939                                 parentNodeScope.member.isSelected = false;
11940                                 parentNodeScope.member.indeterminate = true;
11941                             }else{
11942                                 updateGrpNodeCheckboxes(elem.parent().parent(),false);
11943                             }
11944                             angular.element(elem.parent().parent()).attr('aria-checked',"mixed");
11945                         }
11946                         if(parentNodeScope &&  parentNodeScope.member){
11947                             parentNodeScope.$apply();
11948                         }        
11949                     }
11950                     
11951                     
11952                     
11953                     if(elem.parent().parent().attr('role') == "treeitem"){
11954                         upwardSelection(elem.parent().parent());
11955                     }
11956                 }
11957
11958                 scope.showChild = function () {
11959                         if (!element.hasClass('grouped')) {
11960                             if (angular.isArray(scope.member.child) && scope.member.child.length > 0 && (scope.member.divide === undefined || scope.member.child.length < scope.member.divide)) {
11961                                 scope.groupIt = false;
11962                                 element.addClass('grouped');
11963                                 element.append("<b2b-tree-node-checkbox collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-node-checkbox>");
11964                                 $compile(element.contents())(scope);
11965                                 if(scope.member.active && scope.member.active === true){
11966                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-collapsed');
11967                                 };
11968                                 if(scope.member.selected && scope.member.selected === true){
11969                                     element.attr('tabindex', 0);
11970                                     removeRootTabIndex(element);
11971                                 };
11972                                 if(scope.member.active && scope.member.active == undefined){
11973                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');
11974                                 };
11975                             } else if (scope.member.child && scope.member.divide && scope.member.child.length > scope.member.divide) {
11976                                 element.addClass('grouped');
11977                                 scope.groupIt = true;
11978                                 var j = 0;
11979                                 var grpName = '';
11980                                 if(scope.member.child[0].groupName !== undefined){
11981                                     grpName = scope.member.child[0].groupName;
11982                                 }
11983                                 else{
11984                                     var toSlice = scope.member.child[0].name.search(' ');
11985                                     grpName = scope.member.child[0].name.slice(0, toSlice);
11986                                 }
11987
11988                                 for (i = 0; i < scope.member.child.length; i += scope.member.divide) {
11989                                     j = 0;
11990                                     for (j = j + i; j < (i + scope.member.divide); j++) {                                        
11991                                         if (j === scope.member.child.length) {
11992                                             scope.member.child[j - 1].grpChild = grpName + ' ' + (i + 1) + ' - ' + (scope.member.child.length);
11993                                             break;
11994                                             
11995                                             if(scope.member.child[j-1].active && scope.member.child[j-1].active===true){
11996                                                 scope.member.child[j-1].activeGrp = true;
11997                                             };
11998                                             
11999                                         }
12000                                         if (i + scope.member.divide > scope.member.child.length) {
12001                                             scope.member.child[j].grpChild = grpName + ' ' + (i + 1) + ' - ' + (scope.member.child.length);
12002                                             if(scope.member.child[j].active && scope.member.child[j].active===true){
12003                                                 scope.member.child[j].activeGrp = true;
12004                                             };
12005
12006                                         } else {
12007                                             scope.member.child[j].grpChild = grpName + ' ' + (i + 1) + ' - ' + (i + scope.member.divide);
12008                                             if(scope.member.child[j].active && scope.member.child[j].active===true){
12009                                                 scope.member.child[j].activeGrp = true;
12010                                             };
12011                                         }
12012                                     }
12013                                 }
12014                                 if(scope.member.divide){
12015                                     element.append("<b2b-tree-node-checkbox collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-node-checkbox>");
12016                                 } else {
12017                                     element.append("<b2b-tree-node-checkbox collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-node-checkbox>");
12018                                 }
12019                                 $compile(element.contents())(scope);
12020                                 if(scope.member.active && scope.member.active === true){
12021                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-collapsed');
12022                                 };
12023                                 
12024                                 if( scope.member.active && scope.member.active == undefined){
12025                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');
12026                                 };
12027                             }
12028                         }
12029                         $timeout(function () {
12030                             if(!scope.member.indeterminate){
12031                                 downwardSelection(element);
12032                             }    
12033                         });  
12034
12035                 };
12036                 
12037                 if(scope.member.active && scope.member.active == true){
12038                     scope.showChild();
12039                 };
12040                 if(scope.member.active == undefined && !element.find('a').eq(0).hasClass('active') && scope.member.child !== undefined){
12041                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');
12042                 }
12043                 else if(scope.member.child == undefined){
12044                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-circle');
12045                     if(scope.$parent.$index === 0) {
12046                         element.find('a').eq(0).append('<span class="first-link"></span>');
12047                     };
12048                 };
12049                 
12050                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).bind('click', function (evt) {
12051                     scope.showChild();
12052                     var expandFunc = scope.member.onExpand;
12053                     if (element.find('a').eq(0).hasClass('active') && scope.member.onExpand !== undefined) {
12054                        var eValue = scope.member.onExpand(scope.member);
12055                     }
12056                     if (!element.find('a').eq(0).hasClass('active') && scope.member.onCollapse !== undefined) {
12057                         scope.member.onCollapse(scope.member);
12058                     }
12059                 });
12060
12061                 angular.element(element[0].querySelectorAll('.treeNodeName')).eq(0).bind('click', function (evt) {
12062
12063                 });
12064                 
12065             }
12066         }
12067 }])
12068     .directive('b2bTreeNodeLink', ['keymap', '$timeout', function (keymap, $timeout) {
12069         return {
12070             restrict: 'A',
12071             link: function (scope, element, attr, ctrl) {
12072                 var rootE, parentE, upE, downE;
12073                 var closeOthersUp = function (elem) {
12074                     
12075                     if (elem.find('a').eq(0).hasClass('active')) {
12076                         activeToggle(elem);
12077                         return;
12078                     }
12079                     if (elem.hasClass('bg')) {
12080                         elem.removeClass('bg');
12081                     }
12082                     if (elem[0].previousElementSibling !== null) {
12083                         closeOthersUp(angular.element(elem[0].previousElementSibling));
12084                     }
12085                 };
12086                 var closeOthersDown = function (elem) {
12087                     
12088                     if (elem.find('a').eq(0).hasClass('active')) {
12089                         activeToggle(elem);
12090                         return;
12091                     }
12092                     if (elem.hasClass('bg')) {
12093                         elem.removeClass('bg');
12094                     }
12095                     if (elem[0].nextElementSibling !== null) {
12096                         closeOthersDown(angular.element(elem[0].nextElementSibling));
12097                     }
12098                 };
12099
12100                 var removeBackgroundUp = function (elem) {
12101                     
12102                     if (elem.hasClass('b2b-tree-checkbox')) {
12103                         return;
12104                     } else {
12105                         elem.parent().parent().removeClass('bg');
12106                         removeBackgroundUp(elem.parent().parent());
12107                     }
12108                 };
12109
12110                 var removeBackgroundDown = function (elem) {
12111                     
12112                     angular.element(elem[0].querySelector('.bg')).removeClass('bg');
12113                 };
12114
12115
12116
12117                 var activeToggle = function (elem) {
12118                     var element = elem.find('a').eq(0);
12119                     if (element.hasClass('active')) {
12120                         elem.removeClass('bg');
12121                         if (!angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).hasClass('icon-primary-circle')) {
12122                             element.removeClass('active');
12123                             elem.attr('aria-expanded', 'false');
12124                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-expanded');
12125                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');
12126                         }
12127                     } else {
12128                         elem.addClass('bg');
12129                         if (!angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).hasClass('icon-primary-circle')) {
12130                             element.addClass('active');
12131                             elem.attr('aria-expanded', 'true');
12132                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-collapsed');
12133                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-expanded');
12134                         }
12135                     }
12136                 };
12137                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).bind('click', function (evt) {
12138                     
12139                         if (element[0].previousElementSibling) {
12140                             closeOthersUp(angular.element(element[0].previousElementSibling));
12141                         }
12142                         if (element[0].nextElementSibling) {
12143                             closeOthersDown(angular.element(element[0].nextElementSibling));
12144                         }
12145
12146                         activeToggle(element);
12147
12148                     removeBackgroundDown(element);
12149                     removeBackgroundUp(element);
12150                     evt.stopPropagation();                    
12151                 });
12152                 
12153                 if (element.parent().parent().hasClass('b2b-tree-checkbox') && (element.parent()[0].previousElementSibling === null)) {
12154                     element.attr('tabindex', 0);
12155                 }
12156                 
12157                 var isRoot = function (elem) {
12158                     if (elem.parent().parent().eq(0).hasClass('b2b-tree-checkbox')) {
12159                         return true;
12160                     } else {
12161                         return false;
12162                     }
12163                 };
12164                 var findRoot = function (elem) {
12165                     if (isRoot(elem)) {
12166                         rootE = elem;
12167                         return;
12168                     }
12169                     findRoot(elem.parent());
12170                 };
12171
12172                 var findPreActive = function (elem) {
12173
12174                     if (!(elem.hasClass("active"))) {
12175                         return;
12176                     } else {
12177                         var childElems = angular.element(elem[0].nextElementSibling.children);
12178                         lastE = angular.element(childElems[childElems.length - 1]);
12179                         if (lastE.find('a').eq(0).hasClass('active')) {
12180                             findPreActive(lastE.find('a').eq(0));
12181                         }
12182                         upE = lastE;
12183                     }
12184                 };
12185
12186                 var findUp = function (elem) {
12187                     if (isRoot(elem)) {
12188                         upE = elem;
12189                         return;
12190                     }
12191                     if (elem[0].previousElementSibling !== null && !angular.element(elem[0].previousElementSibling).hasClass('tree-hide')) {
12192                         upE = angular.element(elem[0].previousElementSibling);
12193                         if (upE.find('a').eq(0).hasClass('active')) {
12194                             findPreActive(upE.find('a').eq(0));
12195                         }
12196                     } else {
12197                         upE = elem.parent().parent();
12198                     }
12199                 };
12200
12201                 var downElement = function (elem) {
12202                     if (elem.next().hasClass('tree-hide')) {
12203                         downElement(elem.next());
12204                     } else {
12205                         downE = elem.next();
12206                     }
12207                 }
12208                 var isBottomElem = false;
12209                 var downParent = function(liElem){
12210                     if(liElem.eq(0).parent().parent().eq(0).hasClass('b2b-tree-checkbox')){
12211                         isBottomElem = true;
12212                         return;
12213                     }
12214                     if(liElem.next().length !== 0){
12215                         downE = liElem.next().eq(0);
12216                         return;
12217                     }
12218                     else {
12219                         downParent(liElem.parent().parent());
12220                     }
12221                 }
12222                 
12223                 var findDown = function (elem) {
12224                     if (isRoot(elem.parent()) && !elem.hasClass('active')) {
12225                         downE = elem.parent();
12226                         return;
12227                     }
12228                     if (elem.hasClass('active')) {
12229                         downE = elem.next().find('li').eq(0);
12230                         if (downE.hasClass('tree-hide')) {
12231                             downElement(downE);
12232                         }
12233
12234                     } else {
12235                         downParent(elem.parent());
12236                         if(isBottomElem === true){
12237                             downE = elem.parent();
12238                             isBottomElem = false;
12239                         }
12240                     }
12241                 };
12242                 element.bind('keydown', function (evt) {
12243                     switch (evt.keyCode) {
12244                     case keymap.KEY.HOME:
12245                         evt.preventDefault();
12246                         evt.stopPropagation();
12247                         element.attr('tabindex', -1);
12248                         findRoot(element);
12249                         rootE.eq(0).attr('tabindex', 0);
12250                         rootE[0].focus();
12251                         break;
12252                     case keymap.KEY.LEFT:
12253                         evt.preventDefault();
12254                         evt.stopPropagation();
12255                         if (!isRoot(element)) {
12256                             if(element.find('a').eq(0).hasClass('active')){
12257                                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).triggerHandler('click');
12258                                 return;
12259                             }
12260                             element.attr('tabindex', -1);
12261                             parentE = element.parent().parent();
12262                             parentE.attr('tabindex', 0);
12263                             parentE[0].focus();
12264                         } else {
12265                             if (element.find('a').eq(0).hasClass('active')) {
12266                                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).triggerHandler('click');
12267                             }
12268                         };
12269                         break;
12270                     case keymap.KEY.UP:
12271                         evt.preventDefault();
12272                         evt.stopPropagation();
12273                         element.attr('tabindex', -1);
12274                         findUp(element);
12275                         upE.eq(0).attr('tabindex', 0);
12276                         upE[0].focus();
12277                         break;
12278                     case keymap.KEY.RIGHT:
12279                         evt.preventDefault();
12280                         evt.stopPropagation();
12281                         if(angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).hasClass('icon-primary-circle')){
12282                             break;
12283                         }    
12284                         if (!element.find('a').eq(0).hasClass('active')) {
12285                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).triggerHandler('click');
12286                         }
12287                         else {
12288                             element.attr('tabindex', -1);
12289                             findDown(element.find('a').eq(0));
12290                             downE.eq(0).attr('tabindex', 0);
12291                             downE[0].focus();                            
12292                         }                        
12293                         break;
12294                     case keymap.KEY.DOWN:
12295                         evt.preventDefault();
12296                         element.attr('tabindex', -1);
12297                         findDown(element.find('a').eq(0));
12298                         downE.eq(0).attr('tabindex', 0);
12299                         downE[0].focus();
12300                         evt.stopPropagation();
12301                         break;
12302                     case keymap.KEY.SPACE:
12303                     case keymap.KEY.ENTER:
12304                         evt.preventDefault();
12305                         evt.stopPropagation();
12306                         if(angular.isDefined(element.scope().member.isSelected)){
12307                             element.scope().member.isSelected = !element.scope().member.isSelected;
12308                             element.scope().member.indeterminate = false;
12309                             element.scope().$apply();
12310                             element.find('a').eq(0).find('input').prop('indeterminate', false);
12311                             element.find('a').eq(0).find('input').triggerHandler('change');
12312                         }
12313                         break;    
12314                     default:
12315                         break;
12316                     }
12317                 });
12318             }
12319         };
12320     }]);
12321 /*!
12322  * VERSION: 1.7.3
12323  * DATE: 2014-01-14
12324  * UPDATES AND DOCS AT: http://www.greensock.com
12325  *
12326  * @license Copyright (c) 2008-2014, GreenSock. All rights reserved.
12327  * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
12328  * Club GreenSock members, the software agreement that was issued with your membership.
12329  * 
12330  * @author: Jack Doyle, jack@greensock.com
12331  **/
12332 (window._gsQueue || (window._gsQueue = [])).push( function() {
12333
12334         "use strict";
12335
12336         var _doc = document.documentElement,
12337                 _window = window,
12338                 _max = function(element, axis) {
12339                         var dim = (axis === "x") ? "Width" : "Height",
12340                                 scroll = "scroll" + dim,
12341                                 client = "client" + dim,
12342                                 body = document.body;
12343                         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];
12344                 },
12345
12346                 ScrollToPlugin = window._gsDefine.plugin({
12347                         propName: "scrollTo",
12348                         API: 2,
12349                         version:"1.7.3",
12350
12351                         //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
12352                         init: function(target, value, tween) {
12353                                 this._wdw = (target === _window);
12354                                 this._target = target;
12355                                 this._tween = tween;
12356                                 if (typeof(value) !== "object") {
12357                                         value = {y:value}; //if we don't receive an object as the parameter, assume the user intends "y".
12358                                 }
12359                                 this._autoKill = (value.autoKill !== false);
12360                                 this.x = this.xPrev = this.getX();
12361                                 this.y = this.yPrev = this.getY();
12362                                 if (value.x != null) {
12363                                         this._addTween(this, "x", this.x, (value.x === "max") ? _max(target, "x") : value.x, "scrollTo_x", true);
12364                                         this._overwriteProps.push("scrollTo_x");
12365                                 } else {
12366                                         this.skipX = true;
12367                                 }
12368                                 if (value.y != null) {
12369                                         this._addTween(this, "y", this.y, (value.y === "max") ? _max(target, "y") : value.y, "scrollTo_y", true);
12370                                         this._overwriteProps.push("scrollTo_y");
12371                                 } else {
12372                                         this.skipY = true;
12373                                 }
12374                                 return true;
12375                         },
12376
12377                         //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.)
12378                         set: function(v) {
12379                                 this._super.setRatio.call(this, v);
12380
12381                                 var x = (this._wdw || !this.skipX) ? this.getX() : this.xPrev,
12382                                         y = (this._wdw || !this.skipY) ? this.getY() : this.yPrev,
12383                                         yDif = y - this.yPrev,
12384                                         xDif = x - this.xPrev;
12385
12386                                 if (this._autoKill) {
12387                                         //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.
12388                                         if (!this.skipX && (xDif > 7 || xDif < -7) && x < _max(this._target, "x")) {
12389                                                 this.skipX = true; //if the user scrolls separately, we should stop tweening!
12390                                         }
12391                                         if (!this.skipY && (yDif > 7 || yDif < -7) && y < _max(this._target, "y")) {
12392                                                 this.skipY = true; //if the user scrolls separately, we should stop tweening!
12393                                         }
12394                                         if (this.skipX && this.skipY) {
12395                                                 this._tween.kill();
12396                                         }
12397                                 }
12398                                 if (this._wdw) {
12399                                         _window.scrollTo((!this.skipX) ? this.x : x, (!this.skipY) ? this.y : y);
12400                                 } else {
12401                                         if (!this.skipY) {
12402                                                 this._target.scrollTop = this.y;
12403                                         }
12404                                         if (!this.skipX) {
12405                                                 this._target.scrollLeft = this.x;
12406                                         }
12407                                 }
12408                                 this.xPrev = this.x;
12409                                 this.yPrev = this.y;
12410                         }
12411
12412                 }),
12413                 p = ScrollToPlugin.prototype;
12414
12415         ScrollToPlugin.max = _max;
12416
12417         p.getX = function() {
12418                 return (!this._wdw) ? this._target.scrollLeft : (_window.pageXOffset != null) ? _window.pageXOffset : (_doc.scrollLeft != null) ? _doc.scrollLeft : document.body.scrollLeft;
12419         };
12420
12421         p.getY = function() {
12422                 return (!this._wdw) ? this._target.scrollTop : (_window.pageYOffset != null) ? _window.pageYOffset : (_doc.scrollTop != null) ? _doc.scrollTop : document.body.scrollTop;
12423         };
12424
12425         p._kill = function(lookup) {
12426                 if (lookup.scrollTo_x) {
12427                         this.skipX = true;
12428                 }
12429                 if (lookup.scrollTo_y) {
12430                         this.skipY = true;
12431                 }
12432                 return this._super._kill.call(this, lookup);
12433         };
12434
12435 }); if (window._gsDefine) { window._gsQueue.pop()(); }
12436 /*!
12437  * VERSION: 1.12.1
12438  * DATE: 2014-06-26
12439  * UPDATES AND DOCS AT: http://www.greensock.com
12440  * 
12441  * Includes all of the following: TweenLite, TweenMax, TimelineLite, TimelineMax, EasePack, CSSPlugin, RoundPropsPlugin, BezierPlugin, AttrPlugin, DirectionalRotationPlugin
12442  *
12443  * @license Copyright (c) 2008-2014, GreenSock. All rights reserved.
12444  * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
12445  * Club GreenSock members, the software agreement that was issued with your membership.
12446  * 
12447  * @author: Jack Doyle, jack@greensock.com
12448  **/
12449
12450 (window._gsQueue || (window._gsQueue = [])).push( function() {
12451
12452         "use strict";
12453
12454         window._gsDefine("TweenMax", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {
12455
12456                 var _slice = [].slice,
12457                         TweenMax = function(target, duration, vars) {
12458                                 TweenLite.call(this, target, duration, vars);
12459                                 this._cycle = 0;
12460                                 this._yoyo = (this.vars.yoyo === true);
12461                                 this._repeat = this.vars.repeat || 0;
12462                                 this._repeatDelay = this.vars.repeatDelay || 0;
12463                                 this._dirty = true; //ensures that if there is any repeat, the totalDuration will get recalculated to accurately report it.
12464                                 this.render = TweenMax.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method)
12465                         },
12466                         _tinyNum = 0.0000000001,
12467                         TweenLiteInternals = TweenLite._internals,
12468                         _isSelector = TweenLiteInternals.isSelector,
12469                         _isArray = TweenLiteInternals.isArray,
12470                         p = TweenMax.prototype = TweenLite.to({}, 0.1, {}),
12471                         _blankArray = [];
12472
12473                 TweenMax.version = "1.12.1";
12474                 p.constructor = TweenMax;
12475                 p.kill()._gc = false;
12476                 TweenMax.killTweensOf = TweenMax.killDelayedCallsTo = TweenLite.killTweensOf;
12477                 TweenMax.getTweensOf = TweenLite.getTweensOf;
12478                 TweenMax.lagSmoothing = TweenLite.lagSmoothing;
12479                 TweenMax.ticker = TweenLite.ticker;
12480                 TweenMax.render = TweenLite.render;
12481
12482                 p.invalidate = function() {
12483                         this._yoyo = (this.vars.yoyo === true);
12484                         this._repeat = this.vars.repeat || 0;
12485                         this._repeatDelay = this.vars.repeatDelay || 0;
12486                         this._uncache(true);
12487                         return TweenLite.prototype.invalidate.call(this);
12488                 };
12489                 
12490                 p.updateTo = function(vars, resetDuration) {
12491                         var curRatio = this.ratio, p;
12492                         if (resetDuration && this._startTime < this._timeline._time) {
12493                                 this._startTime = this._timeline._time;
12494                                 this._uncache(false);
12495                                 if (this._gc) {
12496                                         this._enabled(true, false);
12497                                 } else {
12498                                         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.
12499                                 }
12500                         }
12501                         for (p in vars) {
12502                                 this.vars[p] = vars[p];
12503                         }
12504                         if (this._initted) {
12505                                 if (resetDuration) {
12506                                         this._initted = false;
12507                                 } else {
12508                                         if (this._gc) {
12509                                                 this._enabled(true, false);
12510                                         }
12511                                         if (this._notifyPluginsOfEnabled && this._firstPT) {
12512                                                 TweenLite._onPluginEvent("_onDisable", this); //in case a plugin like MotionBlur must perform some cleanup tasks
12513                                         }
12514                                         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. 
12515                                                 var prevTime = this._time;
12516                                                 this.render(0, true, false);
12517                                                 this._initted = false;
12518                                                 this.render(prevTime, true, false);
12519                                         } else if (this._time > 0) {
12520                                                 this._initted = false;
12521                                                 this._init();
12522                                                 var inv = 1 / (1 - curRatio),
12523                                                         pt = this._firstPT, endValue;
12524                                                 while (pt) {
12525                                                         endValue = pt.s + pt.c; 
12526                                                         pt.c *= inv;
12527                                                         pt.s = endValue - pt.c;
12528                                                         pt = pt._next;
12529                                                 }
12530                                         }
12531                                 }
12532                         }
12533                         return this;
12534                 };
12535                                 
12536                 p.render = function(time, suppressEvents, force) {
12537                         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.
12538                                 this.invalidate();
12539                         }
12540                         var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
12541                                 prevTime = this._time,
12542                                 prevTotalTime = this._totalTime, 
12543                                 prevCycle = this._cycle,
12544                                 duration = this._duration,
12545                                 prevRawPrevTime = this._rawPrevTime,
12546                                 isComplete, callback, pt, cycleDuration, r, type, pow, rawPrevTime, i;
12547                         if (time >= totalDur) {
12548                                 this._totalTime = totalDur;
12549                                 this._cycle = this._repeat;
12550                                 if (this._yoyo && (this._cycle & 1) !== 0) {
12551                                         this._time = 0;
12552                                         this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
12553                                 } else {
12554                                         this._time = duration;
12555                                         this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1;
12556                                 }
12557                                 if (!this._reversed) {
12558                                         isComplete = true;
12559                                         callback = "onComplete";
12560                                 }
12561                                 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.
12562                                         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.
12563                                                 time = 0;
12564                                         }
12565                                         if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time) {
12566                                                 force = true;
12567                                                 if (prevRawPrevTime > _tinyNum) {
12568                                                         callback = "onReverseComplete";
12569                                                 }
12570                                         }
12571                                         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.
12572                                 }
12573                                 
12574                         } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
12575                                 this._totalTime = this._time = this._cycle = 0;
12576                                 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
12577                                 if (prevTotalTime !== 0 || (duration === 0 && prevRawPrevTime > 0 && prevRawPrevTime !== _tinyNum)) {
12578                                         callback = "onReverseComplete";
12579                                         isComplete = this._reversed;
12580                                 }
12581                                 if (time < 0) {
12582                                         this._active = false;
12583                                         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.
12584                                                 if (prevRawPrevTime >= 0) {
12585                                                         force = true;
12586                                                 }
12587                                                 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.
12588                                         }
12589                                 } 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.
12590                                         force = true;
12591                                 }
12592                         } else {
12593                                 this._totalTime = this._time = time;
12594                                 
12595                                 if (this._repeat !== 0) {
12596                                         cycleDuration = duration + this._repeatDelay;
12597                                         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!)
12598                                         if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) {
12599                                                 this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning)
12600                                         }
12601                                         this._time = this._totalTime - (this._cycle * cycleDuration);
12602                                         if (this._yoyo) if ((this._cycle & 1) !== 0) {
12603                                                 this._time = duration - this._time;
12604                                         }
12605                                         if (this._time > duration) {
12606                                                 this._time = duration;
12607                                         } else if (this._time < 0) {
12608                                                 this._time = 0;
12609                                         }
12610                                 }
12611
12612                                 if (this._easeType) {
12613                                         r = this._time / duration;
12614                                         type = this._easeType;
12615                                         pow = this._easePower;
12616                                         if (type === 1 || (type === 3 && r >= 0.5)) {
12617                                                 r = 1 - r;
12618                                         }
12619                                         if (type === 3) {
12620                                                 r *= 2;
12621                                         }
12622                                         if (pow === 1) {
12623                                                 r *= r;
12624                                         } else if (pow === 2) {
12625                                                 r *= r * r;
12626                                         } else if (pow === 3) {
12627                                                 r *= r * r * r;
12628                                         } else if (pow === 4) {
12629                                                 r *= r * r * r * r;
12630                                         }
12631
12632                                         if (type === 1) {
12633                                                 this.ratio = 1 - r;
12634                                         } else if (type === 2) {
12635                                                 this.ratio = r;
12636                                         } else if (this._time / duration < 0.5) {
12637                                                 this.ratio = r / 2;
12638                                         } else {
12639                                                 this.ratio = 1 - (r / 2);
12640                                         }
12641
12642                                 } else {
12643                                         this.ratio = this._ease.getRatio(this._time / duration);
12644                                 }
12645                                 
12646                         }
12647                                 
12648                         if (prevTime === this._time && !force && prevCycle === this._cycle) {
12649                                 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.
12650                                         this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
12651                                 }
12652                                 return;
12653                         } else if (!this._initted) {
12654                                 this._init();
12655                                 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.
12656                                         return;
12657                                 } 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.
12658                                         this._time = prevTime;
12659                                         this._totalTime = prevTotalTime;
12660                                         this._rawPrevTime = prevRawPrevTime;
12661                                         this._cycle = prevCycle;
12662                                         TweenLiteInternals.lazyTweens.push(this);
12663                                         this._lazy = time;
12664                                         return;
12665                                 }
12666                                 //_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.
12667                                 if (this._time && !isComplete) {
12668                                         this.ratio = this._ease.getRatio(this._time / duration);
12669                                 } else if (isComplete && this._ease._calcEnd) {
12670                                         this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1);
12671                                 }
12672                         }
12673                         if (this._lazy !== false) {
12674                                 this._lazy = false;
12675                         }
12676
12677                         if (!this._active) if (!this._paused && this._time !== prevTime && time >= 0) {
12678                                 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.
12679                         }
12680                         if (prevTotalTime === 0) {
12681                                 if (this._initted === 2 && time > 0) {
12682                                         //this.invalidate();
12683                                         this._init(); //will just apply overwriting since _initted of (2) means it was a from() tween that had immediateRender:true
12684                                 }
12685                                 if (this._startAt) {
12686                                         if (time >= 0) {
12687                                                 this._startAt.render(time, suppressEvents, force);
12688                                         } else if (!callback) {
12689                                                 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.
12690                                         }
12691                                 }
12692                                 if (this.vars.onStart) if (this._totalTime !== 0 || duration === 0) if (!suppressEvents) {
12693                                         this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
12694                                 }
12695                         }
12696                         
12697                         pt = this._firstPT;
12698                         while (pt) {
12699                                 if (pt.f) {
12700                                         pt.t[pt.p](pt.c * this.ratio + pt.s);
12701                                 } else {
12702                                         pt.t[pt.p] = pt.c * this.ratio + pt.s;
12703                                 }
12704                                 pt = pt._next;
12705                         }
12706                         
12707                         if (this._onUpdate) {
12708                                 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.
12709                                         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.
12710                                 }
12711                                 if (!suppressEvents) if (this._totalTime !== prevTotalTime || isComplete) {
12712                                         this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
12713                                 }
12714                         }
12715                         if (this._cycle !== prevCycle) if (!suppressEvents) if (!this._gc) if (this.vars.onRepeat) {
12716                                 this.vars.onRepeat.apply(this.vars.onRepeatScope || this, this.vars.onRepeatParams || _blankArray);
12717                         }
12718                         if (callback) if (!this._gc) { //check gc because there's a chance that kill() could be called in an onUpdate
12719                                 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.
12720                                         this._startAt.render(time, suppressEvents, force);
12721                                 }
12722                                 if (isComplete) {
12723                                         if (this._timeline.autoRemoveChildren) {
12724                                                 this._enabled(false, false);
12725                                         }
12726                                         this._active = false;
12727                                 }
12728                                 if (!suppressEvents && this.vars[callback]) {
12729                                         this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
12730                                 }
12731                                 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.
12732                                         this._rawPrevTime = 0;
12733                                 }
12734                         }
12735                 };
12736                 
12737 //---- STATIC FUNCTIONS -----------------------------------------------------------------------------------------------------------
12738                 
12739                 TweenMax.to = function(target, duration, vars) {
12740                         return new TweenMax(target, duration, vars);
12741                 };
12742                 
12743                 TweenMax.from = function(target, duration, vars) {
12744                         vars.runBackwards = true;
12745                         vars.immediateRender = (vars.immediateRender != false);
12746                         return new TweenMax(target, duration, vars);
12747                 };
12748                 
12749                 TweenMax.fromTo = function(target, duration, fromVars, toVars) {
12750                         toVars.startAt = fromVars;
12751                         toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
12752                         return new TweenMax(target, duration, toVars);
12753                 };
12754                 
12755                 TweenMax.staggerTo = TweenMax.allTo = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
12756                         stagger = stagger || 0;
12757                         var delay = vars.delay || 0,
12758                                 a = [],
12759                                 finalComplete = function() {
12760                                         if (vars.onComplete) {
12761                                                 vars.onComplete.apply(vars.onCompleteScope || this, arguments);
12762                                         }
12763                                         onCompleteAll.apply(onCompleteAllScope || this, onCompleteAllParams || _blankArray);
12764                                 },
12765                                 l, copy, i, p;
12766                         if (!_isArray(targets)) {
12767                                 if (typeof(targets) === "string") {
12768                                         targets = TweenLite.selector(targets) || targets;
12769                                 }
12770                                 if (_isSelector(targets)) {
12771                                         targets = _slice.call(targets, 0);
12772                                 }
12773                         }
12774                         l = targets.length;
12775                         for (i = 0; i < l; i++) {
12776                                 copy = {};
12777                                 for (p in vars) {
12778                                         copy[p] = vars[p];
12779                                 }
12780                                 copy.delay = delay;
12781                                 if (i === l - 1 && onCompleteAll) {
12782                                         copy.onComplete = finalComplete;
12783                                 }
12784                                 a[i] = new TweenMax(targets[i], duration, copy);
12785                                 delay += stagger;
12786                         }
12787                         return a;
12788                 };
12789                 
12790                 TweenMax.staggerFrom = TweenMax.allFrom = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
12791                         vars.runBackwards = true;
12792                         vars.immediateRender = (vars.immediateRender != false);
12793                         return TweenMax.staggerTo(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
12794                 };
12795                 
12796                 TweenMax.staggerFromTo = TweenMax.allFromTo = function(targets, duration, fromVars, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
12797                         toVars.startAt = fromVars;
12798                         toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
12799                         return TweenMax.staggerTo(targets, duration, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
12800                 };
12801                                 
12802                 TweenMax.delayedCall = function(delay, callback, params, scope, useFrames) {
12803                         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});
12804                 };
12805                 
12806                 TweenMax.set = function(target, vars) {
12807                         return new TweenMax(target, 0, vars);
12808                 };
12809                 
12810                 TweenMax.isTweening = function(target) {
12811                         return (TweenLite.getTweensOf(target, true).length > 0);
12812                 };
12813                 
12814                 var _getChildrenOf = function(timeline, includeTimelines) {
12815                                 var a = [],
12816                                         cnt = 0,
12817                                         tween = timeline._first;
12818                                 while (tween) {
12819                                         if (tween instanceof TweenLite) {
12820                                                 a[cnt++] = tween;
12821                                         } else {
12822                                                 if (includeTimelines) {
12823                                                         a[cnt++] = tween;
12824                                                 }
12825                                                 a = a.concat(_getChildrenOf(tween, includeTimelines));
12826                                                 cnt = a.length;
12827                                         }
12828                                         tween = tween._next;
12829                                 }
12830                                 return a;
12831                         }, 
12832                         getAllTweens = TweenMax.getAllTweens = function(includeTimelines) {
12833                                 return _getChildrenOf(Animation._rootTimeline, includeTimelines).concat( _getChildrenOf(Animation._rootFramesTimeline, includeTimelines) );
12834                         };
12835                 
12836                 TweenMax.killAll = function(complete, tweens, delayedCalls, timelines) {
12837                         if (tweens == null) {
12838                                 tweens = true;
12839                         }
12840                         if (delayedCalls == null) {
12841                                 delayedCalls = true;
12842                         }
12843                         var a = getAllTweens((timelines != false)),
12844                                 l = a.length,
12845                                 allTrue = (tweens && delayedCalls && timelines),
12846                                 isDC, tween, i;
12847                         for (i = 0; i < l; i++) {
12848                                 tween = a[i];
12849                                 if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) {
12850                                         if (complete) {
12851                                                 tween.totalTime(tween._reversed ? 0 : tween.totalDuration());
12852                                         } else {
12853                                                 tween._enabled(false, false);
12854                                         }
12855                                 }
12856                         }
12857                 };
12858                 
12859                 TweenMax.killChildTweensOf = function(parent, complete) {
12860                         if (parent == null) {
12861                                 return;
12862                         }
12863                         var tl = TweenLiteInternals.tweenLookup,
12864                                 a, curParent, p, i, l;
12865                         if (typeof(parent) === "string") {
12866                                 parent = TweenLite.selector(parent) || parent;
12867                         }
12868                         if (_isSelector(parent)) {
12869                                 parent = _slice.call(parent, 0);
12870                         }
12871                         if (_isArray(parent)) {
12872                                 i = parent.length;
12873                                 while (--i > -1) {
12874                                         TweenMax.killChildTweensOf(parent[i], complete);
12875                                 }
12876                                 return;
12877                         }
12878                         a = [];
12879                         for (p in tl) {
12880                                 curParent = tl[p].target.parentNode;
12881                                 while (curParent) {
12882                                         if (curParent === parent) {
12883                                                 a = a.concat(tl[p].tweens);
12884                                         }
12885                                         curParent = curParent.parentNode;
12886                                 }
12887                         }
12888                         l = a.length;
12889                         for (i = 0; i < l; i++) {
12890                                 if (complete) {
12891                                         a[i].totalTime(a[i].totalDuration());
12892                                 }
12893                                 a[i]._enabled(false, false);
12894                         }
12895                 };
12896
12897                 var _changePause = function(pause, tweens, delayedCalls, timelines) {
12898                         tweens = (tweens !== false);
12899                         delayedCalls = (delayedCalls !== false);
12900                         timelines = (timelines !== false);
12901                         var a = getAllTweens(timelines),
12902                                 allTrue = (tweens && delayedCalls && timelines),
12903                                 i = a.length,
12904                                 isDC, tween;
12905                         while (--i > -1) {
12906                                 tween = a[i];
12907                                 if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) {
12908                                         tween.paused(pause);
12909                                 }
12910                         }
12911                 };
12912                 
12913                 TweenMax.pauseAll = function(tweens, delayedCalls, timelines) {
12914                         _changePause(true, tweens, delayedCalls, timelines);
12915                 };
12916                 
12917                 TweenMax.resumeAll = function(tweens, delayedCalls, timelines) {
12918                         _changePause(false, tweens, delayedCalls, timelines);
12919                 };
12920
12921                 TweenMax.globalTimeScale = function(value) {
12922                         var tl = Animation._rootTimeline,
12923                                 t = TweenLite.ticker.time;
12924                         if (!arguments.length) {
12925                                 return tl._timeScale;
12926                         }
12927                         value = value || _tinyNum; //can't allow zero because it'll throw the math off
12928                         tl._startTime = t - ((t - tl._startTime) * tl._timeScale / value);
12929                         tl = Animation._rootFramesTimeline;
12930                         t = TweenLite.ticker.frame;
12931                         tl._startTime = t - ((t - tl._startTime) * tl._timeScale / value);
12932                         tl._timeScale = Animation._rootTimeline._timeScale = value;
12933                         return value;
12934                 };
12935                 
12936         
12937 //---- GETTERS / SETTERS ----------------------------------------------------------------------------------------------------------
12938                 
12939                 p.progress = function(value) {
12940                         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);
12941                 };
12942                 
12943                 p.totalProgress = function(value) {
12944                         return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, false);
12945                 };
12946                 
12947                 p.time = function(value, suppressEvents) {
12948                         if (!arguments.length) {
12949                                 return this._time;
12950                         }
12951                         if (this._dirty) {
12952                                 this.totalDuration();
12953                         }
12954                         if (value > this._duration) {
12955                                 value = this._duration;
12956                         }
12957                         if (this._yoyo && (this._cycle & 1) !== 0) {
12958                                 value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay));
12959                         } else if (this._repeat !== 0) {
12960                                 value += this._cycle * (this._duration + this._repeatDelay);
12961                         }
12962                         return this.totalTime(value, suppressEvents);
12963                 };
12964
12965                 p.duration = function(value) {
12966                         if (!arguments.length) {
12967                                 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.
12968                         }
12969                         return Animation.prototype.duration.call(this, value);
12970                 };
12971
12972                 p.totalDuration = function(value) {
12973                         if (!arguments.length) {
12974                                 if (this._dirty) {
12975                                         //instead of Infinity, we use 999999999999 so that we can accommodate reverses
12976                                         this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat);
12977                                         this._dirty = false;
12978                                 }
12979                                 return this._totalDuration;
12980                         }
12981                         return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) );
12982                 };
12983                 
12984                 p.repeat = function(value) {
12985                         if (!arguments.length) {
12986                                 return this._repeat;
12987                         }
12988                         this._repeat = value;
12989                         return this._uncache(true);
12990                 };
12991                 
12992                 p.repeatDelay = function(value) {
12993                         if (!arguments.length) {
12994                                 return this._repeatDelay;
12995                         }
12996                         this._repeatDelay = value;
12997                         return this._uncache(true);
12998                 };
12999                 
13000                 p.yoyo = function(value) {
13001                         if (!arguments.length) {
13002                                 return this._yoyo;
13003                         }
13004                         this._yoyo = value;
13005                         return this;
13006                 };
13007                 
13008                 
13009                 return TweenMax;
13010                 
13011         }, true);
13012
13013
13014
13015
13016
13017
13018
13019
13020 /*
13021  * ----------------------------------------------------------------
13022  * TimelineLite
13023  * ----------------------------------------------------------------
13024  */
13025         window._gsDefine("TimelineLite", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {
13026
13027                 var TimelineLite = function(vars) {
13028                                 SimpleTimeline.call(this, vars);
13029                                 this._labels = {};
13030                                 this.autoRemoveChildren = (this.vars.autoRemoveChildren === true);
13031                                 this.smoothChildTiming = (this.vars.smoothChildTiming === true);
13032                                 this._sortChildren = true;
13033                                 this._onUpdate = this.vars.onUpdate;
13034                                 var v = this.vars,
13035                                         val, p;
13036                                 for (p in v) {
13037                                         val = v[p];
13038                                         if (_isArray(val)) if (val.join("").indexOf("{self}") !== -1) {
13039                                                 v[p] = this._swapSelfInParams(val);
13040                                         }
13041                                 }
13042                                 if (_isArray(v.tweens)) {
13043                                         this.add(v.tweens, 0, v.align, v.stagger);
13044                                 }
13045                         },
13046                         _tinyNum = 0.0000000001,
13047                         _isSelector = TweenLite._internals.isSelector,
13048                         _isArray = TweenLite._internals.isArray,
13049                         _blankArray = [],
13050                         _globals = window._gsDefine.globals,
13051                         _copy = function(vars) {
13052                                 var copy = {}, p;
13053                                 for (p in vars) {
13054                                         copy[p] = vars[p];
13055                                 }
13056                                 return copy;
13057                         },
13058                         _pauseCallback = function(tween, callback, params, scope) {
13059                                 tween._timeline.pause(tween._startTime);
13060                                 if (callback) {
13061                                         callback.apply(scope || tween._timeline, params || _blankArray);
13062                                 }
13063                         },
13064                         _slice = _blankArray.slice,
13065                         p = TimelineLite.prototype = new SimpleTimeline();
13066
13067                 TimelineLite.version = "1.12.1";
13068                 p.constructor = TimelineLite;
13069                 p.kill()._gc = false;
13070
13071                 p.to = function(target, duration, vars, position) {
13072                         var Engine = (vars.repeat && _globals.TweenMax) || TweenLite;
13073                         return duration ? this.add( new Engine(target, duration, vars), position) : this.set(target, vars, position);
13074                 };
13075
13076                 p.from = function(target, duration, vars, position) {
13077                         return this.add( ((vars.repeat && _globals.TweenMax) || TweenLite).from(target, duration, vars), position);
13078                 };
13079
13080                 p.fromTo = function(target, duration, fromVars, toVars, position) {
13081                         var Engine = (toVars.repeat && _globals.TweenMax) || TweenLite;
13082                         return duration ? this.add( Engine.fromTo(target, duration, fromVars, toVars), position) : this.set(target, toVars, position);
13083                 };
13084
13085                 p.staggerTo = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
13086                         var tl = new TimelineLite({onComplete:onCompleteAll, onCompleteParams:onCompleteAllParams, onCompleteScope:onCompleteAllScope, smoothChildTiming:this.smoothChildTiming}),
13087                                 i;
13088                         if (typeof(targets) === "string") {
13089                                 targets = TweenLite.selector(targets) || targets;
13090                         }
13091                         if (_isSelector(targets)) { //senses if the targets object is a selector. If it is, we should translate it into an array.
13092                                 targets = _slice.call(targets, 0);
13093                         }
13094                         stagger = stagger || 0;
13095                         for (i = 0; i < targets.length; i++) {
13096                                 if (vars.startAt) {
13097                                         vars.startAt = _copy(vars.startAt);
13098                                 }
13099                                 tl.to(targets[i], duration, _copy(vars), i * stagger);
13100                         }
13101                         return this.add(tl, position);
13102                 };
13103
13104                 p.staggerFrom = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
13105                         vars.immediateRender = (vars.immediateRender != false);
13106                         vars.runBackwards = true;
13107                         return this.staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
13108                 };
13109
13110                 p.staggerFromTo = function(targets, duration, fromVars, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
13111                         toVars.startAt = fromVars;
13112                         toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
13113                         return this.staggerTo(targets, duration, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
13114                 };
13115
13116                 p.call = function(callback, params, scope, position) {
13117                         return this.add( TweenLite.delayedCall(0, callback, params, scope), position);
13118                 };
13119
13120                 p.set = function(target, vars, position) {
13121                         position = this._parseTimeOrLabel(position, 0, true);
13122                         if (vars.immediateRender == null) {
13123                                 vars.immediateRender = (position === this._time && !this._paused);
13124                         }
13125                         return this.add( new TweenLite(target, 0, vars), position);
13126                 };
13127
13128                 TimelineLite.exportRoot = function(vars, ignoreDelayedCalls) {
13129                         vars = vars || {};
13130                         if (vars.smoothChildTiming == null) {
13131                                 vars.smoothChildTiming = true;
13132                         }
13133                         var tl = new TimelineLite(vars),
13134                                 root = tl._timeline,
13135                                 tween, next;
13136                         if (ignoreDelayedCalls == null) {
13137                                 ignoreDelayedCalls = true;
13138                         }
13139                         root._remove(tl, true);
13140                         tl._startTime = 0;
13141                         tl._rawPrevTime = tl._time = tl._totalTime = root._time;
13142                         tween = root._first;
13143                         while (tween) {
13144                                 next = tween._next;
13145                                 if (!ignoreDelayedCalls || !(tween instanceof TweenLite && tween.target === tween.vars.onComplete)) {
13146                                         tl.add(tween, tween._startTime - tween._delay);
13147                                 }
13148                                 tween = next;
13149                         }
13150                         root.add(tl, 0);
13151                         return tl;
13152                 };
13153
13154                 p.add = function(value, position, align, stagger) {
13155                         var curTime, l, i, child, tl, beforeRawTime;
13156                         if (typeof(position) !== "number") {
13157                                 position = this._parseTimeOrLabel(position, 0, true, value);
13158                         }
13159                         if (!(value instanceof Animation)) {
13160                                 if ((value instanceof Array) || (value && value.push && _isArray(value))) {
13161                                         align = align || "normal";
13162                                         stagger = stagger || 0;
13163                                         curTime = position;
13164                                         l = value.length;
13165                                         for (i = 0; i < l; i++) {
13166                                                 if (_isArray(child = value[i])) {
13167                                                         child = new TimelineLite({tweens:child});
13168                                                 }
13169                                                 this.add(child, curTime);
13170                                                 if (typeof(child) !== "string" && typeof(child) !== "function") {
13171                                                         if (align === "sequence") {
13172                                                                 curTime = child._startTime + (child.totalDuration() / child._timeScale);
13173                                                         } else if (align === "start") {
13174                                                                 child._startTime -= child.delay();
13175                                                         }
13176                                                 }
13177                                                 curTime += stagger;
13178                                         }
13179                                         return this._uncache(true);
13180                                 } else if (typeof(value) === "string") {
13181                                         return this.addLabel(value, position);
13182                                 } else if (typeof(value) === "function") {
13183                                         value = TweenLite.delayedCall(0, value);
13184                                 } else {
13185                                         throw("Cannot add " + value + " into the timeline; it is not a tween, timeline, function, or string.");
13186                                 }
13187                         }
13188
13189                         SimpleTimeline.prototype.add.call(this, value, position);
13190
13191                         //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.
13192                         if (this._gc || this._time === this._duration) if (!this._paused) if (this._duration < this.duration()) {
13193                                 //in case any of the ancestors had completed but should now be enabled...
13194                                 tl = this;
13195                                 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.
13196                                 while (tl._timeline) {
13197                                         if (beforeRawTime && tl._timeline.smoothChildTiming) {
13198                                                 tl.totalTime(tl._totalTime, true); //moves the timeline (shifts its startTime) if necessary, and also enables it.
13199                                         } else if (tl._gc) {
13200                                                 tl._enabled(true, false);
13201                                         }
13202                                         tl = tl._timeline;
13203                                 }
13204                         }
13205
13206                         return this;
13207                 };
13208
13209                 p.remove = function(value) {
13210                         if (value instanceof Animation) {
13211                                 return this._remove(value, false);
13212                         } else if (value instanceof Array || (value && value.push && _isArray(value))) {
13213                                 var i = value.length;
13214                                 while (--i > -1) {
13215                                         this.remove(value[i]);
13216                                 }
13217                                 return this;
13218                         } else if (typeof(value) === "string") {
13219                                 return this.removeLabel(value);
13220                         }
13221                         return this.kill(null, value);
13222                 };
13223
13224                 p._remove = function(tween, skipDisable) {
13225                         SimpleTimeline.prototype._remove.call(this, tween, skipDisable);
13226                         var last = this._last;
13227                         if (!last) {
13228                                 this._time = this._totalTime = this._duration = this._totalDuration = 0;
13229                         } else if (this._time > last._startTime + last._totalDuration / last._timeScale) {
13230                                 this._time = this.duration();
13231                                 this._totalTime = this._totalDuration;
13232                         }
13233                         return this;
13234                 };
13235
13236                 p.append = function(value, offsetOrLabel) {
13237                         return this.add(value, this._parseTimeOrLabel(null, offsetOrLabel, true, value));
13238                 };
13239
13240                 p.insert = p.insertMultiple = function(value, position, align, stagger) {
13241                         return this.add(value, position || 0, align, stagger);
13242                 };
13243
13244                 p.appendMultiple = function(tweens, offsetOrLabel, align, stagger) {
13245                         return this.add(tweens, this._parseTimeOrLabel(null, offsetOrLabel, true, tweens), align, stagger);
13246                 };
13247
13248                 p.addLabel = function(label, position) {
13249                         this._labels[label] = this._parseTimeOrLabel(position);
13250                         return this;
13251                 };
13252
13253                 p.addPause = function(position, callback, params, scope) {
13254                         return this.call(_pauseCallback, ["{self}", callback, params, scope], this, position);
13255                 };
13256
13257                 p.removeLabel = function(label) {
13258                         delete this._labels[label];
13259                         return this;
13260                 };
13261
13262                 p.getLabelTime = function(label) {
13263                         return (this._labels[label] != null) ? this._labels[label] : -1;
13264                 };
13265
13266                 p._parseTimeOrLabel = function(timeOrLabel, offsetOrLabel, appendIfAbsent, ignore) {
13267                         var i;
13268                         //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().
13269                         if (ignore instanceof Animation && ignore.timeline === this) {
13270                                 this.remove(ignore);
13271                         } else if (ignore && ((ignore instanceof Array) || (ignore.push && _isArray(ignore)))) {
13272                                 i = ignore.length;
13273                                 while (--i > -1) {
13274                                         if (ignore[i] instanceof Animation && ignore[i].timeline === this) {
13275                                                 this.remove(ignore[i]);
13276                                         }
13277                                 }
13278                         }
13279                         if (typeof(offsetOrLabel) === "string") {
13280                                 return this._parseTimeOrLabel(offsetOrLabel, (appendIfAbsent && typeof(timeOrLabel) === "number" && this._labels[offsetOrLabel] == null) ? timeOrLabel - this.duration() : 0, appendIfAbsent);
13281                         }
13282                         offsetOrLabel = offsetOrLabel || 0;
13283                         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).
13284                                 i = timeOrLabel.indexOf("=");
13285                                 if (i === -1) {
13286                                         if (this._labels[timeOrLabel] == null) {
13287                                                 return appendIfAbsent ? (this._labels[timeOrLabel] = this.duration() + offsetOrLabel) : offsetOrLabel;
13288                                         }
13289                                         return this._labels[timeOrLabel] + offsetOrLabel;
13290                                 }
13291                                 offsetOrLabel = parseInt(timeOrLabel.charAt(i-1) + "1", 10) * Number(timeOrLabel.substr(i+1));
13292                                 timeOrLabel = (i > 1) ? this._parseTimeOrLabel(timeOrLabel.substr(0, i-1), 0, appendIfAbsent) : this.duration();
13293                         } else if (timeOrLabel == null) {
13294                                 timeOrLabel = this.duration();
13295                         }
13296                         return Number(timeOrLabel) + offsetOrLabel;
13297                 };
13298
13299                 p.seek = function(position, suppressEvents) {
13300                         return this.totalTime((typeof(position) === "number") ? position : this._parseTimeOrLabel(position), (suppressEvents !== false));
13301                 };
13302
13303                 p.stop = function() {
13304                         return this.paused(true);
13305                 };
13306
13307                 p.gotoAndPlay = function(position, suppressEvents) {
13308                         return this.play(position, suppressEvents);
13309                 };
13310
13311                 p.gotoAndStop = function(position, suppressEvents) {
13312                         return this.pause(position, suppressEvents);
13313                 };
13314
13315                 p.render = function(time, suppressEvents, force) {
13316                         if (this._gc) {
13317                                 this._enabled(true, false);
13318                         }
13319                         var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
13320                                 prevTime = this._time,
13321                                 prevStart = this._startTime,
13322                                 prevTimeScale = this._timeScale,
13323                                 prevPaused = this._paused,
13324                                 tween, isComplete, next, callback, internalForce;
13325                         if (time >= totalDur) {
13326                                 this._totalTime = this._time = totalDur;
13327                                 if (!this._reversed) if (!this._hasPausedChild()) {
13328                                         isComplete = true;
13329                                         callback = "onComplete";
13330                                         if (this._duration === 0) if (time === 0 || this._rawPrevTime < 0 || this._rawPrevTime === _tinyNum) if (this._rawPrevTime !== time && this._first) {
13331                                                 internalForce = true;
13332                                                 if (this._rawPrevTime > _tinyNum) {
13333                                                         callback = "onReverseComplete";
13334                                                 }
13335                                         }
13336                                 }
13337                                 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.
13338                                 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.
13339
13340                         } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
13341                                 this._totalTime = this._time = 0;
13342                                 if (prevTime !== 0 || (this._duration === 0 && this._rawPrevTime !== _tinyNum && (this._rawPrevTime > 0 || (time < 0 && this._rawPrevTime >= 0)))) {
13343                                         callback = "onReverseComplete";
13344                                         isComplete = this._reversed;
13345                                 }
13346                                 if (time < 0) {
13347                                         this._active = false;
13348                                         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.
13349                                                 internalForce = true;
13350                                         }
13351                                         this._rawPrevTime = time;
13352                                 } else {
13353                                         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.
13354
13355                                         time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline)
13356                                         if (!this._initted) {
13357                                                 internalForce = true;
13358                                         }
13359                                 }
13360
13361                         } else {
13362                                 this._totalTime = this._time = this._rawPrevTime = time;
13363                         }
13364                         if ((this._time === prevTime || !this._first) && !force && !internalForce) {
13365                                 return;
13366                         } else if (!this._initted) {
13367                                 this._initted = true;
13368                         }
13369
13370                         if (!this._active) if (!this._paused && this._time !== prevTime && time > 0) {
13371                                 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.
13372                         }
13373
13374                         if (prevTime === 0) if (this.vars.onStart) if (this._time !== 0) if (!suppressEvents) {
13375                                 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
13376                         }
13377
13378                         if (this._time >= prevTime) {
13379                                 tween = this._first;
13380                                 while (tween) {
13381                                         next = tween._next; //record it here because the value could change after rendering...
13382                                         if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
13383                                                 break;
13384                                         } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) {
13385                                                 if (!tween._reversed) {
13386                                                         tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
13387                                                 } else {
13388                                                         tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
13389                                                 }
13390                                         }
13391                                         tween = next;
13392                                 }
13393                         } else {
13394                                 tween = this._last;
13395                                 while (tween) {
13396                                         next = tween._prev; //record it here because the value could change after rendering...
13397                                         if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
13398                                                 break;
13399                                         } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) {
13400                                                 if (!tween._reversed) {
13401                                                         tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
13402                                                 } else {
13403                                                         tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
13404                                                 }
13405                                         }
13406                                         tween = next;
13407                                 }
13408                         }
13409
13410                         if (this._onUpdate) if (!suppressEvents) {
13411                                 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
13412                         }
13413
13414                         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
13415                                 if (isComplete) {
13416                                         if (this._timeline.autoRemoveChildren) {
13417                                                 this._enabled(false, false);
13418                                         }
13419                                         this._active = false;
13420                                 }
13421                                 if (!suppressEvents && this.vars[callback]) {
13422                                         this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
13423                                 }
13424                         }
13425                 };
13426
13427                 p._hasPausedChild = function() {
13428                         var tween = this._first;
13429                         while (tween) {
13430                                 if (tween._paused || ((tween instanceof TimelineLite) && tween._hasPausedChild())) {
13431                                         return true;
13432                                 }
13433                                 tween = tween._next;
13434                         }
13435                         return false;
13436                 };
13437
13438                 p.getChildren = function(nested, tweens, timelines, ignoreBeforeTime) {
13439                         ignoreBeforeTime = ignoreBeforeTime || -9999999999;
13440                         var a = [],
13441                                 tween = this._first,
13442                                 cnt = 0;
13443                         while (tween) {
13444                                 if (tween._startTime < ignoreBeforeTime) {
13445                                         //do nothing
13446                                 } else if (tween instanceof TweenLite) {
13447                                         if (tweens !== false) {
13448                                                 a[cnt++] = tween;
13449                                         }
13450                                 } else {
13451                                         if (timelines !== false) {
13452                                                 a[cnt++] = tween;
13453                                         }
13454                                         if (nested !== false) {
13455                                                 a = a.concat(tween.getChildren(true, tweens, timelines));
13456                                                 cnt = a.length;
13457                                         }
13458                                 }
13459                                 tween = tween._next;
13460                         }
13461                         return a;
13462                 };
13463
13464                 p.getTweensOf = function(target, nested) {
13465                         var disabled = this._gc,
13466                                 a = [],
13467                                 cnt = 0,
13468                                 tweens, i;
13469                         if (disabled) {
13470                                 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.
13471                         }
13472                         tweens = TweenLite.getTweensOf(target);
13473                         i = tweens.length;
13474                         while (--i > -1) {
13475                                 if (tweens[i].timeline === this || (nested && this._contains(tweens[i]))) {
13476                                         a[cnt++] = tweens[i];
13477                                 }
13478                         }
13479                         if (disabled) {
13480                                 this._enabled(false, true);
13481                         }
13482                         return a;
13483                 };
13484
13485                 p._contains = function(tween) {
13486                         var tl = tween.timeline;
13487                         while (tl) {
13488                                 if (tl === this) {
13489                                         return true;
13490                                 }
13491                                 tl = tl.timeline;
13492                         }
13493                         return false;
13494                 };
13495
13496                 p.shiftChildren = function(amount, adjustLabels, ignoreBeforeTime) {
13497                         ignoreBeforeTime = ignoreBeforeTime || 0;
13498                         var tween = this._first,
13499                                 labels = this._labels,
13500                                 p;
13501                         while (tween) {
13502                                 if (tween._startTime >= ignoreBeforeTime) {
13503                                         tween._startTime += amount;
13504                                 }
13505                                 tween = tween._next;
13506                         }
13507                         if (adjustLabels) {
13508                                 for (p in labels) {
13509                                         if (labels[p] >= ignoreBeforeTime) {
13510                                                 labels[p] += amount;
13511                                         }
13512                                 }
13513                         }
13514                         return this._uncache(true);
13515                 };
13516
13517                 p._kill = function(vars, target) {
13518                         if (!vars && !target) {
13519                                 return this._enabled(false, false);
13520                         }
13521                         var tweens = (!target) ? this.getChildren(true, true, false) : this.getTweensOf(target),
13522                                 i = tweens.length,
13523                                 changed = false;
13524                         while (--i > -1) {
13525                                 if (tweens[i]._kill(vars, target)) {
13526                                         changed = true;
13527                                 }
13528                         }
13529                         return changed;
13530                 };
13531
13532                 p.clear = function(labels) {
13533                         var tweens = this.getChildren(false, true, true),
13534                                 i = tweens.length;
13535                         this._time = this._totalTime = 0;
13536                         while (--i > -1) {
13537                                 tweens[i]._enabled(false, false);
13538                         }
13539                         if (labels !== false) {
13540                                 this._labels = {};
13541                         }
13542                         return this._uncache(true);
13543                 };
13544
13545                 p.invalidate = function() {
13546                         var tween = this._first;
13547                         while (tween) {
13548                                 tween.invalidate();
13549                                 tween = tween._next;
13550                         }
13551                         return this;
13552                 };
13553
13554                 p._enabled = function(enabled, ignoreTimeline) {
13555                         if (enabled === this._gc) {
13556                                 var tween = this._first;
13557                                 while (tween) {
13558                                         tween._enabled(enabled, true);
13559                                         tween = tween._next;
13560                                 }
13561                         }
13562                         return SimpleTimeline.prototype._enabled.call(this, enabled, ignoreTimeline);
13563                 };
13564
13565                 p.duration = function(value) {
13566                         if (!arguments.length) {
13567                                 if (this._dirty) {
13568                                         this.totalDuration(); //just triggers recalculation
13569                                 }
13570                                 return this._duration;
13571                         }
13572                         if (this.duration() !== 0 && value !== 0) {
13573                                 this.timeScale(this._duration / value);
13574                         }
13575                         return this;
13576                 };
13577
13578                 p.totalDuration = function(value) {
13579                         if (!arguments.length) {
13580                                 if (this._dirty) {
13581                                         var max = 0,
13582                                                 tween = this._last,
13583                                                 prevStart = 999999999999,
13584                                                 prev, end;
13585                                         while (tween) {
13586                                                 prev = tween._prev; //record it here in case the tween changes position in the sequence...
13587                                                 if (tween._dirty) {
13588                                                         tween.totalDuration(); //could change the tween._startTime, so make sure the tween's cache is clean before analyzing it.
13589                                                 }
13590                                                 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
13591                                                         this.add(tween, tween._startTime - tween._delay);
13592                                                 } else {
13593                                                         prevStart = tween._startTime;
13594                                                 }
13595                                                 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.
13596                                                         max -= tween._startTime;
13597                                                         if (this._timeline.smoothChildTiming) {
13598                                                                 this._startTime += tween._startTime / this._timeScale;
13599                                                         }
13600                                                         this.shiftChildren(-tween._startTime, false, -9999999999);
13601                                                         prevStart = 0;
13602                                                 }
13603                                                 end = tween._startTime + (tween._totalDuration / tween._timeScale);
13604                                                 if (end > max) {
13605                                                         max = end;
13606                                                 }
13607                                                 tween = prev;
13608                                         }
13609                                         this._duration = this._totalDuration = max;
13610                                         this._dirty = false;
13611                                 }
13612                                 return this._totalDuration;
13613                         }
13614                         if (this.totalDuration() !== 0) if (value !== 0) {
13615                                 this.timeScale(this._totalDuration / value);
13616                         }
13617                         return this;
13618                 };
13619
13620                 p.usesFrames = function() {
13621                         var tl = this._timeline;
13622                         while (tl._timeline) {
13623                                 tl = tl._timeline;
13624                         }
13625                         return (tl === Animation._rootFramesTimeline);
13626                 };
13627
13628                 p.rawTime = function() {
13629                         return this._paused ? this._totalTime : (this._timeline.rawTime() - this._startTime) * this._timeScale;
13630                 };
13631
13632                 return TimelineLite;
13633
13634         }, true);
13635         
13636
13637
13638
13639
13640
13641
13642
13643         
13644         
13645         
13646         
13647         
13648 /*
13649  * ----------------------------------------------------------------
13650  * TimelineMax
13651  * ----------------------------------------------------------------
13652  */
13653         window._gsDefine("TimelineMax", ["TimelineLite","TweenLite","easing.Ease"], function(TimelineLite, TweenLite, Ease) {
13654
13655                 var TimelineMax = function(vars) {
13656                                 TimelineLite.call(this, vars);
13657                                 this._repeat = this.vars.repeat || 0;
13658                                 this._repeatDelay = this.vars.repeatDelay || 0;
13659                                 this._cycle = 0;
13660                                 this._yoyo = (this.vars.yoyo === true);
13661                                 this._dirty = true;
13662                         },
13663                         _tinyNum = 0.0000000001,
13664                         _blankArray = [],
13665                         _easeNone = new Ease(null, null, 1, 0),
13666                         p = TimelineMax.prototype = new TimelineLite();
13667
13668                 p.constructor = TimelineMax;
13669                 p.kill()._gc = false;
13670                 TimelineMax.version = "1.12.1";
13671
13672                 p.invalidate = function() {
13673                         this._yoyo = (this.vars.yoyo === true);
13674                         this._repeat = this.vars.repeat || 0;
13675                         this._repeatDelay = this.vars.repeatDelay || 0;
13676                         this._uncache(true);
13677                         return TimelineLite.prototype.invalidate.call(this);
13678                 };
13679
13680                 p.addCallback = function(callback, position, params, scope) {
13681                         return this.add( TweenLite.delayedCall(0, callback, params, scope), position);
13682                 };
13683
13684                 p.removeCallback = function(callback, position) {
13685                         if (callback) {
13686                                 if (position == null) {
13687                                         this._kill(null, callback);
13688                                 } else {
13689                                         var a = this.getTweensOf(callback, false),
13690                                                 i = a.length,
13691                                                 time = this._parseTimeOrLabel(position);
13692                                         while (--i > -1) {
13693                                                 if (a[i]._startTime === time) {
13694                                                         a[i]._enabled(false, false);
13695                                                 }
13696                                         }
13697                                 }
13698                         }
13699                         return this;
13700                 };
13701
13702                 p.tweenTo = function(position, vars) {
13703                         vars = vars || {};
13704                         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.
13705                                 duration, p, t;
13706                         for (p in vars) {
13707                                 copy[p] = vars[p];
13708                         }
13709                         copy.time = this._parseTimeOrLabel(position);
13710                         duration = (Math.abs(Number(copy.time) - this._time) / this._timeScale) || 0.001;
13711                         t = new TweenLite(this, duration, copy);
13712                         copy.onStart = function() {
13713                                 t.target.paused(true);
13714                                 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.
13715                                         t.duration( Math.abs( t.vars.time - t.target.time()) / t.target._timeScale );
13716                                 }
13717                                 if (vars.onStart) { //in case the user had an onStart in the vars - we don't want to overwrite it.
13718                                         vars.onStart.apply(vars.onStartScope || t, vars.onStartParams || _blankArray);
13719                                 }
13720                         };
13721                         return t;
13722                 };
13723
13724                 p.tweenFromTo = function(fromPosition, toPosition, vars) {
13725                         vars = vars || {};
13726                         fromPosition = this._parseTimeOrLabel(fromPosition);
13727                         vars.startAt = {onComplete:this.seek, onCompleteParams:[fromPosition], onCompleteScope:this};
13728                         vars.immediateRender = (vars.immediateRender !== false);
13729                         var t = this.tweenTo(toPosition, vars);
13730                         return t.duration((Math.abs( t.vars.time - fromPosition) / this._timeScale) || 0.001);
13731                 };
13732
13733                 p.render = function(time, suppressEvents, force) {
13734                         if (this._gc) {
13735                                 this._enabled(true, false);
13736                         }
13737                         var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
13738                                 dur = this._duration,
13739                                 prevTime = this._time,
13740                                 prevTotalTime = this._totalTime,
13741                                 prevStart = this._startTime,
13742                                 prevTimeScale = this._timeScale,
13743                                 prevRawPrevTime = this._rawPrevTime,
13744                                 prevPaused = this._paused,
13745                                 prevCycle = this._cycle,
13746                                 tween, isComplete, next, callback, internalForce, cycleDuration;
13747                         if (time >= totalDur) {
13748                                 if (!this._locked) {
13749                                         this._totalTime = totalDur;
13750                                         this._cycle = this._repeat;
13751                                 }
13752                                 if (!this._reversed) if (!this._hasPausedChild()) {
13753                                         isComplete = true;
13754                                         callback = "onComplete";
13755                                         if (this._duration === 0) if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time && this._first) {
13756                                                 internalForce = true;
13757                                                 if (prevRawPrevTime > _tinyNum) {
13758                                                         callback = "onReverseComplete";
13759                                                 }
13760                                         }
13761                                 }
13762                                 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.
13763                                 if (this._yoyo && (this._cycle & 1) !== 0) {
13764                                         this._time = time = 0;
13765                                 } else {
13766                                         this._time = dur;
13767                                         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.
13768                                 }
13769
13770                         } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
13771                                 if (!this._locked) {
13772                                         this._totalTime = this._cycle = 0;
13773                                 }
13774                                 this._time = 0;
13775                                 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)
13776                                         callback = "onReverseComplete";
13777                                         isComplete = this._reversed;
13778                                 }
13779                                 if (time < 0) {
13780                                         this._active = false;
13781                                         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.
13782                                                 internalForce = true;
13783                                         }
13784                                         this._rawPrevTime = time;
13785                                 } else {
13786                                         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.
13787                                         time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline)
13788                                         if (!this._initted) {
13789                                                 internalForce = true;
13790                                         }
13791                                 }
13792
13793                         } else {
13794                                 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.
13795                                         internalForce = true;
13796                                 }
13797                                 this._time = this._rawPrevTime = time;
13798                                 if (!this._locked) {
13799                                         this._totalTime = time;
13800                                         if (this._repeat !== 0) {
13801                                                 cycleDuration = dur + this._repeatDelay;
13802                                                 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!)
13803                                                 if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) {
13804                                                         this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning)
13805                                                 }
13806                                                 this._time = this._totalTime - (this._cycle * cycleDuration);
13807                                                 if (this._yoyo) if ((this._cycle & 1) !== 0) {
13808                                                         this._time = dur - this._time;
13809                                                 }
13810                                                 if (this._time > dur) {
13811                                                         this._time = dur;
13812                                                         time = dur + 0.0001; //to avoid occasional floating point rounding error
13813                                                 } else if (this._time < 0) {
13814                                                         this._time = time = 0;
13815                                                 } else {
13816                                                         time = this._time;
13817                                                 }
13818                                         }
13819                                 }
13820                         }
13821
13822                         if (this._cycle !== prevCycle) if (!this._locked) {
13823                                 /*
13824                                 make sure children at the end/beginning of the timeline are rendered properly. If, for example,
13825                                 a 3-second long timeline rendered at 2.9 seconds previously, and now renders at 3.2 seconds (which
13826                                 would get transated to 2.8 seconds if the timeline yoyos or 0.2 seconds if it just repeats), there
13827                                 could be a callback or a short tween that's at 2.95 or 3 seconds in which wouldn't render. So
13828                                 we need to push the timeline to the end (and/or beginning depending on its yoyo value). Also we must
13829                                 ensure that zero-duration tweens at the very beginning or end of the TimelineMax work.
13830                                 */
13831                                 var backwards = (this._yoyo && (prevCycle & 1) !== 0),
13832                                         wrap = (backwards === (this._yoyo && (this._cycle & 1) !== 0)),
13833                                         recTotalTime = this._totalTime,
13834                                         recCycle = this._cycle,
13835                                         recRawPrevTime = this._rawPrevTime,
13836                                         recTime = this._time;
13837
13838                                 this._totalTime = prevCycle * dur;
13839                                 if (this._cycle < prevCycle) {
13840                                         backwards = !backwards;
13841                                 } else {
13842                                         this._totalTime += dur;
13843                                 }
13844                                 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.
13845
13846                                 this._rawPrevTime = (dur === 0) ? prevRawPrevTime - 0.0001 : prevRawPrevTime;
13847                                 this._cycle = prevCycle;
13848                                 this._locked = true; //prevents changes to totalTime and skips repeat/yoyo behavior when we recursively call render()
13849                                 prevTime = (backwards) ? 0 : dur;
13850                                 this.render(prevTime, suppressEvents, (dur === 0));
13851                                 if (!suppressEvents) if (!this._gc) {
13852                                         if (this.vars.onRepeat) {
13853                                                 this.vars.onRepeat.apply(this.vars.onRepeatScope || this, this.vars.onRepeatParams || _blankArray);
13854                                         }
13855                                 }
13856                                 if (wrap) {
13857                                         prevTime = (backwards) ? dur + 0.0001 : -0.0001;
13858                                         this.render(prevTime, true, false);
13859                                 }
13860                                 this._locked = false;
13861                                 if (this._paused && !prevPaused) { //if the render() triggered callback that paused this timeline, we should abort (very rare, but possible)
13862                                         return;
13863                                 }
13864                                 this._time = recTime;
13865                                 this._totalTime = recTotalTime;
13866                                 this._cycle = recCycle;
13867                                 this._rawPrevTime = recRawPrevTime;
13868                         }
13869
13870                         if ((this._time === prevTime || !this._first) && !force && !internalForce) {
13871                                 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.
13872                                         this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
13873                                 }
13874                                 return;
13875                         } else if (!this._initted) {
13876                                 this._initted = true;
13877                         }
13878
13879                         if (!this._active) if (!this._paused && this._totalTime !== prevTotalTime && time > 0) {
13880                                 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.
13881                         }
13882
13883                         if (prevTotalTime === 0) if (this.vars.onStart) if (this._totalTime !== 0) if (!suppressEvents) {
13884                                 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
13885                         }
13886
13887                         if (this._time >= prevTime) {
13888                                 tween = this._first;
13889                                 while (tween) {
13890                                         next = tween._next; //record it here because the value could change after rendering...
13891                                         if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
13892                                                 break;
13893                                         } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) {
13894                                                 if (!tween._reversed) {
13895                                                         tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
13896                                                 } else {
13897                                                         tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
13898                                                 }
13899
13900                                         }
13901                                         tween = next;
13902                                 }
13903                         } else {
13904                                 tween = this._last;
13905                                 while (tween) {
13906                                         next = tween._prev; //record it here because the value could change after rendering...
13907                                         if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
13908                                                 break;
13909                                         } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) {
13910                                                 if (!tween._reversed) {
13911                                                         tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
13912                                                 } else {
13913                                                         tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
13914                                                 }
13915                                         }
13916                                         tween = next;
13917                                 }
13918                         }
13919
13920                         if (this._onUpdate) if (!suppressEvents) {
13921                                 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
13922                         }
13923                         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
13924                                 if (isComplete) {
13925                                         if (this._timeline.autoRemoveChildren) {
13926                                                 this._enabled(false, false);
13927                                         }
13928                                         this._active = false;
13929                                 }
13930                                 if (!suppressEvents && this.vars[callback]) {
13931                                         this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
13932                                 }
13933                         }
13934                 };
13935
13936                 p.getActive = function(nested, tweens, timelines) {
13937                         if (nested == null) {
13938                                 nested = true;
13939                         }
13940                         if (tweens == null) {
13941                                 tweens = true;
13942                         }
13943                         if (timelines == null) {
13944                                 timelines = false;
13945                         }
13946                         var a = [],
13947                                 all = this.getChildren(nested, tweens, timelines),
13948                                 cnt = 0,
13949                                 l = all.length,
13950                                 i, tween;
13951                         for (i = 0; i < l; i++) {
13952                                 tween = all[i];
13953                                 if (tween.isActive()) {
13954                                         a[cnt++] = tween;
13955                                 }
13956                         }
13957                         return a;
13958                 };
13959
13960
13961                 p.getLabelAfter = function(time) {
13962                         if (!time) if (time !== 0) { //faster than isNan()
13963                                 time = this._time;
13964                         }
13965                         var labels = this.getLabelsArray(),
13966                                 l = labels.length,
13967                                 i;
13968                         for (i = 0; i < l; i++) {
13969                                 if (labels[i].time > time) {
13970                                         return labels[i].name;
13971                                 }
13972                         }
13973                         return null;
13974                 };
13975
13976                 p.getLabelBefore = function(time) {
13977                         if (time == null) {
13978                                 time = this._time;
13979                         }
13980                         var labels = this.getLabelsArray(),
13981                                 i = labels.length;
13982                         while (--i > -1) {
13983                                 if (labels[i].time < time) {
13984                                         return labels[i].name;
13985                                 }
13986                         }
13987                         return null;
13988                 };
13989
13990                 p.getLabelsArray = function() {
13991                         var a = [],
13992                                 cnt = 0,
13993                                 p;
13994                         for (p in this._labels) {
13995                                 a[cnt++] = {time:this._labels[p], name:p};
13996                         }
13997                         a.sort(function(a,b) {
13998                                 return a.time - b.time;
13999                         });
14000                         return a;
14001                 };
14002
14003
14004 //---- GETTERS / SETTERS -------------------------------------------------------------------------------------------------------
14005
14006                 p.progress = function(value) {
14007                         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);
14008                 };
14009
14010                 p.totalProgress = function(value) {
14011                         return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, false);
14012                 };
14013
14014                 p.totalDuration = function(value) {
14015                         if (!arguments.length) {
14016                                 if (this._dirty) {
14017                                         TimelineLite.prototype.totalDuration.call(this); //just forces refresh
14018                                         //Instead of Infinity, we use 999999999999 so that we can accommodate reverses.
14019                                         this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat);
14020                                 }
14021                                 return this._totalDuration;
14022                         }
14023                         return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) );
14024                 };
14025
14026                 p.time = function(value, suppressEvents) {
14027                         if (!arguments.length) {
14028                                 return this._time;
14029                         }
14030                         if (this._dirty) {
14031                                 this.totalDuration();
14032                         }
14033                         if (value > this._duration) {
14034                                 value = this._duration;
14035                         }
14036                         if (this._yoyo && (this._cycle & 1) !== 0) {
14037                                 value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay));
14038                         } else if (this._repeat !== 0) {
14039                                 value += this._cycle * (this._duration + this._repeatDelay);
14040                         }
14041                         return this.totalTime(value, suppressEvents);
14042                 };
14043
14044                 p.repeat = function(value) {
14045                         if (!arguments.length) {
14046                                 return this._repeat;
14047                         }
14048                         this._repeat = value;
14049                         return this._uncache(true);
14050                 };
14051
14052                 p.repeatDelay = function(value) {
14053                         if (!arguments.length) {
14054                                 return this._repeatDelay;
14055                         }
14056                         this._repeatDelay = value;
14057                         return this._uncache(true);
14058                 };
14059
14060                 p.yoyo = function(value) {
14061                         if (!arguments.length) {
14062                                 return this._yoyo;
14063                         }
14064                         this._yoyo = value;
14065                         return this;
14066                 };
14067
14068                 p.currentLabel = function(value) {
14069                         if (!arguments.length) {
14070                                 return this.getLabelBefore(this._time + 0.00000001);
14071                         }
14072                         return this.seek(value, true);
14073                 };
14074
14075                 return TimelineMax;
14076
14077         }, true);
14078         
14079
14080
14081
14082
14083         
14084         
14085         
14086         
14087         
14088         
14089         
14090 /*
14091  * ----------------------------------------------------------------
14092  * BezierPlugin
14093  * ----------------------------------------------------------------
14094  */
14095         (function() {
14096
14097                 var _RAD2DEG = 180 / Math.PI,
14098                         _r1 = [],
14099                         _r2 = [],
14100                         _r3 = [],
14101                         _corProps = {},
14102                         Segment = function(a, b, c, d) {
14103                                 this.a = a;
14104                                 this.b = b;
14105                                 this.c = c;
14106                                 this.d = d;
14107                                 this.da = d - a;
14108                                 this.ca = c - a;
14109                                 this.ba = b - a;
14110                         },
14111                         _correlate = ",x,y,z,left,top,right,bottom,marginTop,marginLeft,marginRight,marginBottom,paddingLeft,paddingTop,paddingRight,paddingBottom,backgroundPosition,backgroundPosition_y,",
14112                         cubicToQuadratic = function(a, b, c, d) {
14113                                 var q1 = {a:a},
14114                                         q2 = {},
14115                                         q3 = {},
14116                                         q4 = {c:d},
14117                                         mab = (a + b) / 2,
14118                                         mbc = (b + c) / 2,
14119                                         mcd = (c + d) / 2,
14120                                         mabc = (mab + mbc) / 2,
14121                                         mbcd = (mbc + mcd) / 2,
14122                                         m8 = (mbcd - mabc) / 8;
14123                                 q1.b = mab + (a - mab) / 4;
14124                                 q2.b = mabc + m8;
14125                                 q1.c = q2.a = (q1.b + q2.b) / 2;
14126                                 q2.c = q3.a = (mabc + mbcd) / 2;
14127                                 q3.b = mbcd - m8;
14128                                 q4.b = mcd + (d - mcd) / 4;
14129                                 q3.c = q4.a = (q3.b + q4.b) / 2;
14130                                 return [q1, q2, q3, q4];
14131                         },
14132                         _calculateControlPoints = function(a, curviness, quad, basic, correlate) {
14133                                 var l = a.length - 1,
14134                                         ii = 0,
14135                                         cp1 = a[0].a,
14136                                         i, p1, p2, p3, seg, m1, m2, mm, cp2, qb, r1, r2, tl;
14137                                 for (i = 0; i < l; i++) {
14138                                         seg = a[ii];
14139                                         p1 = seg.a;
14140                                         p2 = seg.d;
14141                                         p3 = a[ii+1].d;
14142
14143                                         if (correlate) {
14144                                                 r1 = _r1[i];
14145                                                 r2 = _r2[i];
14146                                                 tl = ((r2 + r1) * curviness * 0.25) / (basic ? 0.5 : _r3[i] || 0.5);
14147                                                 m1 = p2 - (p2 - p1) * (basic ? curviness * 0.5 : (r1 !== 0 ? tl / r1 : 0));
14148                                                 m2 = p2 + (p3 - p2) * (basic ? curviness * 0.5 : (r2 !== 0 ? tl / r2 : 0));
14149                                                 mm = p2 - (m1 + (((m2 - m1) * ((r1 * 3 / (r1 + r2)) + 0.5) / 4) || 0));
14150                                         } else {
14151                                                 m1 = p2 - (p2 - p1) * curviness * 0.5;
14152                                                 m2 = p2 + (p3 - p2) * curviness * 0.5;
14153                                                 mm = p2 - (m1 + m2) / 2;
14154                                         }
14155                                         m1 += mm;
14156                                         m2 += mm;
14157
14158                                         seg.c = cp2 = m1;
14159                                         if (i !== 0) {
14160                                                 seg.b = cp1;
14161                                         } else {
14162                                                 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.
14163                                         }
14164
14165                                         seg.da = p2 - p1;
14166                                         seg.ca = cp2 - p1;
14167                                         seg.ba = cp1 - p1;
14168
14169                                         if (quad) {
14170                                                 qb = cubicToQuadratic(p1, cp1, cp2, p2);
14171                                                 a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]);
14172                                                 ii += 4;
14173                                         } else {
14174                                                 ii++;
14175                                         }
14176
14177                                         cp1 = m2;
14178                                 }
14179                                 seg = a[ii];
14180                                 seg.b = cp1;
14181                                 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.
14182                                 seg.da = seg.d - seg.a;
14183                                 seg.ca = seg.c - seg.a;
14184                                 seg.ba = cp1 - seg.a;
14185                                 if (quad) {
14186                                         qb = cubicToQuadratic(seg.a, cp1, seg.c, seg.d);
14187                                         a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]);
14188                                 }
14189                         },
14190                         _parseAnchors = function(values, p, correlate, prepend) {
14191                                 var a = [],
14192                                         l, i, p1, p2, p3, tmp;
14193                                 if (prepend) {
14194                                         values = [prepend].concat(values);
14195                                         i = values.length;
14196                                         while (--i > -1) {
14197                                                 if (typeof( (tmp = values[i][p]) ) === "string") if (tmp.charAt(1) === "=") {
14198                                                         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
14199                                                 }
14200                                         }
14201                                 }
14202                                 l = values.length - 2;
14203                                 if (l < 0) {
14204                                         a[0] = new Segment(values[0][p], 0, 0, values[(l < -1) ? 0 : 1][p]);
14205                                         return a;
14206                                 }
14207                                 for (i = 0; i < l; i++) {
14208                                         p1 = values[i][p];
14209                                         p2 = values[i+1][p];
14210                                         a[i] = new Segment(p1, 0, 0, p2);
14211                                         if (correlate) {
14212                                                 p3 = values[i+2][p];
14213                                                 _r1[i] = (_r1[i] || 0) + (p2 - p1) * (p2 - p1);
14214                                                 _r2[i] = (_r2[i] || 0) + (p3 - p2) * (p3 - p2);
14215                                         }
14216                                 }
14217                                 a[i] = new Segment(values[i][p], 0, 0, values[i+1][p]);
14218                                 return a;
14219                         },
14220                         bezierThrough = function(values, curviness, quadratic, basic, correlate, prepend) {
14221                                 var obj = {},
14222                                         props = [],
14223                                         first = prepend || values[0],
14224                                         i, p, a, j, r, l, seamless, last;
14225                                 correlate = (typeof(correlate) === "string") ? ","+correlate+"," : _correlate;
14226                                 if (curviness == null) {
14227                                         curviness = 1;
14228                                 }
14229                                 for (p in values[0]) {
14230                                         props.push(p);
14231                                 }
14232                                 //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)
14233                                 if (values.length > 1) {
14234                                         last = values[values.length - 1];
14235                                         seamless = true;
14236                                         i = props.length;
14237                                         while (--i > -1) {
14238                                                 p = props[i];
14239                                                 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
14240                                                         seamless = false;
14241                                                         break;
14242                                                 }
14243                                         }
14244                                         if (seamless) {
14245                                                 values = values.concat(); //duplicate the array to avoid contaminating the original which the user may be reusing for other tweens
14246                                                 if (prepend) {
14247                                                         values.unshift(prepend);
14248                                                 }
14249                                                 values.push(values[1]);
14250                                                 prepend = values[values.length - 3];
14251                                         }
14252                                 }
14253                                 _r1.length = _r2.length = _r3.length = 0;
14254                                 i = props.length;
14255                                 while (--i > -1) {
14256                                         p = props[i];
14257                                         _corProps[p] = (correlate.indexOf(","+p+",") !== -1);
14258                                         obj[p] = _parseAnchors(values, p, _corProps[p], prepend);
14259                                 }
14260                                 i = _r1.length;
14261                                 while (--i > -1) {
14262                                         _r1[i] = Math.sqrt(_r1[i]);
14263                                         _r2[i] = Math.sqrt(_r2[i]);
14264                                 }
14265                                 if (!basic) {
14266                                         i = props.length;
14267                                         while (--i > -1) {
14268                                                 if (_corProps[p]) {
14269                                                         a = obj[props[i]];
14270                                                         l = a.length - 1;
14271                                                         for (j = 0; j < l; j++) {
14272                                                                 r = a[j+1].da / _r2[j] + a[j].da / _r1[j];
14273                                                                 _r3[j] = (_r3[j] || 0) + r * r;
14274                                                         }
14275                                                 }
14276                                         }
14277                                         i = _r3.length;
14278                                         while (--i > -1) {
14279                                                 _r3[i] = Math.sqrt(_r3[i]);
14280                                         }
14281                                 }
14282                                 i = props.length;
14283                                 j = quadratic ? 4 : 1;
14284                                 while (--i > -1) {
14285                                         p = props[i];
14286                                         a = obj[p];
14287                                         _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
14288                                         if (seamless) {
14289                                                 a.splice(0, j);
14290                                                 a.splice(a.length - j, j);
14291                                         }
14292                                 }
14293                                 return obj;
14294                         },
14295                         _parseBezierData = function(values, type, prepend) {
14296                                 type = type || "soft";
14297                                 var obj = {},
14298                                         inc = (type === "cubic") ? 3 : 2,
14299                                         soft = (type === "soft"),
14300                                         props = [],
14301                                         a, b, c, d, cur, i, j, l, p, cnt, tmp;
14302                                 if (soft && prepend) {
14303                                         values = [prepend].concat(values);
14304                                 }
14305                                 if (values == null || values.length < inc + 1) { throw "invalid Bezier data"; }
14306                                 for (p in values[0]) {
14307                                         props.push(p);
14308                                 }
14309                                 i = props.length;
14310                                 while (--i > -1) {
14311                                         p = props[i];
14312                                         obj[p] = cur = [];
14313                                         cnt = 0;
14314                                         l = values.length;
14315                                         for (j = 0; j < l; j++) {
14316                                                 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);
14317                                                 if (soft) if (j > 1) if (j < l - 1) {
14318                                                         cur[cnt++] = (a + cur[cnt-2]) / 2;
14319                                                 }
14320                                                 cur[cnt++] = a;
14321                                         }
14322                                         l = cnt - inc + 1;
14323                                         cnt = 0;
14324                                         for (j = 0; j < l; j += inc) {
14325                                                 a = cur[j];
14326                                                 b = cur[j+1];
14327                                                 c = cur[j+2];
14328                                                 d = (inc === 2) ? 0 : cur[j+3];
14329                                                 cur[cnt++] = tmp = (inc === 3) ? new Segment(a, b, c, d) : new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c);
14330                                         }
14331                                         cur.length = cnt;
14332                                 }
14333                                 return obj;
14334                         },
14335                         _addCubicLengths = function(a, steps, resolution) {
14336                                 var inc = 1 / resolution,
14337                                         j = a.length,
14338                                         d, d1, s, da, ca, ba, p, i, inv, bez, index;
14339                                 while (--j > -1) {
14340                                         bez = a[j];
14341                                         s = bez.a;
14342                                         da = bez.d - s;
14343                                         ca = bez.c - s;
14344                                         ba = bez.b - s;
14345                                         d = d1 = 0;
14346                                         for (i = 1; i <= resolution; i++) {
14347                                                 p = inc * i;
14348                                                 inv = 1 - p;
14349                                                 d = d1 - (d1 = (p * p * da + 3 * inv * (p * ca + inv * ba)) * p);
14350                                                 index = j * resolution + i - 1;
14351                                                 steps[index] = (steps[index] || 0) + d * d;
14352                                         }
14353                                 }
14354                         },
14355                         _parseLengthData = function(obj, resolution) {
14356                                 resolution = resolution >> 0 || 6;
14357                                 var a = [],
14358                                         lengths = [],
14359                                         d = 0,
14360                                         total = 0,
14361                                         threshold = resolution - 1,
14362                                         segments = [],
14363                                         curLS = [], //current length segments array
14364                                         p, i, l, index;
14365                                 for (p in obj) {
14366                                         _addCubicLengths(obj[p], a, resolution);
14367                                 }
14368                                 l = a.length;
14369                                 for (i = 0; i < l; i++) {
14370                                         d += Math.sqrt(a[i]);
14371                                         index = i % resolution;
14372                                         curLS[index] = d;
14373                                         if (index === threshold) {
14374                                                 total += d;
14375                                                 index = (i / resolution) >> 0;
14376                                                 segments[index] = curLS;
14377                                                 lengths[index] = total;
14378                                                 d = 0;
14379                                                 curLS = [];
14380                                         }
14381                                 }
14382                                 return {length:total, lengths:lengths, segments:segments};
14383                         },
14384
14385
14386
14387                         BezierPlugin = window._gsDefine.plugin({
14388                                         propName: "bezier",
14389                                         priority: -1,
14390                                         version: "1.3.2",
14391                                         API: 2,
14392                                         global:true,
14393
14394                                         //gets called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
14395                                         init: function(target, vars, tween) {
14396                                                 this._target = target;
14397                                                 if (vars instanceof Array) {
14398                                                         vars = {values:vars};
14399                                                 }
14400                                                 this._func = {};
14401                                                 this._round = {};
14402                                                 this._props = [];
14403                                                 this._timeRes = (vars.timeResolution == null) ? 6 : parseInt(vars.timeResolution, 10);
14404                                                 var values = vars.values || [],
14405                                                         first = {},
14406                                                         second = values[0],
14407                                                         autoRotate = vars.autoRotate || tween.vars.orientToBezier,
14408                                                         p, isFunc, i, j, prepend;
14409
14410                                                 this._autoRotate = autoRotate ? (autoRotate instanceof Array) ? autoRotate : [["x","y","rotation",((autoRotate === true) ? 0 : Number(autoRotate) || 0)]] : null;
14411                                                 for (p in second) {
14412                                                         this._props.push(p);
14413                                                 }
14414
14415                                                 i = this._props.length;
14416                                                 while (--i > -1) {
14417                                                         p = this._props[i];
14418
14419                                                         this._overwriteProps.push(p);
14420                                                         isFunc = this._func[p] = (typeof(target[p]) === "function");
14421                                                         first[p] = (!isFunc) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();
14422                                                         if (!prepend) if (first[p] !== values[0][p]) {
14423                                                                 prepend = first;
14424                                                         }
14425                                                 }
14426                                                 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);
14427                                                 this._segCount = this._beziers[p].length;
14428
14429                                                 if (this._timeRes) {
14430                                                         var ld = _parseLengthData(this._beziers, this._timeRes);
14431                                                         this._length = ld.length;
14432                                                         this._lengths = ld.lengths;
14433                                                         this._segments = ld.segments;
14434                                                         this._l1 = this._li = this._s1 = this._si = 0;
14435                                                         this._l2 = this._lengths[0];
14436                                                         this._curSeg = this._segments[0];
14437                                                         this._s2 = this._curSeg[0];
14438                                                         this._prec = 1 / this._curSeg.length;
14439                                                 }
14440
14441                                                 if ((autoRotate = this._autoRotate)) {
14442                                                         this._initialRotations = [];
14443                                                         if (!(autoRotate[0] instanceof Array)) {
14444                                                                 this._autoRotate = autoRotate = [autoRotate];
14445                                                         }
14446                                                         i = autoRotate.length;
14447                                                         while (--i > -1) {
14448                                                                 for (j = 0; j < 3; j++) {
14449                                                                         p = autoRotate[i][j];
14450                                                                         this._func[p] = (typeof(target[p]) === "function") ? target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ] : false;
14451                                                                 }
14452                                                                 p = autoRotate[i][2];
14453                                                                 this._initialRotations[i] = this._func[p] ? this._func[p].call(this._target) : this._target[p];
14454                                                         }
14455                                                 }
14456                                                 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.
14457                                                 return true;
14458                                         },
14459
14460                                         //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.)
14461                                         set: function(v) {
14462                                                 var segments = this._segCount,
14463                                                         func = this._func,
14464                                                         target = this._target,
14465                                                         notStart = (v !== this._startRatio),
14466                                                         curIndex, inv, i, p, b, t, val, l, lengths, curSeg;
14467                                                 if (!this._timeRes) {
14468                                                         curIndex = (v < 0) ? 0 : (v >= 1) ? segments - 1 : (segments * v) >> 0;
14469                                                         t = (v - (curIndex * (1 / segments))) * segments;
14470                                                 } else {
14471                                                         lengths = this._lengths;
14472                                                         curSeg = this._curSeg;
14473                                                         v *= this._length;
14474                                                         i = this._li;
14475                                                         //find the appropriate segment (if the currently cached one isn't correct)
14476                                                         if (v > this._l2 && i < segments - 1) {
14477                                                                 l = segments - 1;
14478                                                                 while (i < l && (this._l2 = lengths[++i]) <= v) {       }
14479                                                                 this._l1 = lengths[i-1];
14480                                                                 this._li = i;
14481                                                                 this._curSeg = curSeg = this._segments[i];
14482                                                                 this._s2 = curSeg[(this._s1 = this._si = 0)];
14483                                                         } else if (v < this._l1 && i > 0) {
14484                                                                 while (i > 0 && (this._l1 = lengths[--i]) >= v) { }
14485                                                                 if (i === 0 && v < this._l1) {
14486                                                                         this._l1 = 0;
14487                                                                 } else {
14488                                                                         i++;
14489                                                                 }
14490                                                                 this._l2 = lengths[i];
14491                                                                 this._li = i;
14492                                                                 this._curSeg = curSeg = this._segments[i];
14493                                                                 this._s1 = curSeg[(this._si = curSeg.length - 1) - 1] || 0;
14494                                                                 this._s2 = curSeg[this._si];
14495                                                         }
14496                                                         curIndex = i;
14497                                                         //now find the appropriate sub-segment (we split it into the number of pieces that was defined by "precision" and measured each one)
14498                                                         v -= this._l1;
14499                                                         i = this._si;
14500                                                         if (v > this._s2 && i < curSeg.length - 1) {
14501                                                                 l = curSeg.length - 1;
14502                                                                 while (i < l && (this._s2 = curSeg[++i]) <= v) {        }
14503                                                                 this._s1 = curSeg[i-1];
14504                                                                 this._si = i;
14505                                                         } else if (v < this._s1 && i > 0) {
14506                                                                 while (i > 0 && (this._s1 = curSeg[--i]) >= v) {        }
14507                                                                 if (i === 0 && v < this._s1) {
14508                                                                         this._s1 = 0;
14509                                                                 } else {
14510                                                                         i++;
14511                                                                 }
14512                                                                 this._s2 = curSeg[i];
14513                                                                 this._si = i;
14514                                                         }
14515                                                         t = (i + (v - this._s1) / (this._s2 - this._s1)) * this._prec;
14516                                                 }
14517                                                 inv = 1 - t;
14518
14519                                                 i = this._props.length;
14520                                                 while (--i > -1) {
14521                                                         p = this._props[i];
14522                                                         b = this._beziers[p][curIndex];
14523                                                         val = (t * t * b.da + 3 * inv * (t * b.ca + inv * b.ba)) * t + b.a;
14524                                                         if (this._round[p]) {
14525                                                                 val = Math.round(val);
14526                                                         }
14527                                                         if (func[p]) {
14528                                                                 target[p](val);
14529                                                         } else {
14530                                                                 target[p] = val;
14531                                                         }
14532                                                 }
14533
14534                                                 if (this._autoRotate) {
14535                                                         var ar = this._autoRotate,
14536                                                                 b2, x1, y1, x2, y2, add, conv;
14537                                                         i = ar.length;
14538                                                         while (--i > -1) {
14539                                                                 p = ar[i][2];
14540                                                                 add = ar[i][3] || 0;
14541                                                                 conv = (ar[i][4] === true) ? 1 : _RAD2DEG;
14542                                                                 b = this._beziers[ar[i][0]];
14543                                                                 b2 = this._beziers[ar[i][1]];
14544
14545                                                                 if (b && b2) { //in case one of the properties got overwritten.
14546                                                                         b = b[curIndex];
14547                                                                         b2 = b2[curIndex];
14548
14549                                                                         x1 = b.a + (b.b - b.a) * t;
14550                                                                         x2 = b.b + (b.c - b.b) * t;
14551                                                                         x1 += (x2 - x1) * t;
14552                                                                         x2 += ((b.c + (b.d - b.c) * t) - x2) * t;
14553
14554                                                                         y1 = b2.a + (b2.b - b2.a) * t;
14555                                                                         y2 = b2.b + (b2.c - b2.b) * t;
14556                                                                         y1 += (y2 - y1) * t;
14557                                                                         y2 += ((b2.c + (b2.d - b2.c) * t) - y2) * t;
14558
14559                                                                         val = notStart ? Math.atan2(y2 - y1, x2 - x1) * conv + add : this._initialRotations[i];
14560
14561                                                                         if (func[p]) {
14562                                                                                 target[p](val);
14563                                                                         } else {
14564                                                                                 target[p] = val;
14565                                                                         }
14566                                                                 }
14567                                                         }
14568                                                 }
14569                                         }
14570                         }),
14571                         p = BezierPlugin.prototype;
14572
14573
14574                 BezierPlugin.bezierThrough = bezierThrough;
14575                 BezierPlugin.cubicToQuadratic = cubicToQuadratic;
14576                 BezierPlugin._autoCSS = true; //indicates that this plugin can be inserted into the "css" object using the autoCSS feature of TweenLite
14577                 BezierPlugin.quadraticToCubic = function(a, b, c) {
14578                         return new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c);
14579                 };
14580
14581                 BezierPlugin._cssRegister = function() {
14582                         var CSSPlugin = window._gsDefine.globals.CSSPlugin;
14583                         if (!CSSPlugin) {
14584                                 return;
14585                         }
14586                         var _internals = CSSPlugin._internals,
14587                                 _parseToProxy = _internals._parseToProxy,
14588                                 _setPluginRatio = _internals._setPluginRatio,
14589                                 CSSPropTween = _internals.CSSPropTween;
14590                         _internals._registerComplexSpecialProp("bezier", {parser:function(t, e, prop, cssp, pt, plugin) {
14591                                 if (e instanceof Array) {
14592                                         e = {values:e};
14593                                 }
14594                                 plugin = new BezierPlugin();
14595                                 var values = e.values,
14596                                         l = values.length - 1,
14597                                         pluginValues = [],
14598                                         v = {},
14599                                         i, p, data;
14600                                 if (l < 0) {
14601                                         return pt;
14602                                 }
14603                                 for (i = 0; i <= l; i++) {
14604                                         data = _parseToProxy(t, values[i], cssp, pt, plugin, (l !== i));
14605                                         pluginValues[i] = data.end;
14606                                 }
14607                                 for (p in e) {
14608                                         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.
14609                                 }
14610                                 v.values = pluginValues;
14611                                 pt = new CSSPropTween(t, "bezier", 0, 0, data.pt, 2);
14612                                 pt.data = data;
14613                                 pt.plugin = plugin;
14614                                 pt.setRatio = _setPluginRatio;
14615                                 if (v.autoRotate === 0) {
14616                                         v.autoRotate = true;
14617                                 }
14618                                 if (v.autoRotate && !(v.autoRotate instanceof Array)) {
14619                                         i = (v.autoRotate === true) ? 0 : Number(v.autoRotate);
14620                                         v.autoRotate = (data.end.left != null) ? [["left","top","rotation",i,false]] : (data.end.x != null) ? [["x","y","rotation",i,false]] : false;
14621                                 }
14622                                 if (v.autoRotate) {
14623                                         if (!cssp._transform) {
14624                                                 cssp._enableTransforms(false);
14625                                         }
14626                                         data.autoRotate = cssp._target._gsTransform;
14627                                 }
14628                                 plugin._onInitTween(data.proxy, v, cssp._tween);
14629                                 return pt;
14630                         }});
14631                 };
14632
14633                 p._roundProps = function(lookup, value) {
14634                         var op = this._overwriteProps,
14635                                 i = op.length;
14636                         while (--i > -1) {
14637                                 if (lookup[op[i]] || lookup.bezier || lookup.bezierThrough) {
14638                                         this._round[op[i]] = value;
14639                                 }
14640                         }
14641                 };
14642
14643                 p._kill = function(lookup) {
14644                         var a = this._props,
14645                                 p, i;
14646                         for (p in this._beziers) {
14647                                 if (p in lookup) {
14648                                         delete this._beziers[p];
14649                                         delete this._func[p];
14650                                         i = a.length;
14651                                         while (--i > -1) {
14652                                                 if (a[i] === p) {
14653                                                         a.splice(i, 1);
14654                                                 }
14655                                         }
14656                                 }
14657                         }
14658                         return this._super._kill.call(this, lookup);
14659                 };
14660
14661         }());
14662
14663
14664
14665
14666
14667
14668         
14669         
14670         
14671         
14672         
14673         
14674         
14675         
14676 /*
14677  * ----------------------------------------------------------------
14678  * CSSPlugin
14679  * ----------------------------------------------------------------
14680  */
14681         window._gsDefine("plugins.CSSPlugin", ["plugins.TweenPlugin","TweenLite"], function(TweenPlugin, TweenLite) {
14682
14683                 /** @constructor **/
14684                 var CSSPlugin = function() {
14685                                 TweenPlugin.call(this, "css");
14686                                 this._overwriteProps.length = 0;
14687                                 this.setRatio = CSSPlugin.prototype.setRatio; //speed optimization (avoid prototype lookup on this "hot" method)
14688                         },
14689                         _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.
14690                         _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
14691                         _cs, //computed style (we store this in a shared variable to conserve memory and make minification tighter
14692                         _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.
14693                         _specialProps = {},
14694                         p = CSSPlugin.prototype = new TweenPlugin("css");
14695
14696                 p.constructor = CSSPlugin;
14697                 CSSPlugin.version = "1.12.1";
14698                 CSSPlugin.API = 2;
14699                 CSSPlugin.defaultTransformPerspective = 0;
14700                 CSSPlugin.defaultSkewType = "compensated";
14701                 p = "px"; //we'll reuse the "p" variable to keep file size down
14702                 CSSPlugin.suffixMap = {top:p, right:p, bottom:p, left:p, width:p, height:p, fontSize:p, padding:p, margin:p, perspective:p, lineHeight:""};
14703
14704
14705                 var _numExp = /(?:\d|\-\d|\.\d|\-\.\d)+/g,
14706                         _relNumExp = /(?:\d|\-\d|\.\d|\-\.\d|\+=\d|\-=\d|\+=.\d|\-=\.\d)+/g,
14707                         _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)"
14708                         _NaNExp = /[^\d\-\.]/g,
14709                         _suffixExp = /(?:\d|\-|\+|=|#|\.)*/g,
14710                         _opacityExp = /opacity *= *([^)]*)/i,
14711                         _opacityValExp = /opacity:([^;]*)/i,
14712                         _alphaFilterExp = /alpha\(opacity *=.+?\)/i,
14713                         _rgbhslExp = /^(rgb|hsl)/,
14714                         _capsExp = /([A-Z])/g,
14715                         _camelExp = /-([a-z])/gi,
14716                         _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)
14717                         _camelFunc = function(s, g) { return g.toUpperCase(); },
14718                         _horizExp = /(?:Left|Right|Width)/i,
14719                         _ieGetMatrixExp = /(M11|M12|M21|M22)=[\d\-\.e]+/gi,
14720                         _ieSetMatrixExp = /progid\:DXImageTransform\.Microsoft\.Matrix\(.+?\)/i,
14721                         _commasOutsideParenExp = /,(?=[^\)]*(?:\(|$))/gi, //finds any commas that are not within parenthesis
14722                         _DEG2RAD = Math.PI / 180,
14723                         _RAD2DEG = 180 / Math.PI,
14724                         _forcePT = {},
14725                         _doc = document,
14726                         _tempDiv = _doc.createElement("div"),
14727                         _tempImg = _doc.createElement("img"),
14728                         _internals = CSSPlugin._internals = {_specialProps:_specialProps}, //provides a hook to a few internal methods that we need to access from inside other plugins
14729                         _agent = navigator.userAgent,
14730                         _autoRound,
14731                         _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).
14732
14733                         _isSafari,
14734                         _isFirefox, //Firefox has a bug that causes 3D transformed elements to randomly disappear unless a repaint is forced after each update on each element.
14735                         _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!)
14736                         _ieVers,
14737                         _supportsOpacity = (function() { //we set _isSafari, _ieVers, _isFirefox, and _supportsOpacity all in one function here to reduce file size slightly, especially in the minified version.
14738                                 var i = _agent.indexOf("Android"),
14739                                         d = _doc.createElement("div"), a;
14740
14741                                 _isSafari = (_agent.indexOf("Safari") !== -1 && _agent.indexOf("Chrome") === -1 && (i === -1 || Number(_agent.substr(i+8, 1)) > 3));
14742                                 _isSafariLT6 = (_isSafari && (Number(_agent.substr(_agent.indexOf("Version/")+8, 1)) < 6));
14743                                 _isFirefox = (_agent.indexOf("Firefox") !== -1);
14744
14745                                 if ((/MSIE ([0-9]{1,}[\.0-9]{0,})/).exec(_agent)) {
14746                                         _ieVers = parseFloat( RegExp.$1 );
14747                                 }
14748
14749                                 d.innerHTML = "<a title='' style='top:1px;opacity:.55;'>a</a>";
14750                                 a = d.getElementsByTagName("a")[0];
14751                                 return a ? /^0.55/.test(a.style.opacity) : false;
14752                         }()),
14753                         _getIEOpacity = function(v) {
14754                                 return (_opacityExp.test( ((typeof(v) === "string") ? v : (v.currentStyle ? v.currentStyle.filter : v.style.filter) || "") ) ? ( parseFloat( RegExp.$1 ) / 100 ) : 1);
14755                         },
14756                         _log = function(s) {//for logging messages, but in a way that won't throw errors in old versions of IE.
14757                                 if (window.console) {
14758                                         //console.log(s);
14759                                 }
14760                         },
14761                         _prefixCSS = "", //the non-camelCase vendor prefix like "-o-", "-moz-", "-ms-", or "-webkit-"
14762                         _prefix = "", //camelCase vendor prefix like "O", "ms", "Webkit", or "Moz".
14763
14764                         // @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)
14765                         _checkPropPrefix = function(p, e) {
14766                                 e = e || _tempDiv;
14767                                 var s = e.style,
14768                                         a, i;
14769                                 if (s[p] !== undefined) {
14770                                         return p;
14771                                 }
14772                                 p = p.charAt(0).toUpperCase() + p.substr(1);
14773                                 a = ["O","Moz","ms","Ms","Webkit"];
14774                                 i = 5;
14775                                 while (--i > -1 && s[a[i]+p] === undefined) { }
14776                                 if (i >= 0) {
14777                                         _prefix = (i === 3) ? "ms" : a[i];
14778                                         _prefixCSS = "-" + _prefix.toLowerCase() + "-";
14779                                         return _prefix + p;
14780                                 }
14781                                 return null;
14782                         },
14783
14784                         _getComputedStyle = _doc.defaultView ? _doc.defaultView.getComputedStyle : function() {},
14785
14786                         /**
14787                          * @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:
14788                          * var currentLeft = CSSPlugin.getStyle( document.getElementById("myElement"), "left");
14789                          *
14790                          * @param {!Object} t Target element whose style property you want to query
14791                          * @param {!string} p Property name (like "left" or "top" or "marginTop", etc.)
14792                          * @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.
14793                          * @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.
14794                          * @param {string=} dflt Default value that should be returned in the place of null, "none", "auto" or "auto auto".
14795                          * @return {?string} The current property value
14796                          */
14797                         _getStyle = CSSPlugin.getStyle = function(t, p, cs, calc, dflt) {
14798                                 var rv;
14799                                 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.
14800                                         return _getIEOpacity(t);
14801                                 }
14802                                 if (!calc && t.style[p]) {
14803                                         rv = t.style[p];
14804                                 } else if ((cs = cs || _getComputedStyle(t))) {
14805                                         rv = cs[p] || cs.getPropertyValue(p) || cs.getPropertyValue(p.replace(_capsExp, "-$1").toLowerCase());
14806                                 } else if (t.currentStyle) {
14807                                         rv = t.currentStyle[p];
14808                                 }
14809                                 return (dflt != null && (!rv || rv === "none" || rv === "auto" || rv === "auto auto")) ? dflt : rv;
14810                         },
14811
14812                         /**
14813                          * @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.
14814                          * @param {!Object} t Target element
14815                          * @param {!string} p Property name (like "left", "top", "marginLeft", etc.)
14816                          * @param {!number} v Value
14817                          * @param {string=} sfx Suffix (like "px" or "%" or "em")
14818                          * @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.
14819                          * @return {number} value in pixels
14820                          */
14821                         _convertToPixels = _internals.convertToPixels = function(t, p, v, sfx, recurse) {
14822                                 if (sfx === "px" || !sfx) { return v; }
14823                                 if (sfx === "auto" || !v) { return 0; }
14824                                 var horiz = _horizExp.test(p),
14825                                         node = t,
14826                                         style = _tempDiv.style,
14827                                         neg = (v < 0),
14828                                         pix, cache, time;
14829                                 if (neg) {
14830                                         v = -v;
14831                                 }
14832                                 if (sfx === "%" && p.indexOf("border") !== -1) {
14833                                         pix = (v / 100) * (horiz ? t.clientWidth : t.clientHeight);
14834                                 } else {
14835                                         style.cssText = "border:0 solid red;position:" + _getStyle(t, "position") + ";line-height:0;";
14836                                         if (sfx === "%" || !node.appendChild) {
14837                                                 node = t.parentNode || _doc.body;
14838                                                 cache = node._gsCache;
14839                                                 time = TweenLite.ticker.frame;
14840                                                 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)
14841                                                         return cache.width * v / 100;
14842                                                 }
14843                                                 style[(horiz ? "width" : "height")] = v + sfx;
14844                                         } else {
14845                                                 style[(horiz ? "borderLeftWidth" : "borderTopWidth")] = v + sfx;
14846                                         }
14847                                         node.appendChild(_tempDiv);
14848                                         pix = parseFloat(_tempDiv[(horiz ? "offsetWidth" : "offsetHeight")]);
14849                                         node.removeChild(_tempDiv);
14850                                         if (horiz && sfx === "%" && CSSPlugin.cacheWidths !== false) {
14851                                                 cache = node._gsCache = node._gsCache || {};
14852                                                 cache.time = time;
14853                                                 cache.width = pix / v * 100;
14854                                         }
14855                                         if (pix === 0 && !recurse) {
14856                                                 pix = _convertToPixels(t, p, v, sfx, true);
14857                                         }
14858                                 }
14859                                 return neg ? -pix : pix;
14860                         },
14861                         _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
14862                                 if (_getStyle(t, "position", cs) !== "absolute") { return 0; }
14863                                 var dim = ((p === "left") ? "Left" : "Top"),
14864                                         v = _getStyle(t, "margin" + dim, cs);
14865                                 return t["offset" + dim] - (_convertToPixels(t, p, parseFloat(v), v.replace(_suffixExp, "")) || 0);
14866                         },
14867
14868                         // @private returns at object containing ALL of the style properties in camelCase and their associated values.
14869                         _getAllStyles = function(t, cs) {
14870                                 var s = {},
14871                                         i, tr;
14872                                 if ((cs = cs || _getComputedStyle(t, null))) {
14873                                         if ((i = cs.length)) {
14874                                                 while (--i > -1) {
14875                                                         s[cs[i].replace(_camelExp, _camelFunc)] = cs.getPropertyValue(cs[i]);
14876                                                 }
14877                                         } else { //Opera behaves differently - cs.length is always 0, so we must do a for...in loop.
14878                                                 for (i in cs) {
14879                                                         s[i] = cs[i];
14880                                                 }
14881                                         }
14882                                 } else if ((cs = t.currentStyle || t.style)) {
14883                                         for (i in cs) {
14884                                                 if (typeof(i) === "string" && s[i] === undefined) {
14885                                                         s[i.replace(_camelExp, _camelFunc)] = cs[i];
14886                                                 }
14887                                         }
14888                                 }
14889                                 if (!_supportsOpacity) {
14890                                         s.opacity = _getIEOpacity(t);
14891                                 }
14892                                 tr = _getTransform(t, cs, false);
14893                                 s.rotation = tr.rotation;
14894                                 s.skewX = tr.skewX;
14895                                 s.scaleX = tr.scaleX;
14896                                 s.scaleY = tr.scaleY;
14897                                 s.x = tr.x;
14898                                 s.y = tr.y;
14899                                 if (_supports3D) {
14900                                         s.z = tr.z;
14901                                         s.rotationX = tr.rotationX;
14902                                         s.rotationY = tr.rotationY;
14903                                         s.scaleZ = tr.scaleZ;
14904                                 }
14905                                 if (s.filters) {
14906                                         delete s.filters;
14907                                 }
14908                                 return s;
14909                         },
14910
14911                         // @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.
14912                         _cssDif = function(t, s1, s2, vars, forceLookup) {
14913                                 var difs = {},
14914                                         style = t.style,
14915                                         val, p, mpt;
14916                                 for (p in s2) {
14917                                         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") {
14918                                                 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.
14919                                                 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.
14920                                                         mpt = new MiniPropTween(style, p, style[p], mpt);
14921                                                 }
14922                                         }
14923                                 }
14924                                 if (vars) {
14925                                         for (p in vars) { //copy properties (except className)
14926                                                 if (p !== "className") {
14927                                                         difs[p] = vars[p];
14928                                                 }
14929                                         }
14930                                 }
14931                                 return {difs:difs, firstMPT:mpt};
14932                         },
14933                         _dimensions = {width:["Left","Right"], height:["Top","Bottom"]},
14934                         _margins = ["marginLeft","marginRight","marginTop","marginBottom"],
14935
14936                         /**
14937                          * @private Gets the width or height of an element
14938                          * @param {!Object} t Target element
14939                          * @param {!string} p Property name ("width" or "height")
14940                          * @param {Object=} cs Computed style object (if one exists). Just a speed optimization.
14941                          * @return {number} Dimension (in pixels)
14942                          */
14943                         _getDimension = function(t, p, cs) {
14944                                 var v = parseFloat((p === "width") ? t.offsetWidth : t.offsetHeight),
14945                                         a = _dimensions[p],
14946                                         i = a.length;
14947                                 cs = cs || _getComputedStyle(t, null);
14948                                 while (--i > -1) {
14949                                         v -= parseFloat( _getStyle(t, "padding" + a[i], cs, true) ) || 0;
14950                                         v -= parseFloat( _getStyle(t, "border" + a[i] + "Width", cs, true) ) || 0;
14951                                 }
14952                                 return v;
14953                         },
14954
14955                         // @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)
14956                         _parsePosition = function(v, recObj) {
14957                                 if (v == null || v === "" || v === "auto" || v === "auto auto") { //note: Firefox uses "auto auto" as default whereas Chrome uses "auto".
14958                                         v = "0 0";
14959                                 }
14960                                 var a = v.split(" "),
14961                                         x = (v.indexOf("left") !== -1) ? "0%" : (v.indexOf("right") !== -1) ? "100%" : a[0],
14962                                         y = (v.indexOf("top") !== -1) ? "0%" : (v.indexOf("bottom") !== -1) ? "100%" : a[1];
14963                                 if (y == null) {
14964                                         y = "0";
14965                                 } else if (y === "center") {
14966                                         y = "50%";
14967                                 }
14968                                 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.
14969                                         x = "50%";
14970                                 }
14971                                 if (recObj) {
14972                                         recObj.oxp = (x.indexOf("%") !== -1);
14973                                         recObj.oyp = (y.indexOf("%") !== -1);
14974                                         recObj.oxr = (x.charAt(1) === "=");
14975                                         recObj.oyr = (y.charAt(1) === "=");
14976                                         recObj.ox = parseFloat(x.replace(_NaNExp, ""));
14977                                         recObj.oy = parseFloat(y.replace(_NaNExp, ""));
14978                                 }
14979                                 return x + " " + y + ((a.length > 2) ? " " + a[2] : "");
14980                         },
14981
14982                         /**
14983                          * @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!)
14984                          * @param {(number|string)} e End value which is typically a string, but could be a number
14985                          * @param {(number|string)} b Beginning value which is typically a string but could be a number
14986                          * @return {number} Amount of change between the beginning and ending values (relative values that have a "+=" or "-=" are recognized)
14987                          */
14988                         _parseChange = function(e, b) {
14989                                 return (typeof(e) === "string" && e.charAt(1) === "=") ? parseInt(e.charAt(0) + "1", 10) * parseFloat(e.substr(2)) : parseFloat(e) - parseFloat(b);
14990                         },
14991
14992                         /**
14993                          * @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.
14994                          * @param {Object} v Value to be parsed
14995                          * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter)
14996                          * @return {number} Parsed value
14997                          */
14998                         _parseVal = function(v, d) {
14999                                 return (v == null) ? d : (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) + d : parseFloat(v);
15000                         },
15001
15002                         /**
15003                          * @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.
15004                          * @param {Object} v Value to be parsed
15005                          * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter)
15006                          * @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"
15007                          * @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.
15008                          * @return {number} parsed angle in radians
15009                          */
15010                         _parseAngle = function(v, d, p, directionalEnd) {
15011                                 var min = 0.000001,
15012                                         cap, split, dif, result;
15013                                 if (v == null) {
15014                                         result = d;
15015                                 } else if (typeof(v) === "number") {
15016                                         result = v;
15017                                 } else {
15018                                         cap = 360;
15019                                         split = v.split("_");
15020                                         dif = Number(split[0].replace(_NaNExp, "")) * ((v.indexOf("rad") === -1) ? 1 : _RAD2DEG) - ((v.charAt(1) === "=") ? 0 : d);
15021                                         if (split.length) {
15022                                                 if (directionalEnd) {
15023                                                         directionalEnd[p] = d + dif;
15024                                                 }
15025                                                 if (v.indexOf("short") !== -1) {
15026                                                         dif = dif % cap;
15027                                                         if (dif !== dif % (cap / 2)) {
15028                                                                 dif = (dif < 0) ? dif + cap : dif - cap;
15029                                                         }
15030                                                 }
15031                                                 if (v.indexOf("_cw") !== -1 && dif < 0) {
15032                                                         dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
15033                                                 } else if (v.indexOf("ccw") !== -1 && dif > 0) {
15034                                                         dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
15035                                                 }
15036                                         }
15037                                         result = d + dif;
15038                                 }
15039                                 if (result < min && result > -min) {
15040                                         result = 0;
15041                                 }
15042                                 return result;
15043                         },
15044
15045                         _colorLookup = {aqua:[0,255,255],
15046                                 lime:[0,255,0],
15047                                 silver:[192,192,192],
15048                                 black:[0,0,0],
15049                                 maroon:[128,0,0],
15050                                 teal:[0,128,128],
15051                                 blue:[0,0,255],
15052                                 navy:[0,0,128],
15053                                 white:[255,255,255],
15054                                 fuchsia:[255,0,255],
15055                                 olive:[128,128,0],
15056                                 yellow:[255,255,0],
15057                                 orange:[255,165,0],
15058                                 gray:[128,128,128],
15059                                 purple:[128,0,128],
15060                                 green:[0,128,0],
15061                                 red:[255,0,0],
15062                                 pink:[255,192,203],
15063                                 cyan:[0,255,255],
15064                                 transparent:[255,255,255,0]},
15065
15066                         _hue = function(h, m1, m2) {
15067                                 h = (h < 0) ? h + 1 : (h > 1) ? h - 1 : h;
15068                                 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;
15069                         },
15070
15071                         /**
15072                          * @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)
15073                          * @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.
15074                          * @return {Array.<number>} An array containing red, green, and blue (and optionally alpha) in that order.
15075                          */
15076                         _parseColor = function(v) {
15077                                 var c1, c2, c3, h, s, l;
15078                                 if (!v || v === "") {
15079                                         return _colorLookup.black;
15080                                 }
15081                                 if (typeof(v) === "number") {
15082                                         return [v >> 16, (v >> 8) & 255, v & 255];
15083                                 }
15084                                 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.
15085                                         v = v.substr(0, v.length - 1);
15086                                 }
15087                                 if (_colorLookup[v]) {
15088                                         return _colorLookup[v];
15089                                 }
15090                                 if (v.charAt(0) === "#") {
15091                                         if (v.length === 4) { //for shorthand like #9F0
15092                                                 c1 = v.charAt(1),
15093                                                 c2 = v.charAt(2),
15094                                                 c3 = v.charAt(3);
15095                                                 v = "#" + c1 + c1 + c2 + c2 + c3 + c3;
15096                                         }
15097                                         v = parseInt(v.substr(1), 16);
15098                                         return [v >> 16, (v >> 8) & 255, v & 255];
15099                                 }
15100                                 if (v.substr(0, 3) === "hsl") {
15101                                         v = v.match(_numExp);
15102                                         h = (Number(v[0]) % 360) / 360;
15103                                         s = Number(v[1]) / 100;
15104                                         l = Number(v[2]) / 100;
15105                                         c2 = (l <= 0.5) ? l * (s + 1) : l + s - l * s;
15106                                         c1 = l * 2 - c2;
15107                                         if (v.length > 3) {
15108                                                 v[3] = Number(v[3]);
15109                                         }
15110                                         v[0] = _hue(h + 1 / 3, c1, c2);
15111                                         v[1] = _hue(h, c1, c2);
15112                                         v[2] = _hue(h - 1 / 3, c1, c2);
15113                                         return v;
15114                                 }
15115                                 v = v.match(_numExp) || _colorLookup.transparent;
15116                                 v[0] = Number(v[0]);
15117                                 v[1] = Number(v[1]);
15118                                 v[2] = Number(v[2]);
15119                                 if (v.length > 3) {
15120                                         v[3] = Number(v[3]);
15121                                 }
15122                                 return v;
15123                         },
15124                         _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.
15125
15126                 for (p in _colorLookup) {
15127                         _colorExp += "|" + p + "\\b";
15128                 }
15129                 _colorExp = new RegExp(_colorExp+")", "gi");
15130
15131                 /**
15132                  * @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.
15133                  * @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.
15134                  * @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.
15135                  * @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.
15136                  * @return {Function} formatter function
15137                  */
15138                 var _getFormatter = function(dflt, clr, collapsible, multi) {
15139                                 if (dflt == null) {
15140                                         return function(v) {return v;};
15141                                 }
15142                                 var dColor = clr ? (dflt.match(_colorExp) || [""])[0] : "",
15143                                         dVals = dflt.split(dColor).join("").match(_valuesExp) || [],
15144                                         pfx = dflt.substr(0, dflt.indexOf(dVals[0])),
15145                                         sfx = (dflt.charAt(dflt.length - 1) === ")") ? ")" : "",
15146                                         delim = (dflt.indexOf(" ") !== -1) ? " " : ",",
15147                                         numVals = dVals.length,
15148                                         dSfx = (numVals > 0) ? dVals[0].replace(_numExp, "") : "",
15149                                         formatter;
15150                                 if (!numVals) {
15151                                         return function(v) {return v;};
15152                                 }
15153                                 if (clr) {
15154                                         formatter = function(v) {
15155                                                 var color, vals, i, a;
15156                                                 if (typeof(v) === "number") {
15157                                                         v += dSfx;
15158                                                 } else if (multi && _commasOutsideParenExp.test(v)) {
15159                                                         a = v.replace(_commasOutsideParenExp, "|").split("|");
15160                                                         for (i = 0; i < a.length; i++) {
15161                                                                 a[i] = formatter(a[i]);
15162                                                         }
15163                                                         return a.join(",");
15164                                                 }
15165                                                 color = (v.match(_colorExp) || [dColor])[0];
15166                                                 vals = v.split(color).join("").match(_valuesExp) || [];
15167                                                 i = vals.length;
15168                                                 if (numVals > i--) {
15169                                                         while (++i < numVals) {
15170                                                                 vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];
15171                                                         }
15172                                                 }
15173                                                 return pfx + vals.join(delim) + delim + color + sfx + (v.indexOf("inset") !== -1 ? " inset" : "");
15174                                         };
15175                                         return formatter;
15176
15177                                 }
15178                                 formatter = function(v) {
15179                                         var vals, a, i;
15180                                         if (typeof(v) === "number") {
15181                                                 v += dSfx;
15182                                         } else if (multi && _commasOutsideParenExp.test(v)) {
15183                                                 a = v.replace(_commasOutsideParenExp, "|").split("|");
15184                                                 for (i = 0; i < a.length; i++) {
15185                                                         a[i] = formatter(a[i]);
15186                                                 }
15187                                                 return a.join(",");
15188                                         }
15189                                         vals = v.match(_valuesExp) || [];
15190                                         i = vals.length;
15191                                         if (numVals > i--) {
15192                                                 while (++i < numVals) {
15193                                                         vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];
15194                                                 }
15195                                         }
15196                                         return pfx + vals.join(delim) + sfx;
15197                                 };
15198                                 return formatter;
15199                         },
15200
15201                         /**
15202                          * @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.
15203                          * @param {!string} props a comma-delimited list of property names in order from top to left, like "marginTop,marginRight,marginBottom,marginLeft"
15204                          * @return {Function} a formatter function
15205                          */
15206                         _getEdgeParser = function(props) {
15207                                 props = props.split(",");
15208                                 return function(t, e, p, cssp, pt, plugin, vars) {
15209                                         var a = (e + "").split(" "),
15210                                                 i;
15211                                         vars = {};
15212                                         for (i = 0; i < 4; i++) {
15213                                                 vars[props[i]] = a[i] = a[i] || a[(((i - 1) / 2) >> 0)];
15214                                         }
15215                                         return cssp.parse(t, vars, pt, plugin);
15216                                 };
15217                         },
15218
15219                         // @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.
15220                         _setPluginRatio = _internals._setPluginRatio = function(v) {
15221                                 this.plugin.setRatio(v);
15222                                 var d = this.data,
15223                                         proxy = d.proxy,
15224                                         mpt = d.firstMPT,
15225                                         min = 0.000001,
15226                                         val, pt, i, str;
15227                                 while (mpt) {
15228                                         val = proxy[mpt.v];
15229                                         if (mpt.r) {
15230                                                 val = Math.round(val);
15231                                         } else if (val < min && val > -min) {
15232                                                 val = 0;
15233                                         }
15234                                         mpt.t[mpt.p] = val;
15235                                         mpt = mpt._next;
15236                                 }
15237                                 if (d.autoRotate) {
15238                                         d.autoRotate.rotation = proxy.rotation;
15239                                 }
15240                                 //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.
15241                                 if (v === 1) {
15242                                         mpt = d.firstMPT;
15243                                         while (mpt) {
15244                                                 pt = mpt.t;
15245                                                 if (!pt.type) {
15246                                                         pt.e = pt.s + pt.xs0;
15247                                                 } else if (pt.type === 1) {
15248                                                         str = pt.xs0 + pt.s + pt.xs1;
15249                                                         for (i = 1; i < pt.l; i++) {
15250                                                                 str += pt["xn"+i] + pt["xs"+(i+1)];
15251                                                         }
15252                                                         pt.e = str;
15253                                                 }
15254                                                 mpt = mpt._next;
15255                                         }
15256                                 }
15257                         },
15258
15259                         /**
15260                          * @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.
15261                          * @param {!Object} t target object whose property we're tweening (often a CSSPropTween)
15262                          * @param {!string} p property name
15263                          * @param {(number|string|object)} v value
15264                          * @param {MiniPropTween=} next next MiniPropTween in the linked list
15265                          * @param {boolean=} r if true, the tweened value should be rounded to the nearest integer
15266                          */
15267                         MiniPropTween = function(t, p, v, next, r) {
15268                                 this.t = t;
15269                                 this.p = p;
15270                                 this.v = v;
15271                                 this.r = r;
15272                                 if (next) {
15273                                         next._prev = this;
15274                                         this._next = next;
15275                                 }
15276                         },
15277
15278                         /**
15279                          * @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.
15280                          * This method returns an object that has the following properties:
15281                          *  - 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
15282                          *  - 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
15283                          *  - firstMPT: the first MiniPropTween in the linked list
15284                          *  - 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.
15285                          * @param {!Object} t target object to be tweened
15286                          * @param {!(Object|string)} vars the object containing the information about the tweening values (typically the end/destination values) that should be parsed
15287                          * @param {!CSSPlugin} cssp The CSSPlugin instance
15288                          * @param {CSSPropTween=} pt the next CSSPropTween in the linked list
15289                          * @param {TweenPlugin=} plugin the external TweenPlugin instance that will be handling tweening the numeric values
15290                          * @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.
15291                          * @return An object containing the following properties: proxy, end, firstMPT, and pt (see above for descriptions)
15292                          */
15293                         _parseToProxy = _internals._parseToProxy = function(t, vars, cssp, pt, plugin, shallow) {
15294                                 var bpt = pt,
15295                                         start = {},
15296                                         end = {},
15297                                         transform = cssp._transform,
15298                                         oldForce = _forcePT,
15299                                         i, p, xp, mpt, firstPT;
15300                                 cssp._transform = null;
15301                                 _forcePT = vars;
15302                                 pt = firstPT = cssp.parse(t, vars, pt, plugin);
15303                                 _forcePT = oldForce;
15304                                 //break off from the linked list so the new ones are isolated.
15305                                 if (shallow) {
15306                                         cssp._transform = transform;
15307                                         if (bpt) {
15308                                                 bpt._prev = null;
15309                                                 if (bpt._prev) {
15310                                                         bpt._prev._next = null;
15311                                                 }
15312                                         }
15313                                 }
15314                                 while (pt && pt !== bpt) {
15315                                         if (pt.type <= 1) {
15316                                                 p = pt.p;
15317                                                 end[p] = pt.s + pt.c;
15318                                                 start[p] = pt.s;
15319                                                 if (!shallow) {
15320                                                         mpt = new MiniPropTween(pt, "s", p, mpt, pt.r);
15321                                                         pt.c = 0;
15322                                                 }
15323                                                 if (pt.type === 1) {
15324                                                         i = pt.l;
15325                                                         while (--i > 0) {
15326                                                                 xp = "xn" + i;
15327                                                                 p = pt.p + "_" + xp;
15328                                                                 end[p] = pt.data[xp];
15329                                                                 start[p] = pt[xp];
15330                                                                 if (!shallow) {
15331                                                                         mpt = new MiniPropTween(pt, xp, p, mpt, pt.rxp[xp]);
15332                                                                 }
15333                                                         }
15334                                                 }
15335                                         }
15336                                         pt = pt._next;
15337                                 }
15338                                 return {proxy:start, end:end, firstMPT:mpt, pt:firstPT};
15339                         },
15340
15341
15342
15343                         /**
15344                          * @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.
15345                          * CSSPropTweens have the following optional properties as well (not defined through the constructor):
15346                          *  - 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.
15347                          *  - 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)
15348                          *  - 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.
15349                          *  - 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.
15350                          *  - 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.
15351                          * @param {!Object} t Target object whose property will be tweened. Often a DOM element, but not always. It could be anything.
15352                          * @param {string} p Property to tween (name). For example, to tween element.width, p would be "width".
15353                          * @param {number} s Starting numeric value
15354                          * @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.
15355                          * @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.
15356                          * @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.
15357                          * @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"
15358                          * @param {boolean=} r If true, the value(s) should be rounded
15359                          * @param {number=} pr Priority in the linked list order. Higher priority CSSPropTweens will be updated before lower priority ones. The default priority is 0.
15360                          * @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.
15361                          * @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.
15362                          */
15363                         CSSPropTween = _internals.CSSPropTween = function(t, p, s, c, next, type, n, r, pr, b, e) {
15364                                 this.t = t; //target
15365                                 this.p = p; //property
15366                                 this.s = s; //starting value
15367                                 this.c = c; //change value
15368                                 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)
15369                                 if (!(t instanceof CSSPropTween)) {
15370                                         _overwriteProps.push(this.n);
15371                                 }
15372                                 this.r = r; //round (boolean)
15373                                 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
15374                                 if (pr) {
15375                                         this.pr = pr;
15376                                         _hasPriority = true;
15377                                 }
15378                                 this.b = (b === undefined) ? s : b;
15379                                 this.e = (e === undefined) ? s + c : e;
15380                                 if (next) {
15381                                         this._next = next;
15382                                         next._prev = this;
15383                                 }
15384                         },
15385
15386                         /**
15387                          * 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:
15388                          * 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);
15389                          * 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().
15390                          * 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.
15391                          *
15392                          * @param {!Object} t Target whose property will be tweened
15393                          * @param {!string} p Property that will be tweened (its name, like "left" or "backgroundColor" or "boxShadow")
15394                          * @param {string} b Beginning value
15395                          * @param {string} e Ending value
15396                          * @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)
15397                          * @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
15398                          * @param {?CSSPropTween} pt CSSPropTween instance that is the current head of the linked list (we'll prepend to this).
15399                          * @param {number=} pr Priority in the linked list order. Higher priority properties will be updated before lower priority ones. The default priority is 0.
15400                          * @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}
15401                          * @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.
15402                          * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parseComplex() call.
15403                          */
15404                         _parseComplex = CSSPlugin.parseComplex = function(t, p, b, e, clrs, dflt, pt, pr, plugin, setRatio) {
15405                                 //DEBUG: _log("parseComplex: "+p+", b: "+b+", e: "+e);
15406                                 b = b || dflt || "";
15407                                 pt = new CSSPropTween(t, p, 0, 0, pt, (setRatio ? 2 : 1), null, false, pr, b, e);
15408                                 e += ""; //ensures it's a string
15409                                 var ba = b.split(", ").join(",").split(" "), //beginning array
15410                                         ea = e.split(", ").join(",").split(" "), //ending array
15411                                         l = ba.length,
15412                                         autoRound = (_autoRound !== false),
15413                                         i, xi, ni, bv, ev, bnums, enums, bn, rgba, temp, cv, str;
15414                                 if (e.indexOf(",") !== -1 || b.indexOf(",") !== -1) {
15415                                         ba = ba.join(" ").replace(_commasOutsideParenExp, ", ").split(" ");
15416                                         ea = ea.join(" ").replace(_commasOutsideParenExp, ", ").split(" ");
15417                                         l = ba.length;
15418                                 }
15419                                 if (l !== ea.length) {
15420                                         //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")");
15421                                         ba = (dflt || "").split(" ");
15422                                         l = ba.length;
15423                                 }
15424                                 pt.plugin = plugin;
15425                                 pt.setRatio = setRatio;
15426                                 for (i = 0; i < l; i++) {
15427                                         bv = ba[i];
15428                                         ev = ea[i];
15429                                         bn = parseFloat(bv);
15430
15431                                         //if the value begins with a number (most common). It's fine if it has a suffix like px
15432                                         if (bn || bn === 0) {
15433                                                 pt.appendXtra("", bn, _parseChange(ev, bn), ev.replace(_relNumExp, ""), (autoRound && ev.indexOf("px") !== -1), true);
15434
15435                                         //if the value is a color
15436                                         } else if (clrs && (bv.charAt(0) === "#" || _colorLookup[bv] || _rgbhslExp.test(bv))) {
15437                                                 str = ev.charAt(ev.length - 1) === "," ? ")," : ")"; //if there's a comma at the end, retain it.
15438                                                 bv = _parseColor(bv);
15439                                                 ev = _parseColor(ev);
15440                                                 rgba = (bv.length + ev.length > 6);
15441                                                 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
15442                                                         pt["xs" + pt.l] += pt.l ? " transparent" : "transparent";
15443                                                         pt.e = pt.e.split(ea[i]).join("transparent");
15444                                                 } else {
15445                                                         if (!_supportsOpacity) { //old versions of IE don't support rgba().
15446                                                                 rgba = false;
15447                                                         }
15448                                                         pt.appendXtra((rgba ? "rgba(" : "rgb("), bv[0], ev[0] - bv[0], ",", true, true)
15449                                                                 .appendXtra("", bv[1], ev[1] - bv[1], ",", true)
15450                                                                 .appendXtra("", bv[2], ev[2] - bv[2], (rgba ? "," : str), true);
15451                                                         if (rgba) {
15452                                                                 bv = (bv.length < 4) ? 1 : bv[3];
15453                                                                 pt.appendXtra("", bv, ((ev.length < 4) ? 1 : ev[3]) - bv, str, false);
15454                                                         }
15455                                                 }
15456
15457                                         } else {
15458                                                 bnums = bv.match(_numExp); //gets each group of numbers in the beginning value string and drops them into an array
15459
15460                                                 //if no number is found, treat it as a non-tweening value and just append the string to the current xs.
15461                                                 if (!bnums) {
15462                                                         pt["xs" + pt.l] += pt.l ? " " + bv : bv;
15463
15464                                                 //loop through all the numbers that are found and construct the extra values on the pt.
15465                                                 } else {
15466                                                         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
15467                                                         if (!enums || enums.length !== bnums.length) {
15468                                                                 //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")");
15469                                                                 return pt;
15470                                                         }
15471                                                         ni = 0;
15472                                                         for (xi = 0; xi < bnums.length; xi++) {
15473                                                                 cv = bnums[xi];
15474                                                                 temp = bv.indexOf(cv, ni);
15475                                                                 pt.appendXtra(bv.substr(ni, temp - ni), Number(cv), _parseChange(enums[xi], cv), "", (autoRound && bv.substr(temp + cv.length, 2) === "px"), (xi === 0));
15476                                                                 ni = temp + cv.length;
15477                                                         }
15478                                                         pt["xs" + pt.l] += bv.substr(ni);
15479                                                 }
15480                                         }
15481                                 }
15482                                 //if there are relative values ("+=" or "-=" prefix), we need to adjust the ending value to eliminate the prefixes and combine the values properly.
15483                                 if (e.indexOf("=") !== -1) if (pt.data) {
15484                                         str = pt.xs0 + pt.data.s;
15485                                         for (i = 1; i < pt.l; i++) {
15486                                                 str += pt["xs" + i] + pt.data["xn" + i];
15487                                         }
15488                                         pt.e = str + pt["xs" + i];
15489                                 }
15490                                 if (!pt.l) {
15491                                         pt.type = -1;
15492                                         pt.xs0 = pt.e;
15493                                 }
15494                                 return pt.xfirst || pt;
15495                         },
15496                         i = 9;
15497
15498
15499                 p = CSSPropTween.prototype;
15500                 p.l = p.pr = 0; //length (number of extra properties like xn1, xn2, xn3, etc.
15501                 while (--i > 0) {
15502                         p["xn" + i] = 0;
15503                         p["xs" + i] = "";
15504                 }
15505                 p.xs0 = "";
15506                 p._next = p._prev = p.xfirst = p.data = p.plugin = p.setRatio = p.rxp = null;
15507
15508
15509                 /**
15510                  * 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:
15511                  * xs0:"rect(", s:10, xs1:"px, ", xn1:5, xs2:"px, ", xn2:0, xs3:"px, ", xn3:20, xn4:"px)"
15512                  * And they'd all get joined together when the CSSPlugin renders (in the setRatio() method).
15513                  * @param {string=} pfx Prefix (if any)
15514                  * @param {!number} s Starting value
15515                  * @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.
15516                  * @param {string=} sfx Suffix (if any)
15517                  * @param {boolean=} r Round (if true).
15518                  * @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.
15519                  * @return {CSSPropTween} returns itself so that multiple methods can be chained together.
15520                  */
15521                 p.appendXtra = function(pfx, s, c, sfx, r, pad) {
15522                         var pt = this,
15523                                 l = pt.l;
15524                         pt["xs" + l] += (pad && l) ? " " + pfx : pfx || "";
15525                         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!
15526                                 pt["xs" + l] += s + (sfx || "");
15527                                 return pt;
15528                         }
15529                         pt.l++;
15530                         pt.type = pt.setRatio ? 2 : 1;
15531                         pt["xs" + pt.l] = sfx || "";
15532                         if (l > 0) {
15533                                 pt.data["xn" + l] = s + c;
15534                                 pt.rxp["xn" + l] = r; //round extra property (we need to tap into this in the _parseToProxy() method)
15535                                 pt["xn" + l] = s;
15536                                 if (!pt.plugin) {
15537                                         pt.xfirst = new CSSPropTween(pt, "xn" + l, s, c, pt.xfirst || pt, 0, pt.n, r, pt.pr);
15538                                         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.
15539                                 }
15540                                 return pt;
15541                         }
15542                         pt.data = {s:s + c};
15543                         pt.rxp = {};
15544                         pt.s = s;
15545                         pt.c = c;
15546                         pt.r = r;
15547                         return pt;
15548                 };
15549
15550                 /**
15551                  * @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.
15552                  * @param {!string} p Property name (like "boxShadow" or "throwProps")
15553                  * @param {Object=} options An object containing any of the following configuration options:
15554                  *                      - defaultValue: the default value
15555                  *                      - 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)
15556                  *                      - 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.)
15557                  *                      - prefix: if true, we'll determine whether or not this property requires a vendor prefix (like Webkit or Moz or ms or O)
15558                  *                      - color: set this to true if the value for this SpecialProp may contain color-related values like rgb(), rgba(), etc.
15559                  *                      - priority: priority in the linked list order. Higher priority SpecialProps will be updated before lower priority ones. The default priority is 0.
15560                  *                      - multi: if true, the formatter should accommodate a comma-delimited list of values, like boxShadow could have multiple boxShadows listed out.
15561                  *                      - 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.
15562                  *                      - 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).
15563                  */
15564                 var SpecialProp = function(p, options) {
15565                                 options = options || {};
15566                                 this.p = options.prefix ? _checkPropPrefix(p) || p : p;
15567                                 _specialProps[p] = _specialProps[this.p] = this;
15568                                 this.format = options.formatter || _getFormatter(options.defaultValue, options.color, options.collapsible, options.multi);
15569                                 if (options.parser) {
15570                                         this.parse = options.parser;
15571                                 }
15572                                 this.clrs = options.color;
15573                                 this.multi = options.multi;
15574                                 this.keyword = options.keyword;
15575                                 this.dflt = options.defaultValue;
15576                                 this.pr = options.priority || 0;
15577                         },
15578
15579                         //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.
15580                         _registerComplexSpecialProp = _internals._registerComplexSpecialProp = function(p, options, defaults) {
15581                                 if (typeof(options) !== "object") {
15582                                         options = {parser:defaults}; //to make backwards compatible with older versions of BezierPlugin and ThrowPropsPlugin
15583                                 }
15584                                 var a = p.split(","),
15585                                         d = options.defaultValue,
15586                                         i, temp;
15587                                 defaults = defaults || [d];
15588                                 for (i = 0; i < a.length; i++) {
15589                                         options.prefix = (i === 0 && options.prefix);
15590                                         options.defaultValue = defaults[i] || d;
15591                                         temp = new SpecialProp(a[i], options);
15592                                 }
15593                         },
15594
15595                         //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.
15596                         _registerPluginProp = function(p) {
15597                                 if (!_specialProps[p]) {
15598                                         var pluginName = p.charAt(0).toUpperCase() + p.substr(1) + "Plugin";
15599                                         _registerComplexSpecialProp(p, {parser:function(t, e, p, cssp, pt, plugin, vars) {
15600                                                 var pluginClass = (window.GreenSockGlobals || window).com.greensock.plugins[pluginName];
15601                                                 if (!pluginClass) {
15602                                                         _log("Error: " + pluginName + " js file not loaded.");
15603                                                         return pt;
15604                                                 }
15605                                                 pluginClass._cssRegister();
15606                                                 return _specialProps[p].parse(t, e, p, cssp, pt, plugin, vars);
15607                                         }});
15608                                 }
15609                         };
15610
15611
15612                 p = SpecialProp.prototype;
15613
15614                 /**
15615                  * 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)
15616                  * @param {!Object} t target element
15617                  * @param {(string|number|object)} b beginning value
15618                  * @param {(string|number|object)} e ending (destination) value
15619                  * @param {CSSPropTween=} pt next CSSPropTween in the linked list
15620                  * @param {TweenPlugin=} plugin If another plugin will be tweening the complex value, that TweenPlugin instance goes here.
15621                  * @param {function=} setRatio If a custom setRatio() method should be used to handle this complex value, that goes here.
15622                  * @return {CSSPropTween=} First CSSPropTween in the linked list
15623                  */
15624                 p.parseComplex = function(t, b, e, pt, plugin, setRatio) {
15625                         var kwd = this.keyword,
15626                                 i, ba, ea, l, bi, ei;
15627                         //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)
15628                         if (this.multi) if (_commasOutsideParenExp.test(e) || _commasOutsideParenExp.test(b)) {
15629                                 ba = b.replace(_commasOutsideParenExp, "|").split("|");
15630                                 ea = e.replace(_commasOutsideParenExp, "|").split("|");
15631                         } else if (kwd) {
15632                                 ba = [b];
15633                                 ea = [e];
15634                         }
15635                         if (ea) {
15636                                 l = (ea.length > ba.length) ? ea.length : ba.length;
15637                                 for (i = 0; i < l; i++) {
15638                                         b = ba[i] = ba[i] || this.dflt;
15639                                         e = ea[i] = ea[i] || this.dflt;
15640                                         if (kwd) {
15641                                                 bi = b.indexOf(kwd);
15642                                                 ei = e.indexOf(kwd);
15643                                                 if (bi !== ei) {
15644                                                         e = (ei === -1) ? ea : ba;
15645                                                         e[i] += " " + kwd;
15646                                                 }
15647                                         }
15648                                 }
15649                                 b = ba.join(", ");
15650                                 e = ea.join(", ");
15651                         }
15652                         return _parseComplex(t, this.p, b, e, this.clrs, this.dflt, pt, this.pr, plugin, setRatio);
15653                 };
15654
15655                 /**
15656                  * 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:
15657                  * this._firstPT = sp.parse(element, "5px 10px 20px rgb(2550,102,51)", "boxShadow", this);
15658                  * 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).
15659                  * @param {!Object} t Target object whose property is being tweened
15660                  * @param {Object} e End value as provided in the vars object (typically a string, but not always - like a throwProps would be an object).
15661                  * @param {!string} p Property name
15662                  * @param {!CSSPlugin} cssp The CSSPlugin instance that should be associated with this tween.
15663                  * @param {?CSSPropTween} pt The CSSPropTween that is the current head of the linked list (we'll prepend to it)
15664                  * @param {TweenPlugin=} plugin If a plugin will be used to tween the parsed value, this is the plugin instance.
15665                  * @param {Object=} vars Original vars object that contains the data for parsing.
15666                  * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parse() call.
15667                  */
15668                 p.parse = function(t, e, p, cssp, pt, plugin, vars) {
15669                         return this.parseComplex(t.style, this.format(_getStyle(t, this.p, _cs, false, this.dflt)), this.format(e), pt, plugin);
15670                 };
15671
15672                 /**
15673                  * 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:
15674                  *  1) Target object whose property should be tweened (typically a DOM element)
15675                  *  2) The end/destination value (could be a string, number, object, or whatever you want)
15676                  *  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)
15677                  *
15678                  * 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:
15679                  *
15680                  * CSSPlugin.registerSpecialProp("myCustomProp", function(target, value, tween) {
15681                  *      var start = target.style.width;
15682                  *      return function(ratio) {
15683                  *              target.style.width = (start + value * ratio) + "px";
15684                  *              console.log("set width to " + target.style.width);
15685                  *          }
15686                  * }, 0);
15687                  *
15688                  * Then, when I do this tween, it will trigger my special property:
15689                  *
15690                  * TweenLite.to(element, 1, {css:{myCustomProp:100}});
15691                  *
15692                  * In the example, of course, we're just changing the width, but you can do anything you want.
15693                  *
15694                  * @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}})
15695                  * @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.
15696                  * @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.
15697                  */
15698                 CSSPlugin.registerSpecialProp = function(name, onInitTween, priority) {
15699                         _registerComplexSpecialProp(name, {parser:function(t, e, p, cssp, pt, plugin, vars) {
15700                                 var rv = new CSSPropTween(t, p, 0, 0, pt, 2, p, false, priority);
15701                                 rv.plugin = plugin;
15702                                 rv.setRatio = onInitTween(t, e, cssp._tween, p);
15703                                 return rv;
15704                         }, priority:priority});
15705                 };
15706
15707
15708
15709
15710
15711
15712
15713
15714                 //transform-related methods and properties
15715                 var _transformProps = ("scaleX,scaleY,scaleZ,x,y,z,skewX,skewY,rotation,rotationX,rotationY,perspective").split(","),
15716                         _transformProp = _checkPropPrefix("transform"), //the Javascript (camelCase) transform property, like msTransform, WebkitTransform, MozTransform, or OTransform.
15717                         _transformPropCSS = _prefixCSS + "transform",
15718                         _transformOriginProp = _checkPropPrefix("transformOrigin"),
15719                         _supports3D = (_checkPropPrefix("perspective") !== null),
15720                         Transform = _internals.Transform = function() {
15721                                 this.skewY = 0;
15722                         },
15723
15724                         /**
15725                          * 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.
15726                          * @param {!Object} t target element
15727                          * @param {Object=} cs computed style object (optional)
15728                          * @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...}
15729                          * @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)
15730                          * @return {object} object containing all of the transform properties/values like {x:0, y:0, z:0, scaleX:1...}
15731                          */
15732                         _getTransform = _internals.getTransform = function(t, cs, rec, parse) {
15733                                 if (t._gsTransform && rec && !parse) {
15734                                         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.
15735                                 }
15736                                 var tm = rec ? t._gsTransform || new Transform() : new Transform(),
15737                                         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.
15738                                         min = 0.00002,
15739                                         rnd = 100000,
15740                                         minAngle = 179.99,
15741                                         minPI = minAngle * _DEG2RAD,
15742                                         zOrigin = _supports3D ? parseFloat(_getStyle(t, _transformOriginProp, cs, false, "0 0 0").split(" ")[2]) || tm.zOrigin  || 0 : 0,
15743                                         s, m, i, n, dec, scaleX, scaleY, rotation, skewX, difX, difY, difR, difS;
15744                                 if (_transformProp) {
15745                                         s = _getStyle(t, _transformPropCSS, cs, true);
15746                                 } else if (t.currentStyle) {
15747                                         //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.
15748                                         s = t.currentStyle.filter.match(_ieGetMatrixExp);
15749                                         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(",") : "";
15750                                 }
15751                                 //split the matrix values out into an array (m for matrix)
15752                                 m = (s || "").match(/(?:\-|\b)[\d\-\.e]+\b/gi) || [];
15753                                 i = m.length;
15754                                 while (--i > -1) {
15755                                         n = Number(m[i]);
15756                                         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).
15757                                 }
15758                                 if (m.length === 16) {
15759
15760                                         //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)
15761                                         var a13 = m[8], a23 = m[9], a33 = m[10],
15762                                                 a14 = m[12], a24 = m[13], a34 = m[14];
15763
15764                                         //we manually compensate for non-zero z component of transformOrigin to work around bugs in Safari
15765                                         if (tm.zOrigin) {
15766                                                 a34 = -tm.zOrigin;
15767                                                 a14 = a13*a34-m[12];
15768                                                 a24 = a23*a34-m[13];
15769                                                 a34 = a33*a34+tm.zOrigin-m[14];
15770                                         }
15771
15772                                         //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.
15773                                         if (!rec || parse || tm.rotationX == null) {
15774                                                 var a11 = m[0], a21 = m[1], a31 = m[2], a41 = m[3],
15775                                                         a12 = m[4], a22 = m[5], a32 = m[6], a42 = m[7],
15776                                                         a43 = m[11],
15777                                                         angle = Math.atan2(a32, a33),
15778                                                         xFlip = (angle < -minPI || angle > minPI),
15779                                                         t1, t2, t3, cos, sin, yFlip, zFlip;
15780                                                 tm.rotationX = angle * _RAD2DEG;
15781                                                 //rotationX
15782                                                 if (angle) {
15783                                                         cos = Math.cos(-angle);
15784                                                         sin = Math.sin(-angle);
15785                                                         t1 = a12*cos+a13*sin;
15786                                                         t2 = a22*cos+a23*sin;
15787                                                         t3 = a32*cos+a33*sin;
15788                                                         a13 = a12*-sin+a13*cos;
15789                                                         a23 = a22*-sin+a23*cos;
15790                                                         a33 = a32*-sin+a33*cos;
15791                                                         a43 = a42*-sin+a43*cos;
15792                                                         a12 = t1;
15793                                                         a22 = t2;
15794                                                         a32 = t3;
15795                                                 }
15796                                                 //rotationY
15797                                                 angle = Math.atan2(a13, a11);
15798                                                 tm.rotationY = angle * _RAD2DEG;
15799                                                 if (angle) {
15800                                                         yFlip = (angle < -minPI || angle > minPI);
15801                                                         cos = Math.cos(-angle);
15802                                                         sin = Math.sin(-angle);
15803                                                         t1 = a11*cos-a13*sin;
15804                                                         t2 = a21*cos-a23*sin;
15805                                                         t3 = a31*cos-a33*sin;
15806                                                         a23 = a21*sin+a23*cos;
15807                                                         a33 = a31*sin+a33*cos;
15808                                                         a43 = a41*sin+a43*cos;
15809                                                         a11 = t1;
15810                                                         a21 = t2;
15811                                                         a31 = t3;
15812                                                 }
15813                                                 //rotationZ
15814                                                 angle = Math.atan2(a21, a22);
15815                                                 tm.rotation = angle * _RAD2DEG;
15816                                                 if (angle) {
15817                                                         zFlip = (angle < -minPI || angle > minPI);
15818                                                         cos = Math.cos(-angle);
15819                                                         sin = Math.sin(-angle);
15820                                                         a11 = a11*cos+a12*sin;
15821                                                         t2 = a21*cos+a22*sin;
15822                                                         a22 = a21*-sin+a22*cos;
15823                                                         a32 = a31*-sin+a32*cos;
15824                                                         a21 = t2;
15825                                                 }
15826
15827                                                 if (zFlip && xFlip) {
15828                                                         tm.rotation = tm.rotationX = 0;
15829                                                 } else if (zFlip && yFlip) {
15830                                                         tm.rotation = tm.rotationY = 0;
15831                                                 } else if (yFlip && xFlip) {
15832                                                         tm.rotationY = tm.rotationX = 0;
15833                                                 }
15834
15835                                                 tm.scaleX = ((Math.sqrt(a11 * a11 + a21 * a21) * rnd + 0.5) | 0) / rnd;
15836                                                 tm.scaleY = ((Math.sqrt(a22 * a22 + a23 * a23) * rnd + 0.5) | 0) / rnd;
15837                                                 tm.scaleZ = ((Math.sqrt(a32 * a32 + a33 * a33) * rnd + 0.5) | 0) / rnd;
15838                                                 tm.skewX = 0;
15839                                                 tm.perspective = a43 ? 1 / ((a43 < 0) ? -a43 : a43) : 0;
15840                                                 tm.x = a14;
15841                                                 tm.y = a24;
15842                                                 tm.z = a34;
15843                                         }
15844
15845                                 } 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.
15846                                         var k = (m.length >= 6),
15847                                                 a = k ? m[0] : 1,
15848                                                 b = m[1] || 0,
15849                                                 c = m[2] || 0,
15850                                                 d = k ? m[3] : 1;
15851                                         tm.x = m[4] || 0;
15852                                         tm.y = m[5] || 0;
15853                                         scaleX = Math.sqrt(a * a + b * b);
15854                                         scaleY = Math.sqrt(d * d + c * c);
15855                                         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).
15856                                         skewX = (c || d) ? Math.atan2(c, d) * _RAD2DEG + rotation : tm.skewX || 0;
15857                                         difX = scaleX - Math.abs(tm.scaleX || 0);
15858                                         difY = scaleY - Math.abs(tm.scaleY || 0);
15859                                         if (Math.abs(skewX) > 90 && Math.abs(skewX) < 270) {
15860                                                 if (invX) {
15861                                                         scaleX *= -1;
15862                                                         skewX += (rotation <= 0) ? 180 : -180;
15863                                                         rotation += (rotation <= 0) ? 180 : -180;
15864                                                 } else {
15865                                                         scaleY *= -1;
15866                                                         skewX += (skewX <= 0) ? 180 : -180;
15867                                                 }
15868                                         }
15869                                         difR = (rotation - tm.rotation) % 180; //note: matching ranges would be very small (+/-0.0001) or very close to 180.
15870                                         difS = (skewX - tm.skewX) % 180;
15871                                         //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.
15872                                         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)) {
15873                                                 tm.scaleX = scaleX;
15874                                                 tm.scaleY = scaleY;
15875                                                 tm.rotation = rotation;
15876                                                 tm.skewX = skewX;
15877                                         }
15878                                         if (_supports3D) {
15879                                                 tm.rotationX = tm.rotationY = tm.z = 0;
15880                                                 tm.perspective = parseFloat(CSSPlugin.defaultTransformPerspective) || 0;
15881                                                 tm.scaleZ = 1;
15882                                         }
15883                                 }
15884                                 tm.zOrigin = zOrigin;
15885
15886                                 //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.
15887                                 for (i in tm) {
15888                                         if (tm[i] < min) if (tm[i] > -min) {
15889                                                 tm[i] = 0;
15890                                         }
15891                                 }
15892                                 //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);
15893                                 if (rec) {
15894                                         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)
15895                                 }
15896                                 return tm;
15897                         },
15898
15899                         //for setting 2D transforms in IE6, IE7, and IE8 (must use a "filter" to emulate the behavior of modern day browser transforms)
15900                         _setIETransformRatio = function(v) {
15901                                 var t = this.data, //refers to the element's _gsTransform object
15902                                         ang = -t.rotation * _DEG2RAD,
15903                                         skew = ang + t.skewX * _DEG2RAD,
15904                                         rnd = 100000,
15905                                         a = ((Math.cos(ang) * t.scaleX * rnd) | 0) / rnd,
15906                                         b = ((Math.sin(ang) * t.scaleX * rnd) | 0) / rnd,
15907                                         c = ((Math.sin(skew) * -t.scaleY * rnd) | 0) / rnd,
15908                                         d = ((Math.cos(skew) * t.scaleY * rnd) | 0) / rnd,
15909                                         style = this.t.style,
15910                                         cs = this.t.currentStyle,
15911                                         filters, val;
15912                                 if (!cs) {
15913                                         return;
15914                                 }
15915                                 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)
15916                                 b = -c;
15917                                 c = -val;
15918                                 filters = cs.filter;
15919                                 style.filter = ""; //remove filters so that we can accurately measure offsetWidth/offsetHeight
15920                                 var w = this.t.offsetWidth,
15921                                         h = this.t.offsetHeight,
15922                                         clip = (cs.position !== "absolute"),
15923                                         m = "progid:DXImageTransform.Microsoft.Matrix(M11=" + a + ", M12=" + b + ", M21=" + c + ", M22=" + d,
15924                                         ox = t.x,
15925                                         oy = t.y,
15926                                         dx, dy;
15927
15928                                 //if transformOrigin is being used, adjust the offset x and y
15929                                 if (t.ox != null) {
15930                                         dx = ((t.oxp) ? w * t.ox * 0.01 : t.ox) - w / 2;
15931                                         dy = ((t.oyp) ? h * t.oy * 0.01 : t.oy) - h / 2;
15932                                         ox += dx - (dx * a + dy * b);
15933                                         oy += dy - (dx * c + dy * d);
15934                                 }
15935
15936                                 if (!clip) {
15937                                         m += ", sizingMethod='auto expand')";
15938                                 } else {
15939                                         dx = (w / 2);
15940                                         dy = (h / 2);
15941                                         //translate to ensure that transformations occur around the correct origin (default is center).
15942                                         m += ", Dx=" + (dx - (dx * a + dy * b) + ox) + ", Dy=" + (dy - (dx * c + dy * d) + oy) + ")";
15943                                 }
15944                                 if (filters.indexOf("DXImageTransform.Microsoft.Matrix(") !== -1) {
15945                                         style.filter = filters.replace(_ieSetMatrixExp, m);
15946                                 } else {
15947                                         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.
15948                                 }
15949
15950                                 //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.
15951                                 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) {
15952                                         style.removeAttribute("filter");
15953                                 }
15954
15955                                 //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).
15956                                 if (!clip) {
15957                                         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
15958                                                 marg, prop, dif;
15959                                         dx = t.ieOffsetX || 0;
15960                                         dy = t.ieOffsetY || 0;
15961                                         t.ieOffsetX = Math.round((w - ((a < 0 ? -a : a) * w + (b < 0 ? -b : b) * h)) / 2 + ox);
15962                                         t.ieOffsetY = Math.round((h - ((d < 0 ? -d : d) * h + (c < 0 ? -c : c) * w)) / 2 + oy);
15963                                         for (i = 0; i < 4; i++) {
15964                                                 prop = _margins[i];
15965                                                 marg = cs[prop];
15966                                                 //we need to get the current margin in case it is being tweened separately (we want to respect that tween's changes)
15967                                                 val = (marg.indexOf("px") !== -1) ? parseFloat(marg) : _convertToPixels(this.t, prop, parseFloat(marg), marg.replace(_suffixExp, "")) || 0;
15968                                                 if (val !== t[prop]) {
15969                                                         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.
15970                                                 } else {
15971                                                         dif = (i < 2) ? dx - t.ieOffsetX : dy - t.ieOffsetY;
15972                                                 }
15973                                                 style[prop] = (t[prop] = Math.round( val - dif * ((i === 0 || i === 2) ? 1 : mult) )) + "px";
15974                                         }
15975                                 }
15976                         },
15977
15978                         _set3DTransformRatio = _internals.set3DTransformRatio = function(v) {
15979                                 var t = this.data, //refers to the element's _gsTransform object
15980                                         style = this.t.style,
15981                                         angle = t.rotation * _DEG2RAD,
15982                                         sx = t.scaleX,
15983                                         sy = t.scaleY,
15984                                         sz = t.scaleZ,
15985                                         perspective = t.perspective,
15986                                         a11, a12, a13, a14,     a21, a22, a23, a24, a31, a32, a33, a34, a41, a42, a43,
15987                                         zOrigin, rnd, cos, sin, t1, t2, t3, t4;
15988                                 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
15989                                         _set2DTransformRatio.call(this, v);
15990                                         return;
15991                                 }
15992                                 if (_isFirefox) {
15993                                         var n = 0.0001;
15994                                         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.
15995                                                 sx = sz = 0.00002;
15996                                         }
15997                                         if (sy < n && sy > -n) {
15998                                                 sy = sz = 0.00002;
15999                                         }
16000                                         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).
16001                                                 perspective = 0;
16002                                         }
16003                                 }
16004                                 if (angle || t.skewX) {
16005                                         cos = Math.cos(angle);
16006                                         sin = Math.sin(angle);
16007                                         a11 = cos;
16008                                         a21 = sin;
16009                                         if (t.skewX) {
16010                                                 angle -= t.skewX * _DEG2RAD;
16011                                                 cos = Math.cos(angle);
16012                                                 sin = Math.sin(angle);
16013                                                 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
16014                                                         t1 = Math.tan(t.skewX * _DEG2RAD);
16015                                                         t1 = Math.sqrt(1 + t1 * t1);
16016                                                         cos *= t1;
16017                                                         sin *= t1;
16018                                                 }
16019                                         }
16020                                         a12 = -sin;
16021                                         a22 = cos;
16022
16023                                 } else if (!t.rotationY && !t.rotationX && sz === 1 && !perspective) { //if we're only translating and/or 2D scaling, this is faster...
16024                                         style[_transformProp] = "translate3d(" + t.x + "px," + t.y + "px," + t.z +"px)" + ((sx !== 1 || sy !== 1) ? " scale(" + sx + "," + sy + ")" : "");
16025                                         return;
16026                                 } else {
16027                                         a11 = a22 = 1;
16028                                         a12 = a21 = 0;
16029                                 }
16030                                 a33 = 1;
16031                                 a13 = a14 = a23 = a24 = a31 = a32 = a34 = a41 = a42 = 0;
16032                                 a43 = (perspective) ? -1 / perspective : 0;
16033                                 zOrigin = t.zOrigin;
16034                                 rnd = 100000;
16035                                 angle = t.rotationY * _DEG2RAD;
16036                                 if (angle) {
16037                                         cos = Math.cos(angle);
16038                                         sin = Math.sin(angle);
16039                                         a31 = a33*-sin;
16040                                         a41 = a43*-sin;
16041                                         a13 = a11*sin;
16042                                         a23 = a21*sin;
16043                                         a33 *= cos;
16044                                         a43 *= cos;
16045                                         a11 *= cos;
16046                                         a21 *= cos;
16047                                 }
16048                                 angle = t.rotationX * _DEG2RAD;
16049                                 if (angle) {
16050                                         cos = Math.cos(angle);
16051                                         sin = Math.sin(angle);
16052                                         t1 = a12*cos+a13*sin;
16053                                         t2 = a22*cos+a23*sin;
16054                                         t3 = a32*cos+a33*sin;
16055                                         t4 = a42*cos+a43*sin;
16056                                         a13 = a12*-sin+a13*cos;
16057                                         a23 = a22*-sin+a23*cos;
16058                                         a33 = a32*-sin+a33*cos;
16059                                         a43 = a42*-sin+a43*cos;
16060                                         a12 = t1;
16061                                         a22 = t2;
16062                                         a32 = t3;
16063                                         a42 = t4;
16064                                 }
16065                                 if (sz !== 1) {
16066                                         a13*=sz;
16067                                         a23*=sz;
16068                                         a33*=sz;
16069                                         a43*=sz;
16070                                 }
16071                                 if (sy !== 1) {
16072                                         a12*=sy;
16073                                         a22*=sy;
16074                                         a32*=sy;
16075                                         a42*=sy;
16076                                 }
16077                                 if (sx !== 1) {
16078                                         a11*=sx;
16079                                         a21*=sx;
16080                                         a31*=sx;
16081                                         a41*=sx;
16082                                 }
16083                                 if (zOrigin) {
16084                                         a34 -= zOrigin;
16085                                         a14 = a13*a34;
16086                                         a24 = a23*a34;
16087                                         a34 = a33*a34+zOrigin;
16088                                 }
16089                                 //we round the x, y, and z slightly differently to allow even larger values.
16090                                 a14 = (t1 = (a14 += t.x) - (a14 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a14 : a14;
16091                                 a24 = (t1 = (a24 += t.y) - (a24 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a24 : a24;
16092                                 a34 = (t1 = (a34 += t.z) - (a34 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a34 : a34;
16093                                 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(",") + ")";
16094                         },
16095
16096                         _set2DTransformRatio = _internals.set2DTransformRatio = function(v) {
16097                                 var t = this.data, //refers to the element's _gsTransform object
16098                                         targ = this.t,
16099                                         style = targ.style,
16100                                         ang, skew, rnd, sx, sy;
16101                                 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.
16102                                         this.setRatio = _set3DTransformRatio;
16103                                         _set3DTransformRatio.call(this, v);
16104                                         return;
16105                                 }
16106                                 if (!t.rotation && !t.skewX) {
16107                                         style[_transformProp] = "matrix(" + t.scaleX + ",0,0," + t.scaleY + "," + t.x + "," + t.y + ")";
16108                                 } else {
16109                                         ang = t.rotation * _DEG2RAD;
16110                                         skew = ang - t.skewX * _DEG2RAD;
16111                                         rnd = 100000;
16112                                         sx = t.scaleX * rnd;
16113                                         sy = t.scaleY * rnd;
16114                                         //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.
16115                                         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 + ")";
16116                                 }
16117                         };
16118
16119                 _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) {
16120                         if (cssp._transform) { return pt; } //only need to parse the transform once, and only if the browser supports it.
16121                         var m1 = cssp._transform = _getTransform(t, _cs, true, vars.parseTransform),
16122                                 style = t.style,
16123                                 min = 0.000001,
16124                                 i = _transformProps.length,
16125                                 v = vars,
16126                                 endRotations = {},
16127                                 m2, skewY, copy, orig, has3D, hasChange, dr;
16128                         if (typeof(v.transform) === "string" && _transformProp) { //for values like transform:"rotate(60deg) scale(0.5, 0.8)"
16129                                 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.
16130                                 copy[_transformProp] = v.transform;
16131                                 copy.display = "block"; //if display is "none", the browser often refuses to report the transform properties correctly.
16132                                 copy.position = "absolute";
16133                                 _doc.body.appendChild(_tempDiv);
16134                                 m2 = _getTransform(_tempDiv, null, false);
16135                                 _doc.body.removeChild(_tempDiv);
16136                         } else if (typeof(v) === "object") { //for values like scaleX, scaleY, rotation, x, y, skewX, and skewY or transform:{...} (object)
16137                                 m2 = {scaleX:_parseVal((v.scaleX != null) ? v.scaleX : v.scale, m1.scaleX),
16138                                         scaleY:_parseVal((v.scaleY != null) ? v.scaleY : v.scale, m1.scaleY),
16139                                         scaleZ:_parseVal(v.scaleZ, m1.scaleZ),
16140                                         x:_parseVal(v.x, m1.x),
16141                                         y:_parseVal(v.y, m1.y),
16142                                         z:_parseVal(v.z, m1.z),
16143                                         perspective:_parseVal(v.transformPerspective, m1.perspective)};
16144                                 dr = v.directionalRotation;
16145                                 if (dr != null) {
16146                                         if (typeof(dr) === "object") {
16147                                                 for (copy in dr) {
16148                                                         v[copy] = dr[copy];
16149                                                 }
16150                                         } else {
16151                                                 v.rotation = dr;
16152                                         }
16153                                 }
16154                                 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);
16155                                 if (_supports3D) {
16156                                         m2.rotationX = _parseAngle(("rotationX" in v) ? v.rotationX : ("shortRotationX" in v) ? v.shortRotationX + "_short" : m1.rotationX || 0, m1.rotationX, "rotationX", endRotations);
16157                                         m2.rotationY = _parseAngle(("rotationY" in v) ? v.rotationY : ("shortRotationY" in v) ? v.shortRotationY + "_short" : m1.rotationY || 0, m1.rotationY, "rotationY", endRotations);
16158                                 }
16159                                 m2.skewX = (v.skewX == null) ? m1.skewX : _parseAngle(v.skewX, m1.skewX);
16160
16161                                 //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.
16162                                 m2.skewY = (v.skewY == null) ? m1.skewY : _parseAngle(v.skewY, m1.skewY);
16163                                 if ((skewY = m2.skewY - m1.skewY)) {
16164                                         m2.skewX += skewY;
16165                                         m2.rotation += skewY;
16166                                 }
16167                         }
16168
16169                         if (_supports3D && v.force3D != null) {
16170                                 m1.force3D = v.force3D;
16171                                 hasChange = true;
16172                         }
16173
16174                         m1.skewType = v.skewType || m1.skewType || CSSPlugin.defaultSkewType;
16175
16176                         has3D = (m1.force3D || m1.z || m1.rotationX || m1.rotationY || m2.z || m2.rotationX || m2.rotationY || m2.perspective);
16177                         if (!has3D && v.scale != null) {
16178                                 m2.scaleZ = 1; //no need to tween scaleZ.
16179                         }
16180
16181                         while (--i > -1) {
16182                                 p = _transformProps[i];
16183                                 orig = m2[p] - m1[p];
16184                                 if (orig > min || orig < -min || _forcePT[p] != null) {
16185                                         hasChange = true;
16186                                         pt = new CSSPropTween(m1, p, m1[p], orig, pt);
16187                                         if (p in endRotations) {
16188                                                 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
16189                                         }
16190                                         pt.xs0 = 0; //ensures the value stays numeric in setRatio()
16191                                         pt.plugin = plugin;
16192                                         cssp._overwriteProps.push(pt.n);
16193                                 }
16194                         }
16195
16196                         orig = v.transformOrigin;
16197                         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).
16198                                 if (_transformProp) {
16199                                         hasChange = true;
16200                                         p = _transformOriginProp;
16201                                         orig = (orig || _getStyle(t, p, _cs, false, "50% 50%")) + ""; //cast as string to avoid errors
16202                                         pt = new CSSPropTween(style, p, 0, 0, pt, -1, "transformOrigin");
16203                                         pt.b = style[p];
16204                                         pt.plugin = plugin;
16205                                         if (_supports3D) {
16206                                                 copy = m1.zOrigin;
16207                                                 orig = orig.split(" ");
16208                                                 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.
16209                                                 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)!
16210                                                 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)
16211                                                 pt.b = copy;
16212                                                 pt.xs0 = pt.e = m1.zOrigin;
16213                                         } else {
16214                                                 pt.xs0 = pt.e = orig;
16215                                         }
16216
16217                                 //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).
16218                                 } else {
16219                                         _parsePosition(orig + "", m1);
16220                                 }
16221                         }
16222
16223                         if (hasChange) {
16224                                 cssp._transformType = (has3D || this._transformType === 3) ? 3 : 2; //quicker than calling cssp._enableTransforms();
16225                         }
16226                         return pt;
16227                 }, prefix:true});
16228
16229                 _registerComplexSpecialProp("boxShadow", {defaultValue:"0px 0px 0px 0px #999", prefix:true, color:true, multi:true, keyword:"inset"});
16230
16231                 _registerComplexSpecialProp("borderRadius", {defaultValue:"0px", parser:function(t, e, p, cssp, pt, plugin) {
16232                         e = this.format(e);
16233                         var props = ["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"],
16234                                 style = t.style,
16235                                 ea1, i, es2, bs2, bs, es, bn, en, w, h, esfx, bsfx, rel, hn, vn, em;
16236                         w = parseFloat(t.offsetWidth);
16237                         h = parseFloat(t.offsetHeight);
16238                         ea1 = e.split(" ");
16239                         for (i = 0; i < props.length; i++) { //if we're dealing with percentages, we must convert things separately for the horizontal and vertical axis!
16240                                 if (this.p.indexOf("border")) { //older browsers used a prefix
16241                                         props[i] = _checkPropPrefix(props[i]);
16242                                 }
16243                                 bs = bs2 = _getStyle(t, props[i], _cs, false, "0px");
16244                                 if (bs.indexOf(" ") !== -1) {
16245                                         bs2 = bs.split(" ");
16246                                         bs = bs2[0];
16247                                         bs2 = bs2[1];
16248                                 }
16249                                 es = es2 = ea1[i];
16250                                 bn = parseFloat(bs);
16251                                 bsfx = bs.substr((bn + "").length);
16252                                 rel = (es.charAt(1) === "=");
16253                                 if (rel) {
16254                                         en = parseInt(es.charAt(0)+"1", 10);
16255                                         es = es.substr(2);
16256                                         en *= parseFloat(es);
16257                                         esfx = es.substr((en + "").length - (en < 0 ? 1 : 0)) || "";
16258                                 } else {
16259                                         en = parseFloat(es);
16260                                         esfx = es.substr((en + "").length);
16261                                 }
16262                                 if (esfx === "") {
16263                                         esfx = _suffixMap[p] || bsfx;
16264                                 }
16265                                 if (esfx !== bsfx) {
16266                                         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.
16267                                         vn = _convertToPixels(t, "borderTop", bn, bsfx); //vertical number
16268                                         if (esfx === "%") {
16269                                                 bs = (hn / w * 100) + "%";
16270                                                 bs2 = (vn / h * 100) + "%";
16271                                         } else if (esfx === "em") {
16272                                                 em = _convertToPixels(t, "borderLeft", 1, "em");
16273                                                 bs = (hn / em) + "em";
16274                                                 bs2 = (vn / em) + "em";
16275                                         } else {
16276                                                 bs = hn + "px";
16277                                                 bs2 = vn + "px";
16278                                         }
16279                                         if (rel) {
16280                                                 es = (parseFloat(bs) + en) + esfx;
16281                                                 es2 = (parseFloat(bs2) + en) + esfx;
16282                                         }
16283                                 }
16284                                 pt = _parseComplex(style, props[i], bs + " " + bs2, es + " " + es2, false, "0px", pt);
16285                         }
16286                         return pt;
16287                 }, prefix:true, formatter:_getFormatter("0px 0px 0px 0px", false, true)});
16288                 _registerComplexSpecialProp("backgroundPosition", {defaultValue:"0 0", parser:function(t, e, p, cssp, pt, plugin) {
16289                         var bp = "background-position",
16290                                 cs = (_cs || _getComputedStyle(t, null)),
16291                                 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
16292                                 es = this.format(e),
16293                                 ba, ea, i, pct, overlap, src;
16294                         if ((bs.indexOf("%") !== -1) !== (es.indexOf("%") !== -1)) {
16295                                 src = _getStyle(t, "backgroundImage").replace(_urlExp, "");
16296                                 if (src && src !== "none") {
16297                                         ba = bs.split(" ");
16298                                         ea = es.split(" ");
16299                                         _tempImg.setAttribute("src", src); //set the temp <img>'s src to the background-image so that we can measure its width/height
16300                                         i = 2;
16301                                         while (--i > -1) {
16302                                                 bs = ba[i];
16303                                                 pct = (bs.indexOf("%") !== -1);
16304                                                 if (pct !== (ea[i].indexOf("%") !== -1)) {
16305                                                         overlap = (i === 0) ? t.offsetWidth - _tempImg.width : t.offsetHeight - _tempImg.height;
16306                                                         ba[i] = pct ? (parseFloat(bs) / 100 * overlap) + "px" : (parseFloat(bs) / overlap * 100) + "%";
16307                                                 }
16308                                         }
16309                                         bs = ba.join(" ");
16310                                 }
16311                         }
16312                         return this.parseComplex(t.style, bs, es, pt, plugin);
16313                 }, formatter:_parsePosition});
16314                 _registerComplexSpecialProp("backgroundSize", {defaultValue:"0 0", formatter:_parsePosition});
16315                 _registerComplexSpecialProp("perspective", {defaultValue:"0px", prefix:true});
16316                 _registerComplexSpecialProp("perspectiveOrigin", {defaultValue:"50% 50%", prefix:true});
16317                 _registerComplexSpecialProp("transformStyle", {prefix:true});
16318                 _registerComplexSpecialProp("backfaceVisibility", {prefix:true});
16319                 _registerComplexSpecialProp("userSelect", {prefix:true});
16320                 _registerComplexSpecialProp("margin", {parser:_getEdgeParser("marginTop,marginRight,marginBottom,marginLeft")});
16321                 _registerComplexSpecialProp("padding", {parser:_getEdgeParser("paddingTop,paddingRight,paddingBottom,paddingLeft")});
16322                 _registerComplexSpecialProp("clip", {defaultValue:"rect(0px,0px,0px,0px)", parser:function(t, e, p, cssp, pt, plugin){
16323                         var b, cs, delim;
16324                         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.
16325                                 cs = t.currentStyle;
16326                                 delim = _ieVers < 8 ? " " : ",";
16327                                 b = "rect(" + cs.clipTop + delim + cs.clipRight + delim + cs.clipBottom + delim + cs.clipLeft + ")";
16328                                 e = this.format(e).split(",").join(delim);
16329                         } else {
16330                                 b = this.format(_getStyle(t, this.p, _cs, false, this.dflt));
16331                                 e = this.format(e);
16332                         }
16333                         return this.parseComplex(t.style, b, e, pt, plugin);
16334                 }});
16335                 _registerComplexSpecialProp("textShadow", {defaultValue:"0px 0px 0px #999", color:true, multi:true});
16336                 _registerComplexSpecialProp("autoRound,strictUnits", {parser:function(t, e, p, cssp, pt) {return pt;}}); //just so that we can ignore these properties (not tween them)
16337                 _registerComplexSpecialProp("border", {defaultValue:"0px solid #000", parser:function(t, e, p, cssp, pt, plugin) {
16338                                 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);
16339                         }, color:true, formatter:function(v) {
16340                                 var a = v.split(" ");
16341                                 return a[0] + " " + (a[1] || "solid") + " " + (v.match(_colorExp) || ["#000"])[0];
16342                         }});
16343                 _registerComplexSpecialProp("borderWidth", {parser:_getEdgeParser("borderTopWidth,borderRightWidth,borderBottomWidth,borderLeftWidth")}); //Firefox doesn't pick up on borderWidth set in style sheets (only inline).
16344                 _registerComplexSpecialProp("float,cssFloat,styleFloat", {parser:function(t, e, p, cssp, pt, plugin) {
16345                         var s = t.style,
16346                                 prop = ("cssFloat" in s) ? "cssFloat" : "styleFloat";
16347                         return new CSSPropTween(s, prop, 0, 0, pt, -1, p, false, 0, s[prop], e);
16348                 }});
16349
16350                 //opacity-related
16351                 var _setIEOpacityRatio = function(v) {
16352                                 var t = this.t, //refers to the element's style property
16353                                         filters = t.filter || _getStyle(this.data, "filter"),
16354                                         val = (this.s + this.c * v) | 0,
16355                                         skip;
16356                                 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.
16357                                         if (filters.indexOf("atrix(") === -1 && filters.indexOf("radient(") === -1 && filters.indexOf("oader(") === -1) {
16358                                                 t.removeAttribute("filter");
16359                                                 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.
16360                                         } else {
16361                                                 t.filter = filters.replace(_alphaFilterExp, "");
16362                                                 skip = true;
16363                                         }
16364                                 }
16365                                 if (!skip) {
16366                                         if (this.xn1) {
16367                                                 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.
16368                                         }
16369                                         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
16370                                                 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)
16371                                                         t.filter = filters + " alpha(opacity=" + val + ")"; //we round the value because otherwise, bugs in IE7/8 can prevent "visibility" changes from being applied properly.
16372                                                 }
16373                                         } else {
16374                                                 t.filter = filters.replace(_opacityExp, "opacity=" + val);
16375                                         }
16376                                 }
16377                         };
16378                 _registerComplexSpecialProp("opacity,alpha,autoAlpha", {defaultValue:"1", parser:function(t, e, p, cssp, pt, plugin) {
16379                         var b = parseFloat(_getStyle(t, "opacity", _cs, false, "1")),
16380                                 style = t.style,
16381                                 isAutoAlpha = (p === "autoAlpha");
16382                         if (typeof(e) === "string" && e.charAt(1) === "=") {
16383                                 e = ((e.charAt(0) === "-") ? -1 : 1) * parseFloat(e.substr(2)) + b;
16384                         }
16385                         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)
16386                                 b = 0;
16387                         }
16388                         if (_supportsOpacity) {
16389                                 pt = new CSSPropTween(style, "opacity", b, e - b, pt);
16390                         } else {
16391                                 pt = new CSSPropTween(style, "opacity", b * 100, (e - b) * 100, pt);
16392                                 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.
16393                                 style.zoom = 1; //helps correct an IE issue.
16394                                 pt.type = 2;
16395                                 pt.b = "alpha(opacity=" + pt.s + ")";
16396                                 pt.e = "alpha(opacity=" + (pt.s + pt.c) + ")";
16397                                 pt.data = t;
16398                                 pt.plugin = plugin;
16399                                 pt.setRatio = _setIEOpacityRatio;
16400                         }
16401                         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
16402                                 pt = new CSSPropTween(style, "visibility", 0, 0, pt, -1, null, false, 0, ((b !== 0) ? "inherit" : "hidden"), ((e === 0) ? "hidden" : "inherit"));
16403                                 pt.xs0 = "inherit";
16404                                 cssp._overwriteProps.push(pt.n);
16405                                 cssp._overwriteProps.push(p);
16406                         }
16407                         return pt;
16408                 }});
16409
16410
16411                 var _removeProp = function(s, p) {
16412                                 if (p) {
16413                                         if (s.removeProperty) {
16414                                                 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)
16415                                                         p = "M" + p.substr(1);
16416                                                 }
16417                                                 s.removeProperty(p.replace(_capsExp, "-$1").toLowerCase());
16418                                         } else { //note: old versions of IE use "removeAttribute()" instead of "removeProperty()"
16419                                                 s.removeAttribute(p);
16420                                         }
16421                                 }
16422                         },
16423                         _setClassNameRatio = function(v) {
16424                                 this.t._gsClassPT = this;
16425                                 if (v === 1 || v === 0) {
16426                                         this.t.setAttribute("class", (v === 0) ? this.b : this.e);
16427                                         var mpt = this.data, //first MiniPropTween
16428                                                 s = this.t.style;
16429                                         while (mpt) {
16430                                                 if (!mpt.v) {
16431                                                         _removeProp(s, mpt.p);
16432                                                 } else {
16433                                                         s[mpt.p] = mpt.v;
16434                                                 }
16435                                                 mpt = mpt._next;
16436                                         }
16437                                         if (v === 1 && this.t._gsClassPT === this) {
16438                                                 this.t._gsClassPT = null;
16439                                         }
16440                                 } else if (this.t.getAttribute("class") !== this.e) {
16441                                         this.t.setAttribute("class", this.e);
16442                                 }
16443                         };
16444                 _registerComplexSpecialProp("className", {parser:function(t, e, p, cssp, pt, plugin, vars) {
16445                         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.
16446                                 cssText = t.style.cssText,
16447                                 difData, bs, cnpt, cnptLookup, mpt;
16448                         pt = cssp._classNamePT = new CSSPropTween(t, p, 0, 0, pt, 2);
16449                         pt.setRatio = _setClassNameRatio;
16450                         pt.pr = -11;
16451                         _hasPriority = true;
16452                         pt.b = b;
16453                         bs = _getAllStyles(t, _cs);
16454                         //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)
16455                         cnpt = t._gsClassPT;
16456                         if (cnpt) {
16457                                 cnptLookup = {};
16458                                 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.
16459                                 while (mpt) {
16460                                         cnptLookup[mpt.p] = 1;
16461                                         mpt = mpt._next;
16462                                 }
16463                                 cnpt.setRatio(1);
16464                         }
16465                         t._gsClassPT = pt;
16466                         pt.e = (e.charAt(1) !== "=") ? e : b.replace(new RegExp("\\s*\\b" + e.substr(2) + "\\b"), "") + ((e.charAt(0) === "+") ? " " + e.substr(2) : "");
16467                         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.
16468                                 t.setAttribute("class", pt.e);
16469                                 difData = _cssDif(t, bs, _getAllStyles(t), vars, cnptLookup);
16470                                 t.setAttribute("class", b);
16471                                 pt.data = difData.firstMPT;
16472                                 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).
16473                                 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)
16474                         }
16475                         return pt;
16476                 }});
16477
16478
16479                 var _setClearPropsRatio = function(v) {
16480                         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).
16481                                 var s = this.t.style,
16482                                         transformParse = _specialProps.transform.parse,
16483                                         a, p, i, clearTransform;
16484                                 if (this.e === "all") {
16485                                         s.cssText = "";
16486                                         clearTransform = true;
16487                                 } else {
16488                                         a = this.e.split(",");
16489                                         i = a.length;
16490                                         while (--i > -1) {
16491                                                 p = a[i];
16492                                                 if (_specialProps[p]) {
16493                                                         if (_specialProps[p].parse === transformParse) {
16494                                                                 clearTransform = true;
16495                                                         } else {
16496                                                                 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"
16497                                                         }
16498                                                 }
16499                                                 _removeProp(s, p);
16500                                         }
16501                                 }
16502                                 if (clearTransform) {
16503                                         _removeProp(s, _transformProp);
16504                                         if (this.t._gsTransform) {
16505                                                 delete this.t._gsTransform;
16506                                         }
16507                                 }
16508
16509                         }
16510                 };
16511                 _registerComplexSpecialProp("clearProps", {parser:function(t, e, p, cssp, pt) {
16512                         pt = new CSSPropTween(t, p, 0, 0, pt, 2);
16513                         pt.setRatio = _setClearPropsRatio;
16514                         pt.e = e;
16515                         pt.pr = -10;
16516                         pt.data = cssp._tween;
16517                         _hasPriority = true;
16518                         return pt;
16519                 }});
16520
16521                 p = "bezier,throwProps,physicsProps,physics2D".split(",");
16522                 i = p.length;
16523                 while (i--) {
16524                         _registerPluginProp(p[i]);
16525                 }
16526
16527
16528
16529
16530
16531
16532
16533
16534                 p = CSSPlugin.prototype;
16535                 p._firstPT = null;
16536
16537                 //gets called when the tween renders for the first time. This kicks everything off, recording start/end values, etc.
16538                 p._onInitTween = function(target, vars, tween) {
16539                         if (!target.nodeType) { //css is only for dom elements
16540                                 return false;
16541                         }
16542                         this._target = target;
16543                         this._tween = tween;
16544                         this._vars = vars;
16545                         _autoRound = vars.autoRound;
16546                         _hasPriority = false;
16547                         _suffixMap = vars.suffixMap || CSSPlugin.suffixMap;
16548                         _cs = _getComputedStyle(target, "");
16549                         _overwriteProps = this._overwriteProps;
16550                         var style = target.style,
16551                                 v, pt, pt2, first, last, next, zIndex, tpt, threeD;
16552                         if (_reqSafariFix) if (style.zIndex === "") {
16553                                 v = _getStyle(target, "zIndex", _cs);
16554                                 if (v === "auto" || v === "") {
16555                                         //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.
16556                                         this._addLazySet(style, "zIndex", 0);
16557                                 }
16558                         }
16559
16560                         if (typeof(vars) === "string") {
16561                                 first = style.cssText;
16562                                 v = _getAllStyles(target, _cs);
16563                                 style.cssText = first + ";" + vars;
16564                                 v = _cssDif(target, v, _getAllStyles(target)).difs;
16565                                 if (!_supportsOpacity && _opacityValExp.test(vars)) {
16566                                         v.opacity = parseFloat( RegExp.$1 );
16567                                 }
16568                                 vars = v;
16569                                 style.cssText = first;
16570                         }
16571                         this._firstPT = pt = this.parse(target, vars, null);
16572
16573                         if (this._transformType) {
16574                                 threeD = (this._transformType === 3);
16575                                 if (!_transformProp) {
16576                                         style.zoom = 1; //helps correct an IE issue.
16577                                 } else if (_isSafari) {
16578                                         _reqSafariFix = true;
16579                                         //if zIndex isn't set, iOS Safari doesn't repaint things correctly sometimes (seemingly at random).
16580                                         if (style.zIndex === "") {
16581                                                 zIndex = _getStyle(target, "zIndex", _cs);
16582                                                 if (zIndex === "auto" || zIndex === "") {
16583                                                         this._addLazySet(style, "zIndex", 0);
16584                                                 }
16585                                         }
16586                                         //Setting WebkitBackfaceVisibility corrects 3 bugs:
16587                                         // 1) [non-Android] Safari skips rendering changes to "top" and "left" that are made on the same frame/render as a transform update.
16588                                         // 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.
16589                                         // 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.
16590                                         //Note: we allow the user to override the auto-setting by defining WebkitBackfaceVisibility in the vars of the tween.
16591                                         if (_isSafariLT6) {
16592                                                 this._addLazySet(style, "WebkitBackfaceVisibility", this._vars.WebkitBackfaceVisibility || (threeD ? "visible" : "hidden"));
16593                                         }
16594                                 }
16595                                 pt2 = pt;
16596                                 while (pt2 && pt2._next) {
16597                                         pt2 = pt2._next;
16598                                 }
16599                                 tpt = new CSSPropTween(target, "transform", 0, 0, null, 2);
16600                                 this._linkCSSP(tpt, null, pt2);
16601                                 tpt.setRatio = (threeD && _supports3D) ? _set3DTransformRatio : _transformProp ? _set2DTransformRatio : _setIETransformRatio;
16602                                 tpt.data = this._transform || _getTransform(target, _cs, true);
16603                                 _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.
16604                         }
16605
16606                         if (_hasPriority) {
16607                                 //reorders the linked list in order of pr (priority)
16608                                 while (pt) {
16609                                         next = pt._next;
16610                                         pt2 = first;
16611                                         while (pt2 && pt2.pr > pt.pr) {
16612                                                 pt2 = pt2._next;
16613                                         }
16614                                         if ((pt._prev = pt2 ? pt2._prev : last)) {
16615                                                 pt._prev._next = pt;
16616                                         } else {
16617                                                 first = pt;
16618                                         }
16619                                         if ((pt._next = pt2)) {
16620                                                 pt2._prev = pt;
16621                                         } else {
16622                                                 last = pt;
16623                                         }
16624                                         pt = next;
16625                                 }
16626                                 this._firstPT = first;
16627                         }
16628                         return true;
16629                 };
16630
16631
16632                 p.parse = function(target, vars, pt, plugin) {
16633                         var style = target.style,
16634                                 p, sp, bn, en, bs, es, bsfx, esfx, isStr, rel;
16635                         for (p in vars) {
16636                                 es = vars[p]; //ending value string
16637                                 sp = _specialProps[p]; //SpecialProp lookup.
16638                                 if (sp) {
16639                                         pt = sp.parse(target, es, p, this, pt, plugin, vars);
16640
16641                                 } else {
16642                                         bs = _getStyle(target, p, _cs) + "";
16643                                         isStr = (typeof(es) === "string");
16644                                         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:
16645                                                 if (!isStr) {
16646                                                         es = _parseColor(es);
16647                                                         es = ((es.length > 3) ? "rgba(" : "rgb(") + es.join(",") + ")";
16648                                                 }
16649                                                 pt = _parseComplex(style, p, bs, es, true, "transparent", pt, 0, plugin);
16650
16651                                         } else if (isStr && (es.indexOf(" ") !== -1 || es.indexOf(",") !== -1)) {
16652                                                 pt = _parseComplex(style, p, bs, es, true, null, pt, 0, plugin);
16653
16654                                         } else {
16655                                                 bn = parseFloat(bs);
16656                                                 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.
16657
16658                                                 if (bs === "" || bs === "auto") {
16659                                                         if (p === "width" || p === "height") {
16660                                                                 bn = _getDimension(target, p, _cs);
16661                                                                 bsfx = "px";
16662                                                         } else if (p === "left" || p === "top") {
16663                                                                 bn = _calculateOffset(target, p, _cs);
16664                                                                 bsfx = "px";
16665                                                         } else {
16666                                                                 bn = (p !== "opacity") ? 0 : 1;
16667                                                                 bsfx = "";
16668                                                         }
16669                                                 }
16670
16671                                                 rel = (isStr && es.charAt(1) === "=");
16672                                                 if (rel) {
16673                                                         en = parseInt(es.charAt(0) + "1", 10);
16674                                                         es = es.substr(2);
16675                                                         en *= parseFloat(es);
16676                                                         esfx = es.replace(_suffixExp, "");
16677                                                 } else {
16678                                                         en = parseFloat(es);
16679                                                         esfx = isStr ? es.substr((en + "").length) || "" : "";
16680                                                 }
16681
16682                                                 if (esfx === "") {
16683                                                         esfx = (p in _suffixMap) ? _suffixMap[p] : bsfx; //populate the end suffix, prioritizing the map, then if none is found, use the beginning suffix.
16684                                                 }
16685
16686                                                 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.
16687
16688                                                 //if the beginning/ending suffixes don't match, normalize them...
16689                                                 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!
16690                                                         bn = _convertToPixels(target, p, bn, bsfx);
16691                                                         if (esfx === "%") {
16692                                                                 bn /= _convertToPixels(target, p, 100, "%") / 100;
16693                                                                 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.
16694                                                                         bs = bn + "%";
16695                                                                 }
16696
16697                                                         } else if (esfx === "em") {
16698                                                                 bn /= _convertToPixels(target, p, 1, "em");
16699
16700                                                         //otherwise convert to pixels.
16701                                                         } else if (esfx !== "px") {
16702                                                                 en = _convertToPixels(target, p, en, esfx);
16703                                                                 esfx = "px"; //we don't use bsfx after this, so we don't need to set it to px too.
16704                                                         }
16705                                                         if (rel) if (en || en === 0) {
16706                                                                 es = (en + bn) + esfx; //the changes we made affect relative calculations, so adjust the end value here.
16707                                                         }
16708                                                 }
16709
16710                                                 if (rel) {
16711                                                         en += bn;
16712                                                 }
16713
16714                                                 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.
16715                                                         pt = new CSSPropTween(style, p, bn, en - bn, pt, 0, p, (_autoRound !== false && (esfx === "px" || p === "zIndex")), 0, bs, es);
16716                                                         pt.xs0 = esfx;
16717                                                         //DEBUG: _log("tween "+p+" from "+pt.b+" ("+bn+esfx+") to "+pt.e+" with suffix: "+pt.xs0);
16718                                                 } else if (style[p] === undefined || !es && (es + "" === "NaN" || es == null)) {
16719                                                         _log("invalid " + p + " tween value: " + vars[p]);
16720                                                 } else {
16721                                                         pt = new CSSPropTween(style, p, en || bn || 0, 0, pt, -1, p, false, 0, bs, es);
16722                                                         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.
16723                                                         //DEBUG: _log("non-tweening value "+p+": "+pt.xs0);
16724                                                 }
16725                                         }
16726                                 }
16727                                 if (plugin) if (pt && !pt.plugin) {
16728                                         pt.plugin = plugin;
16729                                 }
16730                         }
16731                         return pt;
16732                 };
16733
16734
16735                 //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.
16736                 p.setRatio = function(v) {
16737                         var pt = this._firstPT,
16738                                 min = 0.000001,
16739                                 val, str, i;
16740
16741                         //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).
16742                         if (v === 1 && (this._tween._time === this._tween._duration || this._tween._time === 0)) {
16743                                 while (pt) {
16744                                         if (pt.type !== 2) {
16745                                                 pt.t[pt.p] = pt.e;
16746                                         } else {
16747                                                 pt.setRatio(v);
16748                                         }
16749                                         pt = pt._next;
16750                                 }
16751
16752                         } else if (v || !(this._tween._time === this._tween._duration || this._tween._time === 0) || this._tween._rawPrevTime === -0.000001) {
16753                                 while (pt) {
16754                                         val = pt.c * v + pt.s;
16755                                         if (pt.r) {
16756                                                 val = Math.round(val);
16757                                         } else if (val < min) if (val > -min) {
16758                                                 val = 0;
16759                                         }
16760                                         if (!pt.type) {
16761                                                 pt.t[pt.p] = val + pt.xs0;
16762                                         } else if (pt.type === 1) { //complex value (one that typically has multiple numbers inside a string, like "rect(5px,10px,20px,25px)"
16763                                                 i = pt.l;
16764                                                 if (i === 2) {
16765                                                         pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2;
16766                                                 } else if (i === 3) {
16767                                                         pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3;
16768                                                 } else if (i === 4) {
16769                                                         pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3 + pt.xn3 + pt.xs4;
16770                                                 } else if (i === 5) {
16771                                                         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;
16772                                                 } else {
16773                                                         str = pt.xs0 + val + pt.xs1;
16774                                                         for (i = 1; i < pt.l; i++) {
16775                                                                 str += pt["xn"+i] + pt["xs"+(i+1)];
16776                                                         }
16777                                                         pt.t[pt.p] = str;
16778                                                 }
16779
16780                                         } else if (pt.type === -1) { //non-tweening value
16781                                                 pt.t[pt.p] = pt.xs0;
16782
16783                                         } else if (pt.setRatio) { //custom setRatio() for things like SpecialProps, external plugins, etc.
16784                                                 pt.setRatio(v);
16785                                         }
16786                                         pt = pt._next;
16787                                 }
16788
16789                         //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).
16790                         } else {
16791                                 while (pt) {
16792                                         if (pt.type !== 2) {
16793                                                 pt.t[pt.p] = pt.b;
16794                                         } else {
16795                                                 pt.setRatio(v);
16796                                         }
16797                                         pt = pt._next;
16798                                 }
16799                         }
16800                 };
16801
16802                 /**
16803                  * @private
16804                  * Forces rendering of the target's transforms (rotation, scale, etc.) whenever the CSSPlugin's setRatio() is called.
16805                  * Basically, this tells the CSSPlugin to create a CSSPropTween (type 2) after instantiation that runs last in the linked
16806                  * list and calls the appropriate (3D or 2D) rendering function. We separate this into its own method so that we can call
16807                  * it from other plugins like BezierPlugin if, for example, it needs to apply an autoRotation and this CSSPlugin
16808                  * doesn't have any transform-related properties of its own. You can call this method as many times as you
16809                  * want and it won't create duplicate CSSPropTweens.
16810                  *
16811                  * @param {boolean} threeD if true, it should apply 3D tweens (otherwise, just 2D ones are fine and typically faster)
16812                  */
16813                 p._enableTransforms = function(threeD) {
16814                         this._transformType = (threeD || this._transformType === 3) ? 3 : 2;
16815                         this._transform = this._transform || _getTransform(this._target, _cs, true); //ensures that the element has a _gsTransform property with the appropriate values.
16816                 };
16817
16818                 var lazySet = function(v) {
16819                         this.t[this.p] = this.e;
16820                         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.
16821                 };
16822                 /** @private Gives us a way to set a value on the first render (and only the first render). **/
16823                 p._addLazySet = function(t, p, v) {
16824                         var pt = this._firstPT = new CSSPropTween(t, p, 0, 0, this._firstPT, 2);
16825                         pt.e = v;
16826                         pt.setRatio = lazySet;
16827                         pt.data = this;
16828                 };
16829
16830                 /** @private **/
16831                 p._linkCSSP = function(pt, next, prev, remove) {
16832                         if (pt) {
16833                                 if (next) {
16834                                         next._prev = pt;
16835                                 }
16836                                 if (pt._next) {
16837                                         pt._next._prev = pt._prev;
16838                                 }
16839                                 if (pt._prev) {
16840                                         pt._prev._next = pt._next;
16841                                 } else if (this._firstPT === pt) {
16842                                         this._firstPT = pt._next;
16843                                         remove = true; //just to prevent resetting this._firstPT 5 lines down in case pt._next is null. (optimized for speed)
16844                                 }
16845                                 if (prev) {
16846                                         prev._next = pt;
16847                                 } else if (!remove && this._firstPT === null) {
16848                                         this._firstPT = pt;
16849                                 }
16850                                 pt._next = next;
16851                                 pt._prev = prev;
16852                         }
16853                         return pt;
16854                 };
16855
16856                 //we need to make sure that if alpha or autoAlpha is killed, opacity is too. And autoAlpha affects the "visibility" property.
16857                 p._kill = function(lookup) {
16858                         var copy = lookup,
16859                                 pt, p, xfirst;
16860                         if (lookup.autoAlpha || lookup.alpha) {
16861                                 copy = {};
16862                                 for (p in lookup) { //copy the lookup so that we're not changing the original which may be passed elsewhere.
16863                                         copy[p] = lookup[p];
16864                                 }
16865                                 copy.opacity = 1;
16866                                 if (copy.autoAlpha) {
16867                                         copy.visibility = 1;
16868                                 }
16869                         }
16870                         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".
16871                                 xfirst = pt.xfirst;
16872                                 if (xfirst && xfirst._prev) {
16873                                         this._linkCSSP(xfirst._prev, pt._next, xfirst._prev._prev); //break off the prev
16874                                 } else if (xfirst === this._firstPT) {
16875                                         this._firstPT = pt._next;
16876                                 }
16877                                 if (pt._next) {
16878                                         this._linkCSSP(pt._next, pt._next._next, xfirst._prev);
16879                                 }
16880                                 this._classNamePT = null;
16881                         }
16882                         return TweenPlugin.prototype._kill.call(this, copy);
16883                 };
16884
16885
16886
16887                 //used by cascadeTo() for gathering all the style properties of each child element into an array for comparison.
16888                 var _getChildStyles = function(e, props, targets) {
16889                                 var children, i, child, type;
16890                                 if (e.slice) {
16891                                         i = e.length;
16892                                         while (--i > -1) {
16893                                                 _getChildStyles(e[i], props, targets);
16894                                         }
16895                                         return;
16896                                 }
16897                                 children = e.childNodes;
16898                                 i = children.length;
16899                                 while (--i > -1) {
16900                                         child = children[i];
16901                                         type = child.type;
16902                                         if (child.style) {
16903                                                 props.push(_getAllStyles(child));
16904                                                 if (targets) {
16905                                                         targets.push(child);
16906                                                 }
16907                                         }
16908                                         if ((type === 1 || type === 9 || type === 11) && child.childNodes.length) {
16909                                                 _getChildStyles(child, props, targets);
16910                                         }
16911                                 }
16912                         };
16913
16914                 /**
16915                  * Typically only useful for className tweens that may affect child elements, this method creates a TweenLite
16916                  * and then compares the style properties of all the target's child elements at the tween's start and end, and
16917                  * if any are different, it also creates tweens for those and returns an array containing ALL of the resulting
16918                  * tweens (so that you can easily add() them to a TimelineLite, for example). The reason this functionality is
16919                  * wrapped into a separate static method of CSSPlugin instead of being integrated into all regular className tweens
16920                  * is because it creates entirely new tweens that may have completely different targets than the original tween,
16921                  * so if they were all lumped into the original tween instance, it would be inconsistent with the rest of the API
16922                  * and it would create other problems. For example:
16923                  *  - 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)
16924                  *  - 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.
16925                  *  - 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.
16926                  *
16927                  * @param {Object} target object to be tweened
16928                  * @param {number} Duration in seconds (or frames for frames-based tweens)
16929                  * @param {Object} Object containing the end values, like {className:"newClass", ease:Linear.easeNone}
16930                  * @return {Array} An array of TweenLite instances
16931                  */
16932                 CSSPlugin.cascadeTo = function(target, duration, vars) {
16933                         var tween = TweenLite.to(target, duration, vars),
16934                                 results = [tween],
16935                                 b = [],
16936                                 e = [],
16937                                 targets = [],
16938                                 _reservedProps = TweenLite._internals.reservedProps,
16939                                 i, difs, p;
16940                         target = tween._targets || tween.target;
16941                         _getChildStyles(target, b, targets);
16942                         tween.render(duration, true);
16943                         _getChildStyles(target, e);
16944                         tween.render(0, true);
16945                         tween._enabled(true);
16946                         i = targets.length;
16947                         while (--i > -1) {
16948                                 difs = _cssDif(targets[i], b[i], e[i]);
16949                                 if (difs.firstMPT) {
16950                                         difs = difs.difs;
16951                                         for (p in vars) {
16952                                                 if (_reservedProps[p]) {
16953                                                         difs[p] = vars[p];
16954                                                 }
16955                                         }
16956                                         results.push( TweenLite.to(targets[i], duration, difs) );
16957                                 }
16958                         }
16959                         return results;
16960                 };
16961
16962                 TweenPlugin.activate([CSSPlugin]);
16963                 return CSSPlugin;
16964
16965         }, true);
16966
16967         
16968         
16969         
16970         
16971         
16972         
16973         
16974         
16975         
16976         
16977 /*
16978  * ----------------------------------------------------------------
16979  * RoundPropsPlugin
16980  * ----------------------------------------------------------------
16981  */
16982         (function() {
16983
16984                 var RoundPropsPlugin = window._gsDefine.plugin({
16985                                 propName: "roundProps",
16986                                 priority: -1,
16987                                 API: 2,
16988
16989                                 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
16990                                 init: function(target, value, tween) {
16991                                         this._tween = tween;
16992                                         return true;
16993                                 }
16994
16995                         }),
16996                         p = RoundPropsPlugin.prototype;
16997
16998                 p._onInitAllProps = function() {
16999                         var tween = this._tween,
17000                                 rp = (tween.vars.roundProps instanceof Array) ? tween.vars.roundProps : tween.vars.roundProps.split(","),
17001                                 i = rp.length,
17002                                 lookup = {},
17003                                 rpt = tween._propLookup.roundProps,
17004                                 prop, pt, next;
17005                         while (--i > -1) {
17006                                 lookup[rp[i]] = 1;
17007                         }
17008                         i = rp.length;
17009                         while (--i > -1) {
17010                                 prop = rp[i];
17011                                 pt = tween._firstPT;
17012                                 while (pt) {
17013                                         next = pt._next; //record here, because it may get removed
17014                                         if (pt.pg) {
17015                                                 pt.t._roundProps(lookup, true);
17016                                         } else if (pt.n === prop) {
17017                                                 this._add(pt.t, prop, pt.s, pt.c);
17018                                                 //remove from linked list
17019                                                 if (next) {
17020                                                         next._prev = pt._prev;
17021                                                 }
17022                                                 if (pt._prev) {
17023                                                         pt._prev._next = next;
17024                                                 } else if (tween._firstPT === pt) {
17025                                                         tween._firstPT = next;
17026                                                 }
17027                                                 pt._next = pt._prev = null;
17028                                                 tween._propLookup[prop] = rpt;
17029                                         }
17030                                         pt = next;
17031                                 }
17032                         }
17033                         return false;
17034                 };
17035
17036                 p._add = function(target, p, s, c) {
17037                         this._addTween(target, p, s, s + c, p, true);
17038                         this._overwriteProps.push(p);
17039                 };
17040
17041         }());
17042
17043
17044
17045
17046
17047
17048
17049
17050
17051
17052 /*
17053  * ----------------------------------------------------------------
17054  * AttrPlugin
17055  * ----------------------------------------------------------------
17056  */
17057         window._gsDefine.plugin({
17058                 propName: "attr",
17059                 API: 2,
17060                 version: "0.3.2",
17061
17062                 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
17063                 init: function(target, value, tween) {
17064                         var p, start, end;
17065                         if (typeof(target.setAttribute) !== "function") {
17066                                 return false;
17067                         }
17068                         this._target = target;
17069                         this._proxy = {};
17070                         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.
17071                         this._end = {};
17072                         for (p in value) {
17073                                 this._start[p] = this._proxy[p] = start = target.getAttribute(p);
17074                                 end = this._addTween(this._proxy, p, parseFloat(start), value[p], p);
17075                                 this._end[p] = end ? end.s + end.c : value[p];
17076                                 this._overwriteProps.push(p);
17077                         }
17078                         return true;
17079                 },
17080
17081                 //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.)
17082                 set: function(ratio) {
17083                         this._super.setRatio.call(this, ratio);
17084                         var props = this._overwriteProps,
17085                                 i = props.length,
17086                                 lookup = (ratio === 1) ? this._end : ratio ? this._proxy : this._start,
17087                                 p;
17088                         while (--i > -1) {
17089                                 p = props[i];
17090                                 this._target.setAttribute(p, lookup[p] + "");
17091                         }
17092                 }
17093
17094         });
17095
17096
17097
17098
17099
17100
17101
17102
17103
17104
17105 /*
17106  * ----------------------------------------------------------------
17107  * DirectionalRotationPlugin
17108  * ----------------------------------------------------------------
17109  */
17110         window._gsDefine.plugin({
17111                 propName: "directionalRotation",
17112                 API: 2,
17113                 version: "0.2.0",
17114
17115                 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
17116                 init: function(target, value, tween) {
17117                         if (typeof(value) !== "object") {
17118                                 value = {rotation:value};
17119                         }
17120                         this.finals = {};
17121                         var cap = (value.useRadians === true) ? Math.PI * 2 : 360,
17122                                 min = 0.000001,
17123                                 p, v, start, end, dif, split;
17124                         for (p in value) {
17125                                 if (p !== "useRadians") {
17126                                         split = (value[p] + "").split("_");
17127                                         v = split[0];
17128                                         start = parseFloat( (typeof(target[p]) !== "function") ? target[p] : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]() );
17129                                         end = this.finals[p] = (typeof(v) === "string" && v.charAt(1) === "=") ? start + parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) : Number(v) || 0;
17130                                         dif = end - start;
17131                                         if (split.length) {
17132                                                 v = split.join("_");
17133                                                 if (v.indexOf("short") !== -1) {
17134                                                         dif = dif % cap;
17135                                                         if (dif !== dif % (cap / 2)) {
17136                                                                 dif = (dif < 0) ? dif + cap : dif - cap;
17137                                                         }
17138                                                 }
17139                                                 if (v.indexOf("_cw") !== -1 && dif < 0) {
17140                                                         dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
17141                                                 } else if (v.indexOf("ccw") !== -1 && dif > 0) {
17142                                                         dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
17143                                                 }
17144                                         }
17145                                         if (dif > min || dif < -min) {
17146                                                 this._addTween(target, p, start, start + dif, p);
17147                                                 this._overwriteProps.push(p);
17148                                         }
17149                                 }
17150                         }
17151                         return true;
17152                 },
17153
17154                 //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.)
17155                 set: function(ratio) {
17156                         var pt;
17157                         if (ratio !== 1) {
17158                                 this._super.setRatio.call(this, ratio);
17159                         } else {
17160                                 pt = this._firstPT;
17161                                 while (pt) {
17162                                         if (pt.f) {
17163                                                 pt.t[pt.p](this.finals[pt.p]);
17164                                         } else {
17165                                                 pt.t[pt.p] = this.finals[pt.p];
17166                                         }
17167                                         pt = pt._next;
17168                                 }
17169                         }
17170                 }
17171
17172         })._autoCSS = true;
17173
17174
17175
17176
17177
17178
17179
17180         
17181         
17182         
17183         
17184 /*
17185  * ----------------------------------------------------------------
17186  * EasePack
17187  * ----------------------------------------------------------------
17188  */
17189         window._gsDefine("easing.Back", ["easing.Ease"], function(Ease) {
17190                 
17191                 var w = (window.GreenSockGlobals || window),
17192                         gs = w.com.greensock,
17193                         _2PI = Math.PI * 2,
17194                         _HALF_PI = Math.PI / 2,
17195                         _class = gs._class,
17196                         _create = function(n, f) {
17197                                 var C = _class("easing." + n, function(){}, true),
17198                                         p = C.prototype = new Ease();
17199                                 p.constructor = C;
17200                                 p.getRatio = f;
17201                                 return C;
17202                         },
17203                         _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.
17204                         _wrap = function(name, EaseOut, EaseIn, EaseInOut, aliases) {
17205                                 var C = _class("easing."+name, {
17206                                         easeOut:new EaseOut(),
17207                                         easeIn:new EaseIn(),
17208                                         easeInOut:new EaseInOut()
17209                                 }, true);
17210                                 _easeReg(C, name);
17211                                 return C;
17212                         },
17213                         EasePoint = function(time, value, next) {
17214                                 this.t = time;
17215                                 this.v = value;
17216                                 if (next) {
17217                                         this.next = next;
17218                                         next.prev = this;
17219                                         this.c = next.v - value;
17220                                         this.gap = next.t - time;
17221                                 }
17222                         },
17223
17224                         //Back
17225                         _createBack = function(n, f) {
17226                                 var C = _class("easing." + n, function(overshoot) {
17227                                                 this._p1 = (overshoot || overshoot === 0) ? overshoot : 1.70158;
17228                                                 this._p2 = this._p1 * 1.525;
17229                                         }, true),
17230                                         p = C.prototype = new Ease();
17231                                 p.constructor = C;
17232                                 p.getRatio = f;
17233                                 p.config = function(overshoot) {
17234                                         return new C(overshoot);
17235                                 };
17236                                 return C;
17237                         },
17238
17239                         Back = _wrap("Back",
17240                                 _createBack("BackOut", function(p) {
17241                                         return ((p = p - 1) * p * ((this._p1 + 1) * p + this._p1) + 1);
17242                                 }),
17243                                 _createBack("BackIn", function(p) {
17244                                         return p * p * ((this._p1 + 1) * p - this._p1);
17245                                 }),
17246                                 _createBack("BackInOut", function(p) {
17247                                         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);
17248                                 })
17249                         ),
17250
17251
17252                         //SlowMo
17253                         SlowMo = _class("easing.SlowMo", function(linearRatio, power, yoyoMode) {
17254                                 power = (power || power === 0) ? power : 0.7;
17255                                 if (linearRatio == null) {
17256                                         linearRatio = 0.7;
17257                                 } else if (linearRatio > 1) {
17258                                         linearRatio = 1;
17259                                 }
17260                                 this._p = (linearRatio !== 1) ? power : 0;
17261                                 this._p1 = (1 - linearRatio) / 2;
17262                                 this._p2 = linearRatio;
17263                                 this._p3 = this._p1 + this._p2;
17264                                 this._calcEnd = (yoyoMode === true);
17265                         }, true),
17266                         p = SlowMo.prototype = new Ease(),
17267                         SteppedEase, RoughEase, _createElastic;
17268
17269                 p.constructor = SlowMo;
17270                 p.getRatio = function(p) {
17271                         var r = p + (0.5 - p) * this._p;
17272                         if (p < this._p1) {
17273                                 return this._calcEnd ? 1 - ((p = 1 - (p / this._p1)) * p) : r - ((p = 1 - (p / this._p1)) * p * p * p * r);
17274                         } else if (p > this._p3) {
17275                                 return this._calcEnd ? 1 - (p = (p - this._p3) / this._p1) * p : r + ((p - r) * (p = (p - this._p3) / this._p1) * p * p * p);
17276                         }
17277                         return this._calcEnd ? 1 : r;
17278                 };
17279                 SlowMo.ease = new SlowMo(0.7, 0.7);
17280
17281                 p.config = SlowMo.config = function(linearRatio, power, yoyoMode) {
17282                         return new SlowMo(linearRatio, power, yoyoMode);
17283                 };
17284
17285
17286                 //SteppedEase
17287                 SteppedEase = _class("easing.SteppedEase", function(steps) {
17288                                 steps = steps || 1;
17289                                 this._p1 = 1 / steps;
17290                                 this._p2 = steps + 1;
17291                         }, true);
17292                 p = SteppedEase.prototype = new Ease();
17293                 p.constructor = SteppedEase;
17294                 p.getRatio = function(p) {
17295                         if (p < 0) {
17296                                 p = 0;
17297                         } else if (p >= 1) {
17298                                 p = 0.999999999;
17299                         }
17300                         return ((this._p2 * p) >> 0) * this._p1;
17301                 };
17302                 p.config = SteppedEase.config = function(steps) {
17303                         return new SteppedEase(steps);
17304                 };
17305
17306
17307                 //RoughEase
17308                 RoughEase = _class("easing.RoughEase", function(vars) {
17309                         vars = vars || {};
17310                         var taper = vars.taper || "none",
17311                                 a = [],
17312                                 cnt = 0,
17313                                 points = (vars.points || 20) | 0,
17314                                 i = points,
17315                                 randomize = (vars.randomize !== false),
17316                                 clamp = (vars.clamp === true),
17317                                 template = (vars.template instanceof Ease) ? vars.template : null,
17318                                 strength = (typeof(vars.strength) === "number") ? vars.strength * 0.4 : 0.4,
17319                                 x, y, bump, invX, obj, pnt;
17320                         while (--i > -1) {
17321                                 x = randomize ? Math.random() : (1 / points) * i;
17322                                 y = template ? template.getRatio(x) : x;
17323                                 if (taper === "none") {
17324                                         bump = strength;
17325                                 } else if (taper === "out") {
17326                                         invX = 1 - x;
17327                                         bump = invX * invX * strength;
17328                                 } else if (taper === "in") {
17329                                         bump = x * x * strength;
17330                                 } else if (x < 0.5) {  //"both" (start)
17331                                         invX = x * 2;
17332                                         bump = invX * invX * 0.5 * strength;
17333                                 } else {                                //"both" (end)
17334                                         invX = (1 - x) * 2;
17335                                         bump = invX * invX * 0.5 * strength;
17336                                 }
17337                                 if (randomize) {
17338                                         y += (Math.random() * bump) - (bump * 0.5);
17339                                 } else if (i % 2) {
17340                                         y += bump * 0.5;
17341                                 } else {
17342                                         y -= bump * 0.5;
17343                                 }
17344                                 if (clamp) {
17345                                         if (y > 1) {
17346                                                 y = 1;
17347                                         } else if (y < 0) {
17348                                                 y = 0;
17349                                         }
17350                                 }
17351                                 a[cnt++] = {x:x, y:y};
17352                         }
17353                         a.sort(function(a, b) {
17354                                 return a.x - b.x;
17355                         });
17356
17357                         pnt = new EasePoint(1, 1, null);
17358                         i = points;
17359                         while (--i > -1) {
17360                                 obj = a[i];
17361                                 pnt = new EasePoint(obj.x, obj.y, pnt);
17362                         }
17363
17364                         this._prev = new EasePoint(0, 0, (pnt.t !== 0) ? pnt : pnt.next);
17365                 }, true);
17366                 p = RoughEase.prototype = new Ease();
17367                 p.constructor = RoughEase;
17368                 p.getRatio = function(p) {
17369                         var pnt = this._prev;
17370                         if (p > pnt.t) {
17371                                 while (pnt.next && p >= pnt.t) {
17372                                         pnt = pnt.next;
17373                                 }
17374                                 pnt = pnt.prev;
17375                         } else {
17376                                 while (pnt.prev && p <= pnt.t) {
17377                                         pnt = pnt.prev;
17378                                 }
17379                         }
17380                         this._prev = pnt;
17381                         return (pnt.v + ((p - pnt.t) / pnt.gap) * pnt.c);
17382                 };
17383                 p.config = function(vars) {
17384                         return new RoughEase(vars);
17385                 };
17386                 RoughEase.ease = new RoughEase();
17387
17388
17389                 //Bounce
17390                 _wrap("Bounce",
17391                         _create("BounceOut", function(p) {
17392                                 if (p < 1 / 2.75) {
17393                                         return 7.5625 * p * p;
17394                                 } else if (p < 2 / 2.75) {
17395                                         return 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;
17396                                 } else if (p < 2.5 / 2.75) {
17397                                         return 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;
17398                                 }
17399                                 return 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;
17400                         }),
17401                         _create("BounceIn", function(p) {
17402                                 if ((p = 1 - p) < 1 / 2.75) {
17403                                         return 1 - (7.5625 * p * p);
17404                                 } else if (p < 2 / 2.75) {
17405                                         return 1 - (7.5625 * (p -= 1.5 / 2.75) * p + 0.75);
17406                                 } else if (p < 2.5 / 2.75) {
17407                                         return 1 - (7.5625 * (p -= 2.25 / 2.75) * p + 0.9375);
17408                                 }
17409                                 return 1 - (7.5625 * (p -= 2.625 / 2.75) * p + 0.984375);
17410                         }),
17411                         _create("BounceInOut", function(p) {
17412                                 var invert = (p < 0.5);
17413                                 if (invert) {
17414                                         p = 1 - (p * 2);
17415                                 } else {
17416                                         p = (p * 2) - 1;
17417                                 }
17418                                 if (p < 1 / 2.75) {
17419                                         p = 7.5625 * p * p;
17420                                 } else if (p < 2 / 2.75) {
17421                                         p = 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;
17422                                 } else if (p < 2.5 / 2.75) {
17423                                         p = 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;
17424                                 } else {
17425                                         p = 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;
17426                                 }
17427                                 return invert ? (1 - p) * 0.5 : p * 0.5 + 0.5;
17428                         })
17429                 );
17430
17431
17432                 //CIRC
17433                 _wrap("Circ",
17434                         _create("CircOut", function(p) {
17435                                 return Math.sqrt(1 - (p = p - 1) * p);
17436                         }),
17437                         _create("CircIn", function(p) {
17438                                 return -(Math.sqrt(1 - (p * p)) - 1);
17439                         }),
17440                         _create("CircInOut", function(p) {
17441                                 return ((p*=2) < 1) ? -0.5 * (Math.sqrt(1 - p * p) - 1) : 0.5 * (Math.sqrt(1 - (p -= 2) * p) + 1);
17442                         })
17443                 );
17444
17445
17446                 //Elastic
17447                 _createElastic = function(n, f, def) {
17448                         var C = _class("easing." + n, function(amplitude, period) {
17449                                         this._p1 = amplitude || 1;
17450                                         this._p2 = period || def;
17451                                         this._p3 = this._p2 / _2PI * (Math.asin(1 / this._p1) || 0);
17452                                 }, true),
17453                                 p = C.prototype = new Ease();
17454                         p.constructor = C;
17455                         p.getRatio = f;
17456                         p.config = function(amplitude, period) {
17457                                 return new C(amplitude, period);
17458                         };
17459                         return C;
17460                 };
17461                 _wrap("Elastic",
17462                         _createElastic("ElasticOut", function(p) {
17463                                 return this._p1 * Math.pow(2, -10 * p) * Math.sin( (p - this._p3) * _2PI / this._p2 ) + 1;
17464                         }, 0.3),
17465                         _createElastic("ElasticIn", function(p) {
17466                                 return -(this._p1 * Math.pow(2, 10 * (p -= 1)) * Math.sin( (p - this._p3) * _2PI / this._p2 ));
17467                         }, 0.3),
17468                         _createElastic("ElasticInOut", function(p) {
17469                                 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;
17470                         }, 0.45)
17471                 );
17472
17473
17474                 //Expo
17475                 _wrap("Expo",
17476                         _create("ExpoOut", function(p) {
17477                                 return 1 - Math.pow(2, -10 * p);
17478                         }),
17479                         _create("ExpoIn", function(p) {
17480                                 return Math.pow(2, 10 * (p - 1)) - 0.001;
17481                         }),
17482                         _create("ExpoInOut", function(p) {
17483                                 return ((p *= 2) < 1) ? 0.5 * Math.pow(2, 10 * (p - 1)) : 0.5 * (2 - Math.pow(2, -10 * (p - 1)));
17484                         })
17485                 );
17486
17487
17488                 //Sine
17489                 _wrap("Sine",
17490                         _create("SineOut", function(p) {
17491                                 return Math.sin(p * _HALF_PI);
17492                         }),
17493                         _create("SineIn", function(p) {
17494                                 return -Math.cos(p * _HALF_PI) + 1;
17495                         }),
17496                         _create("SineInOut", function(p) {
17497                                 return -0.5 * (Math.cos(Math.PI * p) - 1);
17498                         })
17499                 );
17500
17501                 _class("easing.EaseLookup", {
17502                                 find:function(s) {
17503                                         return Ease.map[s];
17504                                 }
17505                         }, true);
17506
17507                 //register the non-standard eases
17508                 _easeReg(w.SlowMo, "SlowMo", "ease,");
17509                 _easeReg(RoughEase, "RoughEase", "ease,");
17510                 _easeReg(SteppedEase, "SteppedEase", "ease,");
17511
17512                 return Back;
17513                 
17514         }, true);
17515
17516
17517 }); 
17518
17519
17520
17521
17522
17523
17524
17525
17526
17527
17528
17529 /*
17530  * ----------------------------------------------------------------
17531  * Base classes like TweenLite, SimpleTimeline, Ease, Ticker, etc.
17532  * ----------------------------------------------------------------
17533  */
17534 (function(window) {
17535
17536                 "use strict";
17537                 var _globals = window.GreenSockGlobals || window;
17538                 if (_globals.TweenLite) {
17539                         return; //in case the core set of classes is already loaded, don't instantiate twice.
17540                 }
17541                 var _namespace = function(ns) {
17542                                 var a = ns.split("."),
17543                                         p = _globals, i;
17544                                 for (i = 0; i < a.length; i++) {
17545                                         p[a[i]] = p = p[a[i]] || {};
17546                                 }
17547                                 return p;
17548                         },
17549                         gs = _namespace("com.greensock"),
17550                         _tinyNum = 0.0000000001,
17551                         _slice = [].slice,
17552                         _emptyFunc = function() {},
17553                         _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)
17554                                 var toString = Object.prototype.toString,
17555                                         array = toString.call([]);
17556                                 return function(obj) {
17557                                         return obj != null && (obj instanceof Array || (typeof(obj) === "object" && !!obj.push && toString.call(obj) === array));
17558                                 };
17559                         }()),
17560                         a, i, p, _ticker, _tickerActive,
17561                         _defLookup = {},
17562
17563                         /**
17564                          * @constructor
17565                          * Defines a GreenSock class, optionally with an array of dependencies that must be instantiated first and passed into the definition.
17566                          * This allows users to load GreenSock JS files in any order even if they have interdependencies (like CSSPlugin extends TweenPlugin which is
17567                          * inside TweenLite.js, but if CSSPlugin is loaded first, it should wait to run its code until TweenLite.js loads and instantiates TweenPlugin
17568                          * and then pass TweenPlugin to CSSPlugin's definition). This is all done automatically and internally.
17569                          *
17570                          * Every definition will be added to a "com.greensock" global object (typically window, but if a window.GreenSockGlobals object is found,
17571                          * 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,
17572                          * it is ALSO referenced at window.TweenLite. However some classes aren't considered global, like the base com.greensock.core.Animation class, so
17573                          * those will only be at the package like window.com.greensock.core.Animation. Again, if you define a GreenSockGlobals object on the window, everything
17574                          * gets tucked neatly inside there instead of on the window directly. This allows you to do advanced things like load multiple versions of GreenSock
17575                          * 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
17576                          * sandbox the banner one like:
17577                          *
17578                          * <script>
17579                          *     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.
17580                          * </script>
17581                          * <script src="js/greensock/v1.7/TweenMax.js"></script>
17582                          * <script>
17583                          *     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(...)
17584                          * </script>
17585                          * <script src="js/greensock/v1.6/TweenMax.js"></script>
17586                          * <script>
17587                          *     gs.TweenLite.to(...); //would use v1.7
17588                          *     TweenLite.to(...); //would use v1.6
17589                          * </script>
17590                          *
17591                          * @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".
17592                          * @param {!Array.<string>} dependencies An array of dependencies (described as their namespaces minus "com.greensock." prefix). For example ["TweenLite","plugins.TweenPlugin","core.Animation"]
17593                          * @param {!function():Object} func The function that should be called and passed the resolved dependencies which will return the actual class for this definition.
17594                          * @param {boolean=} global If true, the class will be added to the global scope (typically window unless you define a window.GreenSockGlobals object)
17595                          */
17596                         Definition = function(ns, dependencies, func, global) {
17597                                 this.sc = (_defLookup[ns]) ? _defLookup[ns].sc : []; //subclasses
17598                                 _defLookup[ns] = this;
17599                                 this.gsClass = null;
17600                                 this.func = func;
17601                                 var _classes = [];
17602                                 this.check = function(init) {
17603                                         var i = dependencies.length,
17604                                                 missing = i,
17605                                                 cur, a, n, cl;
17606                                         while (--i > -1) {
17607                                                 if ((cur = _defLookup[dependencies[i]] || new Definition(dependencies[i], [])).gsClass) {
17608                                                         _classes[i] = cur.gsClass;
17609                                                         missing--;
17610                                                 } else if (init) {
17611                                                         cur.sc.push(this);
17612                                                 }
17613                                         }
17614                                         if (missing === 0 && func) {
17615                                                 a = ("com.greensock." + ns).split(".");
17616                                                 n = a.pop();
17617                                                 cl = _namespace(a.join("."))[n] = this.gsClass = func.apply(func, _classes);
17618
17619                                                 //exports to multiple environments
17620                                                 if (global) {
17621                                                         _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.)
17622                                                         if (typeof(define) === "function" && define.amd){ //AMD
17623                                                                 define((window.GreenSockAMDPath ? window.GreenSockAMDPath + "/" : "") + ns.split(".").join("/"), [], function() { return cl; });
17624                                                         } else if (typeof(module) !== "undefined" && module.exports){ //node
17625                                                                 module.exports = cl;
17626                                                         }
17627                                                 }
17628                                                 for (i = 0; i < this.sc.length; i++) {
17629                                                         this.sc[i].check();
17630                                                 }
17631                                         }
17632                                 };
17633                                 this.check(true);
17634                         },
17635
17636                         //used to create Definition instances (which basically registers a class that has dependencies).
17637                         _gsDefine = window._gsDefine = function(ns, dependencies, func, global) {
17638                                 return new Definition(ns, dependencies, func, global);
17639                         },
17640
17641                         //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).
17642                         _class = gs._class = function(ns, func, global) {
17643                                 func = func || function() {};
17644                                 _gsDefine(ns, [], function(){ return func; }, global);
17645                                 return func;
17646                         };
17647
17648                 _gsDefine.globals = _globals;
17649
17650
17651
17652 /*
17653  * ----------------------------------------------------------------
17654  * Ease
17655  * ----------------------------------------------------------------
17656  */
17657                 var _baseParams = [0, 0, 1, 1],
17658                         _blankArray = [],
17659                         Ease = _class("easing.Ease", function(func, extraParams, type, power) {
17660                                 this._func = func;
17661                                 this._type = type || 0;
17662                                 this._power = power || 0;
17663                                 this._params = extraParams ? _baseParams.concat(extraParams) : _baseParams;
17664                         }, true),
17665                         _easeMap = Ease.map = {},
17666                         _easeReg = Ease.register = function(ease, names, types, create) {
17667                                 var na = names.split(","),
17668                                         i = na.length,
17669                                         ta = (types || "easeIn,easeOut,easeInOut").split(","),
17670                                         e, name, j, type;
17671                                 while (--i > -1) {
17672                                         name = na[i];
17673                                         e = create ? _class("easing."+name, null, true) : gs.easing[name] || {};
17674                                         j = ta.length;
17675                                         while (--j > -1) {
17676                                                 type = ta[j];
17677                                                 _easeMap[name + "." + type] = _easeMap[type + name] = e[type] = ease.getRatio ? ease : ease[type] || new ease();
17678                                         }
17679                                 }
17680                         };
17681
17682                 p = Ease.prototype;
17683                 p._calcEnd = false;
17684                 p.getRatio = function(p) {
17685                         if (this._func) {
17686                                 this._params[0] = p;
17687                                 return this._func.apply(null, this._params);
17688                         }
17689                         var t = this._type,
17690                                 pw = this._power,
17691                                 r = (t === 1) ? 1 - p : (t === 2) ? p : (p < 0.5) ? p * 2 : (1 - p) * 2;
17692                         if (pw === 1) {
17693                                 r *= r;
17694                         } else if (pw === 2) {
17695                                 r *= r * r;
17696                         } else if (pw === 3) {
17697                                 r *= r * r * r;
17698                         } else if (pw === 4) {
17699                                 r *= r * r * r * r;
17700                         }
17701                         return (t === 1) ? 1 - r : (t === 2) ? r : (p < 0.5) ? r / 2 : 1 - (r / 2);
17702                 };
17703
17704                 //create all the standard eases like Linear, Quad, Cubic, Quart, Quint, Strong, Power0, Power1, Power2, Power3, and Power4 (each with easeIn, easeOut, and easeInOut)
17705                 a = ["Linear","Quad","Cubic","Quart","Quint,Strong"];
17706                 i = a.length;
17707                 while (--i > -1) {
17708                         p = a[i]+",Power"+i;
17709                         _easeReg(new Ease(null,null,1,i), p, "easeOut", true);
17710                         _easeReg(new Ease(null,null,2,i), p, "easeIn" + ((i === 0) ? ",easeNone" : ""));
17711                         _easeReg(new Ease(null,null,3,i), p, "easeInOut");
17712                 }
17713                 _easeMap.linear = gs.easing.Linear.easeIn;
17714                 _easeMap.swing = gs.easing.Quad.easeInOut; //for jQuery folks
17715
17716
17717 /*
17718  * ----------------------------------------------------------------
17719  * EventDispatcher
17720  * ----------------------------------------------------------------
17721  */
17722                 var EventDispatcher = _class("events.EventDispatcher", function(target) {
17723                         this._listeners = {};
17724                         this._eventTarget = target || this;
17725                 });
17726                 p = EventDispatcher.prototype;
17727
17728                 p.addEventListener = function(type, callback, scope, useParam, priority) {
17729                         priority = priority || 0;
17730                         var list = this._listeners[type],
17731                                 index = 0,
17732                                 listener, i;
17733                         if (list == null) {
17734                                 this._listeners[type] = list = [];
17735                         }
17736                         i = list.length;
17737                         while (--i > -1) {
17738                                 listener = list[i];
17739                                 if (listener.c === callback && listener.s === scope) {
17740                                         list.splice(i, 1);
17741                                 } else if (index === 0 && listener.pr < priority) {
17742                                         index = i + 1;
17743                                 }
17744                         }
17745                         list.splice(index, 0, {c:callback, s:scope, up:useParam, pr:priority});
17746                         if (this === _ticker && !_tickerActive) {
17747                                 _ticker.wake();
17748                         }
17749                 };
17750
17751                 p.removeEventListener = function(type, callback) {
17752                         var list = this._listeners[type], i;
17753                         if (list) {
17754                                 i = list.length;
17755                                 while (--i > -1) {
17756                                         if (list[i].c === callback) {
17757                                                 list.splice(i, 1);
17758                                                 return;
17759                                         }
17760                                 }
17761                         }
17762                 };
17763
17764                 p.dispatchEvent = function(type) {
17765                         var list = this._listeners[type],
17766                                 i, t, listener;
17767                         if (list) {
17768                                 i = list.length;
17769                                 t = this._eventTarget;
17770                                 while (--i > -1) {
17771                                         listener = list[i];
17772                                         if (listener.up) {
17773                                                 listener.c.call(listener.s || t, {type:type, target:t});
17774                                         } else {
17775                                                 listener.c.call(listener.s || t);
17776                                         }
17777                                 }
17778                         }
17779                 };
17780
17781
17782 /*
17783  * ----------------------------------------------------------------
17784  * Ticker
17785  * ----------------------------------------------------------------
17786  */
17787                 var _reqAnimFrame = window.requestAnimationFrame,
17788                         _cancelAnimFrame = window.cancelAnimationFrame,
17789                         _getTime = Date.now || function() {return new Date().getTime();},
17790                         _lastUpdate = _getTime();
17791
17792                 //now try to determine the requestAnimationFrame and cancelAnimationFrame functions and if none are found, we'll use a setTimeout()/clearTimeout() polyfill.
17793                 a = ["ms","moz","webkit","o"];
17794                 i = a.length;
17795                 while (--i > -1 && !_reqAnimFrame) {
17796                         _reqAnimFrame = window[a[i] + "RequestAnimationFrame"];
17797                         _cancelAnimFrame = window[a[i] + "CancelAnimationFrame"] || window[a[i] + "CancelRequestAnimationFrame"];
17798                 }
17799
17800                 _class("Ticker", function(fps, useRAF) {
17801                         var _self = this,
17802                                 _startTime = _getTime(),
17803                                 _useRAF = (useRAF !== false && _reqAnimFrame),
17804                                 _lagThreshold = 500,
17805                                 _adjustedLag = 33,
17806                                 _fps, _req, _id, _gap, _nextTime,
17807                                 _tick = function(manual) {
17808                                         var elapsed = _getTime() - _lastUpdate,
17809                                                 overlap, dispatch;
17810                                         if (elapsed > _lagThreshold) {
17811                                                 _startTime += elapsed - _adjustedLag;
17812                                         }
17813                                         _lastUpdate += elapsed;
17814                                         _self.time = (_lastUpdate - _startTime) / 1000;
17815                                         overlap = _self.time - _nextTime;
17816                                         if (!_fps || overlap > 0 || manual === true) {
17817                                                 _self.frame++;
17818                                                 _nextTime += overlap + (overlap >= _gap ? 0.004 : _gap - overlap);
17819                                                 dispatch = true;
17820                                         }
17821                                         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.
17822                                                 _id = _req(_tick);
17823                                         }
17824                                         if (dispatch) {
17825                                                 _self.dispatchEvent("tick");
17826                                         }
17827                                 };
17828
17829                         EventDispatcher.call(_self);
17830                         _self.time = _self.frame = 0;
17831                         _self.tick = function() {
17832                                 _tick(true);
17833                         };
17834
17835                         _self.lagSmoothing = function(threshold, adjustedLag) {
17836                                 _lagThreshold = threshold || (1 / _tinyNum); //zero should be interpreted as basically unlimited
17837                                 _adjustedLag = Math.min(adjustedLag, _lagThreshold, 0);
17838                         };
17839
17840                         _self.sleep = function() {
17841                                 if (_id == null) {
17842                                         return;
17843                                 }
17844                                 if (!_useRAF || !_cancelAnimFrame) {
17845                                         clearTimeout(_id);
17846                                 } else {
17847                                         _cancelAnimFrame(_id);
17848                                 }
17849                                 _req = _emptyFunc;
17850                                 _id = null;
17851                                 if (_self === _ticker) {
17852                                         _tickerActive = false;
17853                                 }
17854                         };
17855
17856                         _self.wake = function() {
17857                                 if (_id !== null) {
17858                                         _self.sleep();
17859                                 } 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().
17860                                         _lastUpdate = _getTime() - _lagThreshold + 5;
17861                                 }
17862                                 _req = (_fps === 0) ? _emptyFunc : (!_useRAF || !_reqAnimFrame) ? function(f) { return setTimeout(f, ((_nextTime - _self.time) * 1000 + 1) | 0); } : _reqAnimFrame;
17863                                 if (_self === _ticker) {
17864                                         _tickerActive = true;
17865                                 }
17866                                 _tick(2);
17867                         };
17868
17869                         _self.fps = function(value) {
17870                                 if (!arguments.length) {
17871                                         return _fps;
17872                                 }
17873                                 _fps = value;
17874                                 _gap = 1 / (_fps || 60);
17875                                 _nextTime = this.time + _gap;
17876                                 _self.wake();
17877                         };
17878
17879                         _self.useRAF = function(value) {
17880                                 if (!arguments.length) {
17881                                         return _useRAF;
17882                                 }
17883                                 _self.sleep();
17884                                 _useRAF = value;
17885                                 _self.fps(_fps);
17886                         };
17887                         _self.fps(fps);
17888
17889                         //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.
17890                         setTimeout(function() {
17891                                 if (_useRAF && (!_id || _self.frame < 5)) {
17892                                         _self.useRAF(false);
17893                                 }
17894                         }, 1500);
17895                 });
17896
17897                 p = gs.Ticker.prototype = new gs.events.EventDispatcher();
17898                 p.constructor = gs.Ticker;
17899
17900
17901 /*
17902  * ----------------------------------------------------------------
17903  * Animation
17904  * ----------------------------------------------------------------
17905  */
17906                 var Animation = _class("core.Animation", function(duration, vars) {
17907                                 this.vars = vars = vars || {};
17908                                 this._duration = this._totalDuration = duration || 0;
17909                                 this._delay = Number(vars.delay) || 0;
17910                                 this._timeScale = 1;
17911                                 this._active = (vars.immediateRender === true);
17912                                 this.data = vars.data;
17913                                 this._reversed = (vars.reversed === true);
17914
17915                                 if (!_rootTimeline) {
17916                                         return;
17917                                 }
17918                                 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.
17919                                         _ticker.wake();
17920                                 }
17921
17922                                 var tl = this.vars.useFrames ? _rootFramesTimeline : _rootTimeline;
17923                                 tl.add(this, tl._time);
17924
17925                                 if (this.vars.paused) {
17926                                         this.paused(true);
17927                                 }
17928                         });
17929
17930                 _ticker = Animation.ticker = new gs.Ticker();
17931                 p = Animation.prototype;
17932                 p._dirty = p._gc = p._initted = p._paused = false;
17933                 p._totalTime = p._time = 0;
17934                 p._rawPrevTime = -1;
17935                 p._next = p._last = p._onUpdate = p._timeline = p.timeline = null;
17936                 p._paused = false;
17937
17938
17939                 //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.
17940                 var _checkTimeout = function() {
17941                                 if (_tickerActive && _getTime() - _lastUpdate > 2000) {
17942                                         _ticker.wake();
17943                                 }
17944                                 setTimeout(_checkTimeout, 2000);
17945                         };
17946                 _checkTimeout();
17947
17948
17949                 p.play = function(from, suppressEvents) {
17950                         if (from != null) {
17951                                 this.seek(from, suppressEvents);
17952                         }
17953                         return this.reversed(false).paused(false);
17954                 };
17955
17956                 p.pause = function(atTime, suppressEvents) {
17957                         if (atTime != null) {
17958                                 this.seek(atTime, suppressEvents);
17959                         }
17960                         return this.paused(true);
17961                 };
17962
17963                 p.resume = function(from, suppressEvents) {
17964                         if (from != null) {
17965                                 this.seek(from, suppressEvents);
17966                         }
17967                         return this.paused(false);
17968                 };
17969
17970                 p.seek = function(time, suppressEvents) {
17971                         return this.totalTime(Number(time), suppressEvents !== false);
17972                 };
17973
17974                 p.restart = function(includeDelay, suppressEvents) {
17975                         return this.reversed(false).paused(false).totalTime(includeDelay ? -this._delay : 0, (suppressEvents !== false), true);
17976                 };
17977
17978                 p.reverse = function(from, suppressEvents) {
17979                         if (from != null) {
17980                                 this.seek((from || this.totalDuration()), suppressEvents);
17981                         }
17982                         return this.reversed(true).paused(false);
17983                 };
17984
17985                 p.render = function(time, suppressEvents, force) {
17986                         //stub - we override this method in subclasses.
17987                 };
17988
17989                 p.invalidate = function() {
17990                         return this;
17991                 };
17992
17993                 p.isActive = function() {
17994                         var tl = this._timeline, //the 2 root timelines won't have a _timeline; they're always active.
17995                                 startTime = this._startTime,
17996                                 rawTime;
17997                         return (!tl || (!this._gc && !this._paused && tl.isActive() && (rawTime = tl.rawTime()) >= startTime && rawTime < startTime + this.totalDuration() / this._timeScale));
17998                 };
17999
18000                 p._enabled = function (enabled, ignoreTimeline) {
18001                         if (!_tickerActive) {
18002                                 _ticker.wake();
18003                         }
18004                         this._gc = !enabled;
18005                         this._active = this.isActive();
18006                         if (ignoreTimeline !== true) {
18007                                 if (enabled && !this.timeline) {
18008                                         this._timeline.add(this, this._startTime - this._delay);
18009                                 } else if (!enabled && this.timeline) {
18010                                         this._timeline._remove(this, true);
18011                                 }
18012                         }
18013                         return false;
18014                 };
18015
18016
18017                 p._kill = function(vars, target) {
18018                         return this._enabled(false, false);
18019                 };
18020
18021                 p.kill = function(vars, target) {
18022                         this._kill(vars, target);
18023                         return this;
18024                 };
18025
18026                 p._uncache = function(includeSelf) {
18027                         var tween = includeSelf ? this : this.timeline;
18028                         while (tween) {
18029                                 tween._dirty = true;
18030                                 tween = tween.timeline;
18031                         }
18032                         return this;
18033                 };
18034
18035                 p._swapSelfInParams = function(params) {
18036                         var i = params.length,
18037                                 copy = params.concat();
18038                         while (--i > -1) {
18039                                 if (params[i] === "{self}") {
18040                                         copy[i] = this;
18041                                 }
18042                         }
18043                         return copy;
18044                 };
18045
18046 //----Animation getters/setters --------------------------------------------------------
18047
18048                 p.eventCallback = function(type, callback, params, scope) {
18049                         if ((type || "").substr(0,2) === "on") {
18050                                 var v = this.vars;
18051                                 if (arguments.length === 1) {
18052                                         return v[type];
18053                                 }
18054                                 if (callback == null) {
18055                                         delete v[type];
18056                                 } else {
18057                                         v[type] = callback;
18058                                         v[type + "Params"] = (_isArray(params) && params.join("").indexOf("{self}") !== -1) ? this._swapSelfInParams(params) : params;
18059                                         v[type + "Scope"] = scope;
18060                                 }
18061                                 if (type === "onUpdate") {
18062                                         this._onUpdate = callback;
18063                                 }
18064                         }
18065                         return this;
18066                 };
18067
18068                 p.delay = function(value) {
18069                         if (!arguments.length) {
18070                                 return this._delay;
18071                         }
18072                         if (this._timeline.smoothChildTiming) {
18073                                 this.startTime( this._startTime + value - this._delay );
18074                         }
18075                         this._delay = value;
18076                         return this;
18077                 };
18078
18079                 p.duration = function(value) {
18080                         if (!arguments.length) {
18081                                 this._dirty = false;
18082                                 return this._duration;
18083                         }
18084                         this._duration = this._totalDuration = value;
18085                         this._uncache(true); //true in case it's a TweenMax or TimelineMax that has a repeat - we'll need to refresh the totalDuration.
18086                         if (this._timeline.smoothChildTiming) if (this._time > 0) if (this._time < this._duration) if (value !== 0) {
18087                                 this.totalTime(this._totalTime * (value / this._duration), true);
18088                         }
18089                         return this;
18090                 };
18091
18092                 p.totalDuration = function(value) {
18093                         this._dirty = false;
18094                         return (!arguments.length) ? this._totalDuration : this.duration(value);
18095                 };
18096
18097                 p.time = function(value, suppressEvents) {
18098                         if (!arguments.length) {
18099                                 return this._time;
18100                         }
18101                         if (this._dirty) {
18102                                 this.totalDuration();
18103                         }
18104                         return this.totalTime((value > this._duration) ? this._duration : value, suppressEvents);
18105                 };
18106
18107                 p.totalTime = function(time, suppressEvents, uncapped) {
18108                         if (!_tickerActive) {
18109                                 _ticker.wake();
18110                         }
18111                         if (!arguments.length) {
18112                                 return this._totalTime;
18113                         }
18114                         if (this._timeline) {
18115                                 if (time < 0 && !uncapped) {
18116                                         time += this.totalDuration();
18117                                 }
18118                                 if (this._timeline.smoothChildTiming) {
18119                                         if (this._dirty) {
18120                                                 this.totalDuration();
18121                                         }
18122                                         var totalDuration = this._totalDuration,
18123                                                 tl = this._timeline;
18124                                         if (time > totalDuration && !uncapped) {
18125                                                 time = totalDuration;
18126                                         }
18127                                         this._startTime = (this._paused ? this._pauseTime : tl._time) - ((!this._reversed ? time : totalDuration - time) / this._timeScale);
18128                                         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.
18129                                                 this._uncache(false);
18130                                         }
18131                                         //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.
18132                                         if (tl._timeline) {
18133                                                 while (tl._timeline) {
18134                                                         if (tl._timeline._time !== (tl._startTime + tl._totalTime) / tl._timeScale) {
18135                                                                 tl.totalTime(tl._totalTime, true);
18136                                                         }
18137                                                         tl = tl._timeline;
18138                                                 }
18139                                         }
18140                                 }
18141                                 if (this._gc) {
18142                                         this._enabled(true, false);
18143                                 }
18144                                 if (this._totalTime !== time || this._duration === 0) {
18145                                         this.render(time, suppressEvents, false);
18146                                         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.
18147                                                 _lazyRender();
18148                                         }
18149                                 }
18150                         }
18151                         return this;
18152                 };
18153
18154                 p.progress = p.totalProgress = function(value, suppressEvents) {
18155                         return (!arguments.length) ? this._time / this.duration() : this.totalTime(this.duration() * value, suppressEvents);
18156                 };
18157
18158                 p.startTime = function(value) {
18159                         if (!arguments.length) {
18160                                 return this._startTime;
18161                         }
18162                         if (value !== this._startTime) {
18163                                 this._startTime = value;
18164                                 if (this.timeline) if (this.timeline._sortChildren) {
18165                                         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.
18166                                 }
18167                         }
18168                         return this;
18169                 };
18170
18171                 p.timeScale = function(value) {
18172                         if (!arguments.length) {
18173                                 return this._timeScale;
18174                         }
18175                         value = value || _tinyNum; //can't allow zero because it'll throw the math off
18176                         if (this._timeline && this._timeline.smoothChildTiming) {
18177                                 var pauseTime = this._pauseTime,
18178                                         t = (pauseTime || pauseTime === 0) ? pauseTime : this._timeline.totalTime();
18179                                 this._startTime = t - ((t - this._startTime) * this._timeScale / value);
18180                         }
18181                         this._timeScale = value;
18182                         return this._uncache(false);
18183                 };
18184
18185                 p.reversed = function(value) {
18186                         if (!arguments.length) {
18187                                 return this._reversed;
18188                         }
18189                         if (value != this._reversed) {
18190                                 this._reversed = value;
18191                                 this.totalTime(((this._timeline && !this._timeline.smoothChildTiming) ? this.totalDuration() - this._totalTime : this._totalTime), true);
18192                         }
18193                         return this;
18194                 };
18195
18196                 p.paused = function(value) {
18197                         if (!arguments.length) {
18198                                 return this._paused;
18199                         }
18200                         if (value != this._paused) if (this._timeline) {
18201                                 if (!_tickerActive && !value) {
18202                                         _ticker.wake();
18203                                 }
18204                                 var tl = this._timeline,
18205                                         raw = tl.rawTime(),
18206                                         elapsed = raw - this._pauseTime;
18207                                 if (!value && tl.smoothChildTiming) {
18208                                         this._startTime += elapsed;
18209                                         this._uncache(false);
18210                                 }
18211                                 this._pauseTime = value ? raw : null;
18212                                 this._paused = value;
18213                                 this._active = this.isActive();
18214                                 if (!value && elapsed !== 0 && this._initted && this.duration()) {
18215                                         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.
18216                                 }
18217                         }
18218                         if (this._gc && !value) {
18219                                 this._enabled(true, false);
18220                         }
18221                         return this;
18222                 };
18223
18224
18225 /*
18226  * ----------------------------------------------------------------
18227  * SimpleTimeline
18228  * ----------------------------------------------------------------
18229  */
18230                 var SimpleTimeline = _class("core.SimpleTimeline", function(vars) {
18231                         Animation.call(this, 0, vars);
18232                         this.autoRemoveChildren = this.smoothChildTiming = true;
18233                 });
18234
18235                 p = SimpleTimeline.prototype = new Animation();
18236                 p.constructor = SimpleTimeline;
18237                 p.kill()._gc = false;
18238                 p._first = p._last = null;
18239                 p._sortChildren = false;
18240
18241                 p.add = p.insert = function(child, position, align, stagger) {
18242                         var prevTween, st;
18243                         child._startTime = Number(position || 0) + child._delay;
18244                         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).
18245                                 child._pauseTime = child._startTime + ((this.rawTime() - child._startTime) / child._timeScale);
18246                         }
18247                         if (child.timeline) {
18248                                 child.timeline._remove(child, true); //removes from existing timeline so that it can be properly added to this one.
18249                         }
18250                         child.timeline = child._timeline = this;
18251                         if (child._gc) {
18252                                 child._enabled(true, true);
18253                         }
18254                         prevTween = this._last;
18255                         if (this._sortChildren) {
18256                                 st = child._startTime;
18257                                 while (prevTween && prevTween._startTime > st) {
18258                                         prevTween = prevTween._prev;
18259                                 }
18260                         }
18261                         if (prevTween) {
18262                                 child._next = prevTween._next;
18263                                 prevTween._next = child;
18264                         } else {
18265                                 child._next = this._first;
18266                                 this._first = child;
18267                         }
18268                         if (child._next) {
18269                                 child._next._prev = child;
18270                         } else {
18271                                 this._last = child;
18272                         }
18273                         child._prev = prevTween;
18274                         if (this._timeline) {
18275                                 this._uncache(true);
18276                         }
18277                         return this;
18278                 };
18279
18280                 p._remove = function(tween, skipDisable) {
18281                         if (tween.timeline === this) {
18282                                 if (!skipDisable) {
18283                                         tween._enabled(false, true);
18284                                 }
18285                                 tween.timeline = null;
18286
18287                                 if (tween._prev) {
18288                                         tween._prev._next = tween._next;
18289                                 } else if (this._first === tween) {
18290                                         this._first = tween._next;
18291                                 }
18292                                 if (tween._next) {
18293                                         tween._next._prev = tween._prev;
18294                                 } else if (this._last === tween) {
18295                                         this._last = tween._prev;
18296                                 }
18297
18298                                 if (this._timeline) {
18299                                         this._uncache(true);
18300                                 }
18301                         }
18302                         return this;
18303                 };
18304
18305                 p.render = function(time, suppressEvents, force) {
18306                         var tween = this._first,
18307                                 next;
18308                         this._totalTime = this._time = this._rawPrevTime = time;
18309                         while (tween) {
18310                                 next = tween._next; //record it here because the value could change after rendering...
18311                                 if (tween._active || (time >= tween._startTime && !tween._paused)) {
18312                                         if (!tween._reversed) {
18313                                                 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
18314                                         } else {
18315                                                 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
18316                                         }
18317                                 }
18318                                 tween = next;
18319                         }
18320                 };
18321
18322                 p.rawTime = function() {
18323                         if (!_tickerActive) {
18324                                 _ticker.wake();
18325                         }
18326                         return this._totalTime;
18327                 };
18328
18329 /*
18330  * ----------------------------------------------------------------
18331  * TweenLite
18332  * ----------------------------------------------------------------
18333  */
18334                 var TweenLite = _class("TweenLite", function(target, duration, vars) {
18335                                 Animation.call(this, duration, vars);
18336                                 this.render = TweenLite.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method)
18337
18338                                 if (target == null) {
18339                                         throw "Cannot tween a null target.";
18340                                 }
18341
18342                                 this.target = target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;
18343
18344                                 var isSelector = (target.jquery || (target.length && target !== window && target[0] && (target[0] === window || (target[0].nodeType && target[0].style && !target.nodeType)))),
18345                                         overwrite = this.vars.overwrite,
18346                                         i, targ, targets;
18347
18348                                 this._overwrite = overwrite = (overwrite == null) ? _overwriteLookup[TweenLite.defaultOverwrite] : (typeof(overwrite) === "number") ? overwrite >> 0 : _overwriteLookup[overwrite];
18349
18350                                 if ((isSelector || target instanceof Array || (target.push && _isArray(target))) && typeof(target[0]) !== "number") {
18351                                         this._targets = targets = _slice.call(target, 0);
18352                                         this._propLookup = [];
18353                                         this._siblings = [];
18354                                         for (i = 0; i < targets.length; i++) {
18355                                                 targ = targets[i];
18356                                                 if (!targ) {
18357                                                         targets.splice(i--, 1);
18358                                                         continue;
18359                                                 } else if (typeof(targ) === "string") {
18360                                                         targ = targets[i--] = TweenLite.selector(targ); //in case it's an array of strings
18361                                                         if (typeof(targ) === "string") {
18362                                                                 targets.splice(i+1, 1); //to avoid an endless loop (can't imagine why the selector would return a string, but just in case)
18363                                                         }
18364                                                         continue;
18365                                                 } 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.
18366                                                         targets.splice(i--, 1);
18367                                                         this._targets = targets = targets.concat(_slice.call(targ, 0));
18368                                                         continue;
18369                                                 }
18370                                                 this._siblings[i] = _register(targ, this, false);
18371                                                 if (overwrite === 1) if (this._siblings[i].length > 1) {
18372                                                         _applyOverwrite(targ, this, null, 1, this._siblings[i]);
18373                                                 }
18374                                         }
18375
18376                                 } else {
18377                                         this._propLookup = {};
18378                                         this._siblings = _register(target, this, false);
18379                                         if (overwrite === 1) if (this._siblings.length > 1) {
18380                                                 _applyOverwrite(target, this, null, 1, this._siblings);
18381                                         }
18382                                 }
18383                                 if (this.vars.immediateRender || (duration === 0 && this._delay === 0 && this.vars.immediateRender !== false)) {
18384                                         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)
18385                                         this.render(-this._delay);
18386                                 }
18387                         }, true),
18388                         _isSelector = function(v) {
18389                                 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.
18390                         },
18391                         _autoCSS = function(vars, target) {
18392                                 var css = {},
18393                                         p;
18394                                 for (p in vars) {
18395                                         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.
18396                                                 css[p] = vars[p];
18397                                                 delete vars[p];
18398                                         }
18399                                 }
18400                                 vars.css = css;
18401                         };
18402
18403                 p = TweenLite.prototype = new Animation();
18404                 p.constructor = TweenLite;
18405                 p.kill()._gc = false;
18406
18407 //----TweenLite defaults, overwrite management, and root updates ----------------------------------------------------
18408
18409                 p.ratio = 0;
18410                 p._firstPT = p._targets = p._overwrittenProps = p._startAt = null;
18411                 p._notifyPluginsOfEnabled = p._lazy = false;
18412
18413                 TweenLite.version = "1.12.1";
18414                 TweenLite.defaultEase = p._ease = new Ease(null, null, 1, 1);
18415                 TweenLite.defaultOverwrite = "auto";
18416                 TweenLite.ticker = _ticker;
18417                 TweenLite.autoSleep = true;
18418                 TweenLite.lagSmoothing = function(threshold, adjustedLag) {
18419                         _ticker.lagSmoothing(threshold, adjustedLag);
18420                 };
18421                 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; };
18422
18423                 var _lazyTweens = [],
18424                         _lazyLookup = {},
18425                         _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.
18426                         _plugins = TweenLite._plugins = {},
18427                         _tweenLookup = _internals.tweenLookup = {},
18428                         _tweenLookupNum = 0,
18429                         _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},
18430                         _overwriteLookup = {none:0, all:1, auto:2, concurrent:3, allOnStart:4, preexisting:5, "true":1, "false":0},
18431                         _rootFramesTimeline = Animation._rootFramesTimeline = new SimpleTimeline(),
18432                         _rootTimeline = Animation._rootTimeline = new SimpleTimeline(),
18433                         _lazyRender = function() {
18434                                 var i = _lazyTweens.length;
18435                                 _lazyLookup = {};
18436                                 while (--i > -1) {
18437                                         a = _lazyTweens[i];
18438                                         if (a && a._lazy !== false) {
18439                                                 a.render(a._lazy, false, true);
18440                                                 a._lazy = false;
18441                                         }
18442                                 }
18443                                 _lazyTweens.length = 0;
18444                         };
18445
18446                 _rootTimeline._startTime = _ticker.time;
18447                 _rootFramesTimeline._startTime = _ticker.frame;
18448                 _rootTimeline._active = _rootFramesTimeline._active = true;
18449                 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".
18450
18451                 Animation._updateRoot = TweenLite.render = function() {
18452                                 var i, a, p;
18453                                 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.
18454                                         _lazyRender();
18455                                 }
18456                                 _rootTimeline.render((_ticker.time - _rootTimeline._startTime) * _rootTimeline._timeScale, false, false);
18457                                 _rootFramesTimeline.render((_ticker.frame - _rootFramesTimeline._startTime) * _rootFramesTimeline._timeScale, false, false);
18458                                 if (_lazyTweens.length) {
18459                                         _lazyRender();
18460                                 }
18461                                 if (!(_ticker.frame % 120)) { //dump garbage every 120 frames...
18462                                         for (p in _tweenLookup) {
18463                                                 a = _tweenLookup[p].tweens;
18464                                                 i = a.length;
18465                                                 while (--i > -1) {
18466                                                         if (a[i]._gc) {
18467                                                                 a.splice(i, 1);
18468                                                         }
18469                                                 }
18470                                                 if (a.length === 0) {
18471                                                         delete _tweenLookup[p];
18472                                                 }
18473                                         }
18474                                         //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
18475                                         p = _rootTimeline._first;
18476                                         if (!p || p._paused) if (TweenLite.autoSleep && !_rootFramesTimeline._first && _ticker._listeners.tick.length === 1) {
18477                                                 while (p && p._paused) {
18478                                                         p = p._next;
18479                                                 }
18480                                                 if (!p) {
18481                                                         _ticker.sleep();
18482                                                 }
18483                                         }
18484                                 }
18485                         };
18486
18487                 _ticker.addEventListener("tick", Animation._updateRoot);
18488
18489                 var _register = function(target, tween, scrub) {
18490                                 var id = target._gsTweenID, a, i;
18491                                 if (!_tweenLookup[id || (target._gsTweenID = id = "t" + (_tweenLookupNum++))]) {
18492                                         _tweenLookup[id] = {target:target, tweens:[]};
18493                                 }
18494                                 if (tween) {
18495                                         a = _tweenLookup[id].tweens;
18496                                         a[(i = a.length)] = tween;
18497                                         if (scrub) {
18498                                                 while (--i > -1) {
18499                                                         if (a[i] === tween) {
18500                                                                 a.splice(i, 1);
18501                                                         }
18502                                                 }
18503                                         }
18504                                 }
18505                                 return _tweenLookup[id].tweens;
18506                         },
18507
18508                         _applyOverwrite = function(target, tween, props, mode, siblings) {
18509                                 var i, changed, curTween, l;
18510                                 if (mode === 1 || mode >= 4) {
18511                                         l = siblings.length;
18512                                         for (i = 0; i < l; i++) {
18513                                                 if ((curTween = siblings[i]) !== tween) {
18514                                                         if (!curTween._gc) if (curTween._enabled(false, false)) {
18515                                                                 changed = true;
18516                                                         }
18517                                                 } else if (mode === 5) {
18518                                                         break;
18519                                                 }
18520                                         }
18521                                         return changed;
18522                                 }
18523                                 //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)
18524                                 var startTime = tween._startTime + _tinyNum,
18525                                         overlaps = [],
18526                                         oCount = 0,
18527                                         zeroDur = (tween._duration === 0),
18528                                         globalStart;
18529                                 i = siblings.length;
18530                                 while (--i > -1) {
18531                                         if ((curTween = siblings[i]) === tween || curTween._gc || curTween._paused) {
18532                                                 //ignore
18533                                         } else if (curTween._timeline !== tween._timeline) {
18534                                                 globalStart = globalStart || _checkOverlap(tween, 0, zeroDur);
18535                                                 if (_checkOverlap(curTween, globalStart, zeroDur) === 0) {
18536                                                         overlaps[oCount++] = curTween;
18537                                                 }
18538                                         } else if (curTween._startTime <= startTime) if (curTween._startTime + curTween.totalDuration() / curTween._timeScale > startTime) if (!((zeroDur || !curTween._initted) && startTime - curTween._startTime <= 0.0000000002)) {
18539                                                 overlaps[oCount++] = curTween;
18540                                         }
18541                                 }
18542
18543                                 i = oCount;
18544                                 while (--i > -1) {
18545                                         curTween = overlaps[i];
18546                                         if (mode === 2) if (curTween._kill(props, target)) {
18547                                                 changed = true;
18548                                         }
18549                                         if (mode !== 2 || (!curTween._firstPT && curTween._initted)) {
18550                                                 if (curTween._enabled(false, false)) { //if all property tweens have been overwritten, kill the tween.
18551                                                         changed = true;
18552                                                 }
18553                                         }
18554                                 }
18555                                 return changed;
18556                         },
18557
18558                         _checkOverlap = function(tween, reference, zeroDur) {
18559                                 var tl = tween._timeline,
18560                                         ts = tl._timeScale,
18561                                         t = tween._startTime;
18562                                 while (tl._timeline) {
18563                                         t += tl._startTime;
18564                                         ts *= tl._timeScale;
18565                                         if (tl._paused) {
18566                                                 return -100;
18567                                         }
18568                                         tl = tl._timeline;
18569                                 }
18570                                 t /= ts;
18571                                 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;
18572                         };
18573
18574
18575 //---- TweenLite instance methods -----------------------------------------------------------------------------
18576
18577                 p._init = function() {
18578                         var v = this.vars,
18579                                 op = this._overwrittenProps,
18580                                 dur = this._duration,
18581                                 immediate = !!v.immediateRender,
18582                                 ease = v.ease,
18583                                 i, initPlugins, pt, p, startVars;
18584                         if (v.startAt) {
18585                                 if (this._startAt) {
18586                                         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.
18587                                         this._startAt.kill();
18588                                 }
18589                                 startVars = {};
18590                                 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);
18591                                         startVars[p] = v.startAt[p];
18592                                 }
18593                                 startVars.overwrite = false;
18594                                 startVars.immediateRender = true;
18595                                 startVars.lazy = (immediate && v.lazy !== false);
18596                                 startVars.startAt = startVars.delay = null; //no nesting of startAt objects allowed (otherwise it could cause an infinite loop).
18597                                 this._startAt = TweenLite.to(this.target, 0, startVars);
18598                                 if (immediate) {
18599                                         if (this._time > 0) {
18600                                                 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()).
18601                                         } else if (dur !== 0) {
18602                                                 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.
18603                                         }
18604                                 }
18605                         } else if (v.runBackwards && dur !== 0) {
18606                                 //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)
18607                                 if (this._startAt) {
18608                                         this._startAt.render(-1, true);
18609                                         this._startAt.kill();
18610                                         this._startAt = null;
18611                                 } else {
18612                                         pt = {};
18613                                         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.
18614                                                 if (!_reservedProps[p] || p === "autoCSS") {
18615                                                         pt[p] = v[p];
18616                                                 }
18617                                         }
18618                                         pt.overwrite = 0;
18619                                         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.
18620                                         pt.lazy = (immediate && v.lazy !== false);
18621                                         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)
18622                                         this._startAt = TweenLite.to(this.target, 0, pt);
18623                                         if (!immediate) {
18624                                                 this._startAt._init(); //ensures that the initial values are recorded
18625                                                 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.
18626                                         } else if (this._time === 0) {
18627                                                 return;
18628                                         }
18629                                 }
18630                         }
18631                         if (!ease) {
18632                                 this._ease = TweenLite.defaultEase;
18633                         } else if (ease instanceof Ease) {
18634                                 this._ease = (v.easeParams instanceof Array) ? ease.config.apply(ease, v.easeParams) : ease;
18635                         } else {
18636                                 this._ease = (typeof(ease) === "function") ? new Ease(ease, v.easeParams) : _easeMap[ease] || TweenLite.defaultEase;
18637                         }
18638                         this._easeType = this._ease._type;
18639                         this._easePower = this._ease._power;
18640                         this._firstPT = null;
18641
18642                         if (this._targets) {
18643                                 i = this._targets.length;
18644                                 while (--i > -1) {
18645                                         if ( this._initProps( this._targets[i], (this._propLookup[i] = {}), this._siblings[i], (op ? op[i] : null)) ) {
18646                                                 initPlugins = true;
18647                                         }
18648                                 }
18649                         } else {
18650                                 initPlugins = this._initProps(this.target, this._propLookup, this._siblings, op);
18651                         }
18652
18653                         if (initPlugins) {
18654                                 TweenLite._onPluginEvent("_onInitAllProps", this); //reorders the array in order of priority. Uses a static TweenPlugin method in order to minimize file size in TweenLite
18655                         }
18656                         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.
18657                                 this._enabled(false, false);
18658                         }
18659                         if (v.runBackwards) {
18660                                 pt = this._firstPT;
18661                                 while (pt) {
18662                                         pt.s += pt.c;
18663                                         pt.c = -pt.c;
18664                                         pt = pt._next;
18665                                 }
18666                         }
18667                         this._onUpdate = v.onUpdate;
18668                         this._initted = true;
18669                 };
18670
18671                 p._initProps = function(target, propLookup, siblings, overwrittenProps) {
18672                         var p, i, initPlugins, plugin, pt, v;
18673                         if (target == null) {
18674                                 return false;
18675                         }
18676
18677                         if (_lazyLookup[target._gsTweenID]) {
18678                                 _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)
18679                         }
18680
18681                         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.
18682                                 _autoCSS(this.vars, target);
18683                         }
18684                         for (p in this.vars) {
18685                                 v = this.vars[p];
18686                                 if (_reservedProps[p]) {
18687                                         if (v) if ((v instanceof Array) || (v.push && _isArray(v))) if (v.join("").indexOf("{self}") !== -1) {
18688                                                 this.vars[p] = v = this._swapSelfInParams(v, this);
18689                                         }
18690
18691                                 } else if (_plugins[p] && (plugin = new _plugins[p]())._onInitTween(target, this.vars[p], this)) {
18692
18693                                         //t - target            [object]
18694                                         //p - property          [string]
18695                                         //s - start                     [number]
18696                                         //c - change            [number]
18697                                         //f - isFunction        [boolean]
18698                                         //n - name                      [string]
18699                                         //pg - isPlugin         [boolean]
18700                                         //pr - priority         [number]
18701                                         this._firstPT = pt = {_next:this._firstPT, t:plugin, p:"setRatio", s:0, c:1, f:true, n:p, pg:true, pr:plugin._priority};
18702                                         i = plugin._overwriteProps.length;
18703                                         while (--i > -1) {
18704                                                 propLookup[plugin._overwriteProps[i]] = this._firstPT;
18705                                         }
18706                                         if (plugin._priority || plugin._onInitAllProps) {
18707                                                 initPlugins = true;
18708                                         }
18709                                         if (plugin._onDisable || plugin._onEnable) {
18710                                                 this._notifyPluginsOfEnabled = true;
18711                                         }
18712
18713                                 } else {
18714                                         this._firstPT = propLookup[p] = pt = {_next:this._firstPT, t:target, p:p, f:(typeof(target[p]) === "function"), n:p, pg:false, pr:0};
18715                                         pt.s = (!pt.f) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();
18716                                         pt.c = (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) : (Number(v) - pt.s) || 0;
18717                                 }
18718                                 if (pt) if (pt._next) {
18719                                         pt._next._prev = pt;
18720                                 }
18721                         }
18722
18723                         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)
18724                                 return this._initProps(target, propLookup, siblings, overwrittenProps);
18725                         }
18726                         if (this._overwrite > 1) if (this._firstPT) if (siblings.length > 1) if (_applyOverwrite(target, this, propLookup, this._overwrite, siblings)) {
18727                                 this._kill(propLookup, target);
18728                                 return this._initProps(target, propLookup, siblings, overwrittenProps);
18729                         }
18730                         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.
18731                                 _lazyLookup[target._gsTweenID] = true;
18732                         }
18733                         return initPlugins;
18734                 };
18735
18736                 p.render = function(time, suppressEvents, force) {
18737                         var prevTime = this._time,
18738                                 duration = this._duration,
18739                                 prevRawPrevTime = this._rawPrevTime,
18740                                 isComplete, callback, pt, rawPrevTime;
18741                         if (time >= duration) {
18742                                 this._totalTime = this._time = duration;
18743                                 this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1;
18744                                 if (!this._reversed ) {
18745                                         isComplete = true;
18746                                         callback = "onComplete";
18747                                 }
18748                                 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.
18749                                         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.
18750                                                 time = 0;
18751                                         }
18752                                         if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time) {
18753                                                 force = true;
18754                                                 if (prevRawPrevTime > _tinyNum) {
18755                                                         callback = "onReverseComplete";
18756                                                 }
18757                                         }
18758                                         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.
18759                                 }
18760
18761                         } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
18762                                 this._totalTime = this._time = 0;
18763                                 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
18764                                 if (prevTime !== 0 || (duration === 0 && prevRawPrevTime > 0 && prevRawPrevTime !== _tinyNum)) {
18765                                         callback = "onReverseComplete";
18766                                         isComplete = this._reversed;
18767                                 }
18768                                 if (time < 0) {
18769                                         this._active = false;
18770                                         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.
18771                                                 if (prevRawPrevTime >= 0) {
18772                                                         force = true;
18773                                                 }
18774                                                 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.
18775                                         }
18776                                 } 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.
18777                                         force = true;
18778                                 }
18779                         } else {
18780                                 this._totalTime = this._time = time;
18781
18782                                 if (this._easeType) {
18783                                         var r = time / duration, type = this._easeType, pow = this._easePower;
18784                                         if (type === 1 || (type === 3 && r >= 0.5)) {
18785                                                 r = 1 - r;
18786                                         }
18787                                         if (type === 3) {
18788                                                 r *= 2;
18789                                         }
18790                                         if (pow === 1) {
18791                                                 r *= r;
18792                                         } else if (pow === 2) {
18793                                                 r *= r * r;
18794                                         } else if (pow === 3) {
18795                                                 r *= r * r * r;
18796                                         } else if (pow === 4) {
18797                                                 r *= r * r * r * r;
18798                                         }
18799
18800                                         if (type === 1) {
18801                                                 this.ratio = 1 - r;
18802                                         } else if (type === 2) {
18803                                                 this.ratio = r;
18804                                         } else if (time / duration < 0.5) {
18805                                                 this.ratio = r / 2;
18806                                         } else {
18807                                                 this.ratio = 1 - (r / 2);
18808                                         }
18809
18810                                 } else {
18811                                         this.ratio = this._ease.getRatio(time / duration);
18812                                 }
18813                         }
18814
18815                         if (this._time === prevTime && !force) {
18816                                 return;
18817                         } else if (!this._initted) {
18818                                 this._init();
18819                                 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.
18820                                         return;
18821                                 } else if (!force && this._firstPT && ((this.vars.lazy !== false && this._duration) || (this.vars.lazy && !this._duration))) {
18822                                         this._time = this._totalTime = prevTime;
18823                                         this._rawPrevTime = prevRawPrevTime;
18824                                         _lazyTweens.push(this);
18825                                         this._lazy = time;
18826                                         return;
18827                                 }
18828                                 //_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.
18829                                 if (this._time && !isComplete) {
18830                                         this.ratio = this._ease.getRatio(this._time / duration);
18831                                 } else if (isComplete && this._ease._calcEnd) {
18832                                         this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1);
18833                                 }
18834                         }
18835                         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.
18836                                 this._lazy = false;
18837                         }
18838                         if (!this._active) if (!this._paused && this._time !== prevTime && time >= 0) {
18839                                 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.
18840                         }
18841                         if (prevTime === 0) {
18842                                 if (this._startAt) {
18843                                         if (time >= 0) {
18844                                                 this._startAt.render(time, suppressEvents, force);
18845                                         } else if (!callback) {
18846                                                 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.
18847                                         }
18848                                 }
18849                                 if (this.vars.onStart) if (this._time !== 0 || duration === 0) if (!suppressEvents) {
18850                                         this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
18851                                 }
18852                         }
18853
18854                         pt = this._firstPT;
18855                         while (pt) {
18856                                 if (pt.f) {
18857                                         pt.t[pt.p](pt.c * this.ratio + pt.s);
18858                                 } else {
18859                                         pt.t[pt.p] = pt.c * this.ratio + pt.s;
18860                                 }
18861                                 pt = pt._next;
18862                         }
18863
18864                         if (this._onUpdate) {
18865                                 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.
18866                                         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.
18867                                 }
18868                                 if (!suppressEvents) if (this._time !== prevTime || isComplete) {
18869                                         this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
18870                                 }
18871                         }
18872
18873                         if (callback) if (!this._gc) { //check _gc because there's a chance that kill() could be called in an onUpdate
18874                                 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.
18875                                         this._startAt.render(time, suppressEvents, force);
18876                                 }
18877                                 if (isComplete) {
18878                                         if (this._timeline.autoRemoveChildren) {
18879                                                 this._enabled(false, false);
18880                                         }
18881                                         this._active = false;
18882                                 }
18883                                 if (!suppressEvents && this.vars[callback]) {
18884                                         this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
18885                                 }
18886                                 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.
18887                                         this._rawPrevTime = 0;
18888                                 }
18889                         }
18890
18891                 };
18892
18893                 p._kill = function(vars, target) {
18894                         if (vars === "all") {
18895                                 vars = null;
18896                         }
18897                         if (vars == null) if (target == null || target === this.target) {
18898                                 this._lazy = false;
18899                                 return this._enabled(false, false);
18900                         }
18901                         target = (typeof(target) !== "string") ? (target || this._targets || this.target) : TweenLite.selector(target) || target;
18902                         var i, overwrittenProps, p, pt, propLookup, changed, killProps, record;
18903                         if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") {
18904                                 i = target.length;
18905                                 while (--i > -1) {
18906                                         if (this._kill(vars, target[i])) {
18907                                                 changed = true;
18908                                         }
18909                                 }
18910                         } else {
18911                                 if (this._targets) {
18912                                         i = this._targets.length;
18913                                         while (--i > -1) {
18914                                                 if (target === this._targets[i]) {
18915                                                         propLookup = this._propLookup[i] || {};
18916                                                         this._overwrittenProps = this._overwrittenProps || [];
18917                                                         overwrittenProps = this._overwrittenProps[i] = vars ? this._overwrittenProps[i] || {} : "all";
18918                                                         break;
18919                                                 }
18920                                         }
18921                                 } else if (target !== this.target) {
18922                                         return false;
18923                                 } else {
18924                                         propLookup = this._propLookup;
18925                                         overwrittenProps = this._overwrittenProps = vars ? this._overwrittenProps || {} : "all";
18926                                 }
18927
18928                                 if (propLookup) {
18929                                         killProps = vars || propLookup;
18930                                         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)
18931                                         for (p in killProps) {
18932                                                 if ((pt = propLookup[p])) {
18933                                                         if (pt.pg && pt.t._kill(killProps)) {
18934                                                                 changed = true; //some plugins need to be notified so they can perform cleanup tasks first
18935                                                         }
18936                                                         if (!pt.pg || pt.t._overwriteProps.length === 0) {
18937                                                                 if (pt._prev) {
18938                                                                         pt._prev._next = pt._next;
18939                                                                 } else if (pt === this._firstPT) {
18940                                                                         this._firstPT = pt._next;
18941                                                                 }
18942                                                                 if (pt._next) {
18943                                                                         pt._next._prev = pt._prev;
18944                                                                 }
18945                                                                 pt._next = pt._prev = null;
18946                                                         }
18947                                                         delete propLookup[p];
18948                                                 }
18949                                                 if (record) {
18950                                                         overwrittenProps[p] = 1;
18951                                                 }
18952                                         }
18953                                         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.
18954                                                 this._enabled(false, false);
18955                                         }
18956                                 }
18957                         }
18958                         return changed;
18959                 };
18960
18961                 p.invalidate = function() {
18962                         if (this._notifyPluginsOfEnabled) {
18963                                 TweenLite._onPluginEvent("_onDisable", this);
18964                         }
18965                         this._firstPT = null;
18966                         this._overwrittenProps = null;
18967                         this._onUpdate = null;
18968                         this._startAt = null;
18969                         this._initted = this._active = this._notifyPluginsOfEnabled = this._lazy = false;
18970                         this._propLookup = (this._targets) ? {} : [];
18971                         return this;
18972                 };
18973
18974                 p._enabled = function(enabled, ignoreTimeline) {
18975                         if (!_tickerActive) {
18976                                 _ticker.wake();
18977                         }
18978                         if (enabled && this._gc) {
18979                                 var targets = this._targets,
18980                                         i;
18981                                 if (targets) {
18982                                         i = targets.length;
18983                                         while (--i > -1) {
18984                                                 this._siblings[i] = _register(targets[i], this, true);
18985                                         }
18986                                 } else {
18987                                         this._siblings = _register(this.target, this, true);
18988                                 }
18989                         }
18990                         Animation.prototype._enabled.call(this, enabled, ignoreTimeline);
18991                         if (this._notifyPluginsOfEnabled) if (this._firstPT) {
18992                                 return TweenLite._onPluginEvent((enabled ? "_onEnable" : "_onDisable"), this);
18993                         }
18994                         return false;
18995                 };
18996
18997
18998 //----TweenLite static methods -----------------------------------------------------
18999
19000                 TweenLite.to = function(target, duration, vars) {
19001                         return new TweenLite(target, duration, vars);
19002                 };
19003
19004                 TweenLite.from = function(target, duration, vars) {
19005                         vars.runBackwards = true;
19006                         vars.immediateRender = (vars.immediateRender != false);
19007                         return new TweenLite(target, duration, vars);
19008                 };
19009
19010                 TweenLite.fromTo = function(target, duration, fromVars, toVars) {
19011                         toVars.startAt = fromVars;
19012                         toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
19013                         return new TweenLite(target, duration, toVars);
19014                 };
19015
19016                 TweenLite.delayedCall = function(delay, callback, params, scope, useFrames) {
19017                         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});
19018                 };
19019
19020                 TweenLite.set = function(target, vars) {
19021                         return new TweenLite(target, 0, vars);
19022                 };
19023
19024                 TweenLite.getTweensOf = function(target, onlyActive) {
19025                         if (target == null) { return []; }
19026                         target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;
19027                         var i, a, j, t;
19028                         if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") {
19029                                 i = target.length;
19030                                 a = [];
19031                                 while (--i > -1) {
19032                                         a = a.concat(TweenLite.getTweensOf(target[i], onlyActive));
19033                                 }
19034                                 i = a.length;
19035                                 //now get rid of any duplicates (tweens of arrays of objects could cause duplicates)
19036                                 while (--i > -1) {
19037                                         t = a[i];
19038                                         j = i;
19039                                         while (--j > -1) {
19040                                                 if (t === a[j]) {
19041                                                         a.splice(i, 1);
19042                                                 }
19043                                         }
19044                                 }
19045                         } else {
19046                                 a = _register(target).concat();
19047                                 i = a.length;
19048                                 while (--i > -1) {
19049                                         if (a[i]._gc || (onlyActive && !a[i].isActive())) {
19050                                                 a.splice(i, 1);
19051                                         }
19052                                 }
19053                         }
19054                         return a;
19055                 };
19056
19057                 TweenLite.killTweensOf = TweenLite.killDelayedCallsTo = function(target, onlyActive, vars) {
19058                         if (typeof(onlyActive) === "object") {
19059                                 vars = onlyActive; //for backwards compatibility (before "onlyActive" parameter was inserted)
19060                                 onlyActive = false;
19061                         }
19062                         var a = TweenLite.getTweensOf(target, onlyActive),
19063                                 i = a.length;
19064                         while (--i > -1) {
19065                                 a[i]._kill(vars, target);
19066                         }
19067                 };
19068
19069
19070
19071 /*
19072  * ----------------------------------------------------------------
19073  * 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)
19074  * ----------------------------------------------------------------
19075  */
19076                 var TweenPlugin = _class("plugins.TweenPlugin", function(props, priority) {
19077                                         this._overwriteProps = (props || "").split(",");
19078                                         this._propName = this._overwriteProps[0];
19079                                         this._priority = priority || 0;
19080                                         this._super = TweenPlugin.prototype;
19081                                 }, true);
19082
19083                 p = TweenPlugin.prototype;
19084                 TweenPlugin.version = "1.10.1";
19085                 TweenPlugin.API = 2;
19086                 p._firstPT = null;
19087
19088                 p._addTween = function(target, prop, start, end, overwriteProp, round) {
19089                         var c, pt;
19090                         if (end != null && (c = (typeof(end) === "number" || end.charAt(1) !== "=") ? Number(end) - start : parseInt(end.charAt(0) + "1", 10) * Number(end.substr(2)))) {
19091                                 this._firstPT = pt = {_next:this._firstPT, t:target, p:prop, s:start, c:c, f:(typeof(target[prop]) === "function"), n:overwriteProp || prop, r:round};
19092                                 if (pt._next) {
19093                                         pt._next._prev = pt;
19094                                 }
19095                                 return pt;
19096                         }
19097                 };
19098
19099                 p.setRatio = function(v) {
19100                         var pt = this._firstPT,
19101                                 min = 0.000001,
19102                                 val;
19103                         while (pt) {
19104                                 val = pt.c * v + pt.s;
19105                                 if (pt.r) {
19106                                         val = Math.round(val);
19107                                 } else if (val < min) if (val > -min) { //prevents issues with converting very small numbers to strings in the browser
19108                                         val = 0;
19109                                 }
19110                                 if (pt.f) {
19111                                         pt.t[pt.p](val);
19112                                 } else {
19113                                         pt.t[pt.p] = val;
19114                                 }
19115                                 pt = pt._next;
19116                         }
19117                 };
19118
19119                 p._kill = function(lookup) {
19120                         var a = this._overwriteProps,
19121                                 pt = this._firstPT,
19122                                 i;
19123                         if (lookup[this._propName] != null) {
19124                                 this._overwriteProps = [];
19125                         } else {
19126                                 i = a.length;
19127                                 while (--i > -1) {
19128                                         if (lookup[a[i]] != null) {
19129                                                 a.splice(i, 1);
19130                                         }
19131                                 }
19132                         }
19133                         while (pt) {
19134                                 if (lookup[pt.n] != null) {
19135                                         if (pt._next) {
19136                                                 pt._next._prev = pt._prev;
19137                                         }
19138                                         if (pt._prev) {
19139                                                 pt._prev._next = pt._next;
19140                                                 pt._prev = null;
19141                                         } else if (this._firstPT === pt) {
19142                                                 this._firstPT = pt._next;
19143                                         }
19144                                 }
19145                                 pt = pt._next;
19146                         }
19147                         return false;
19148                 };
19149
19150                 p._roundProps = function(lookup, value) {
19151                         var pt = this._firstPT;
19152                         while (pt) {
19153                                 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.
19154                                         pt.r = value;
19155                                 }
19156                                 pt = pt._next;
19157                         }
19158                 };
19159
19160                 TweenLite._onPluginEvent = function(type, tween) {
19161                         var pt = tween._firstPT,
19162                                 changed, pt2, first, last, next;
19163                         if (type === "_onInitAllProps") {
19164                                 //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.
19165                                 while (pt) {
19166                                         next = pt._next;
19167                                         pt2 = first;
19168                                         while (pt2 && pt2.pr > pt.pr) {
19169                                                 pt2 = pt2._next;
19170                                         }
19171                                         if ((pt._prev = pt2 ? pt2._prev : last)) {
19172                                                 pt._prev._next = pt;
19173                                         } else {
19174                                                 first = pt;
19175                                         }
19176                                         if ((pt._next = pt2)) {
19177                                                 pt2._prev = pt;
19178                                         } else {
19179                                                 last = pt;
19180                                         }
19181                                         pt = next;
19182                                 }
19183                                 pt = tween._firstPT = first;
19184                         }
19185                         while (pt) {
19186                                 if (pt.pg) if (typeof(pt.t[type]) === "function") if (pt.t[type]()) {
19187                                         changed = true;
19188                                 }
19189                                 pt = pt._next;
19190                         }
19191                         return changed;
19192                 };
19193
19194                 TweenPlugin.activate = function(plugins) {
19195                         var i = plugins.length;
19196                         while (--i > -1) {
19197                                 if (plugins[i].API === TweenPlugin.API) {
19198                                         _plugins[(new plugins[i]())._propName] = plugins[i];
19199                                 }
19200                         }
19201                         return true;
19202                 };
19203
19204                 //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.
19205                 _gsDefine.plugin = function(config) {
19206                         if (!config || !config.propName || !config.init || !config.API) { throw "illegal plugin definition."; }
19207                         var propName = config.propName,
19208                                 priority = config.priority || 0,
19209                                 overwriteProps = config.overwriteProps,
19210                                 map = {init:"_onInitTween", set:"setRatio", kill:"_kill", round:"_roundProps", initAll:"_onInitAllProps"},
19211                                 Plugin = _class("plugins." + propName.charAt(0).toUpperCase() + propName.substr(1) + "Plugin",
19212                                         function() {
19213                                                 TweenPlugin.call(this, propName, priority);
19214                                                 this._overwriteProps = overwriteProps || [];
19215                                         }, (config.global === true)),
19216                                 p = Plugin.prototype = new TweenPlugin(propName),
19217                                 prop;
19218                         p.constructor = Plugin;
19219                         Plugin.API = config.API;
19220                         for (prop in map) {
19221                                 if (typeof(config[prop]) === "function") {
19222                                         p[map[prop]] = config[prop];
19223                                 }
19224                         }
19225                         Plugin.version = config.version;
19226                         TweenPlugin.activate([Plugin]);
19227                         return Plugin;
19228                 };
19229
19230
19231                 //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.
19232                 a = window._gsQueue;
19233                 if (a) {
19234                         for (i = 0; i < a.length; i++) {
19235                                 a[i]();
19236                         }
19237                         for (p in _defLookup) {
19238                                 if (!_defLookup[p].func) {
19239                                         //window.console.log("GSAP encountered missing dependency: com.greensock." + p);
19240                                 }
19241                         }
19242                 }
19243
19244                 _tickerActive = false; //ensures that the first official animation forces a ticker.tick() to update the time when it is instantiated
19245
19246 })(window);
19247
19248 angular.module('b2b.att.collapse', ['b2b.att.transition'])
19249
19250 // The collapsible directive indicates a block of html that will expand and collapse
19251 .directive('b2bCollapse', ['$transition', function($transition) {
19252     // CSS transitions don't work with height: auto, so we have to manually change the height to a
19253     // specific value and then once the animation completes, we can reset the height to auto.
19254     // Unfortunately if you do this while the CSS transitions are specified (i.e. in the CSS class
19255     // "collapse") then you trigger a change to height 0 in between.
19256     // The fix is to remove the "collapse" CSS class while changing the height back to auto - phew!
19257
19258     var props = {
19259         open: {
19260             marginTop: null,
19261             marginBottom: null,
19262             paddingTop: null,
19263             paddingBottom: null,
19264             display: 'block'
19265         },
19266         closed: {
19267             marginTop: 0,
19268             marginBottom: 0,
19269             paddingTop: 0,
19270             paddingBottom: 0,
19271             display: 'none'
19272         }
19273     };
19274
19275     var fixUpHeight = function(scope, element, height) {
19276         // We remove the collapse CSS class to prevent a transition when we change to height: auto
19277         element.removeClass('b2bCollapse');
19278         element.css({height: height});
19279         //adjusting for any margin or padding
19280         if (height === 0) {
19281             element.css(props.closed);
19282         } else {
19283             element.css(props.open);
19284         }
19285         // It appears that  reading offsetWidth makes the browser realise that we have changed the
19286         // height already :-/
19287         var x = element[0].offsetWidth;
19288         element.addClass('b2bCollapse');
19289     };
19290
19291     return {
19292         link: function(scope, element, attrs) {
19293             var isCollapsed;
19294             var initialAnimSkip = true;
19295             scope.$watch(function() {
19296                 return element[0].scrollHeight;
19297             }, function(value) {
19298                 //The listener is called when scrollHeight changes
19299                 //It actually does on 2 scenarios: 
19300                 // 1. Parent is set to display none
19301                 // 2. angular bindings inside are resolved
19302                 //When we have a change of scrollHeight we are setting again the correct height if the group is opened
19303                 if (element[0].scrollHeight !== 0) {
19304                     if (!isCollapsed) {
19305                         if (initialAnimSkip) {
19306                             fixUpHeight(scope, element, element[0].scrollHeight + 'px');
19307                         } else {
19308                             fixUpHeight(scope, element, 'auto');
19309                             element.css({overflow: 'visible'});
19310                         }
19311                     }
19312                 }
19313             });
19314
19315             scope.$watch(attrs.b2bCollapse, function(value) {
19316                 if (value) {
19317                     collapse();
19318                 } else {
19319                     expand();
19320                 }
19321             });
19322
19323
19324             var currentTransition;
19325             var doTransition = function(change) {
19326                 if (currentTransition) {
19327                     currentTransition.cancel();
19328                 }
19329                 currentTransition = $transition(element, change);
19330                 currentTransition.then(
19331                         function() {
19332                             currentTransition = undefined;
19333                         },
19334                         function() {
19335                             currentTransition = undefined;
19336                         }
19337                 );
19338                 return currentTransition;
19339             };
19340
19341             var expand = function() {
19342                 scope.postTransition = true; 
19343                 if (initialAnimSkip) {
19344                     initialAnimSkip = false;
19345                     if (!isCollapsed) {
19346                         fixUpHeight(scope, element, 'auto');
19347                     }
19348                 } else {
19349                     //doTransition({ height : element[0].scrollHeight + 'px' })
19350                     doTransition(angular.extend({height: element[0].scrollHeight + 'px'}, props.open))
19351                             .then(function() {
19352                                 // This check ensures that we don't accidentally update the height if the user has closed
19353                                 // the group while the animation was still running
19354                                 if (!isCollapsed) {
19355                                     fixUpHeight(scope, element, 'auto');
19356                                 }
19357                             });
19358                 }
19359                 isCollapsed = false;
19360             };
19361
19362             var collapse = function() {
19363                 isCollapsed = true;
19364                 if (initialAnimSkip) {
19365                     initialAnimSkip = false;
19366                     fixUpHeight(scope, element, 0);
19367                 } else {
19368                     fixUpHeight(scope, element, element[0].scrollHeight + 'px');
19369                     doTransition(angular.extend({height: 0}, props.closed)).then(function() {
19370                         scope.postTransition = false;
19371                     });
19372                     element.css({overflow: 'hidden'});
19373                 }
19374             };
19375         }
19376     };
19377 }]);
19378 angular.module('b2b.att.position', [])
19379
19380 .factory('$position', ['$document', '$window', function ($document, $window) {
19381     function getStyle(el, cssprop) {
19382         if (el.currentStyle) { //IE
19383             return el.currentStyle[cssprop];
19384         } else if ($window.getComputedStyle) {
19385             return $window.getComputedStyle(el)[cssprop];
19386         }
19387         // finally try and get inline style
19388         return el.style[cssprop];
19389     }
19390
19391     /**
19392      * Checks if a given element is statically positioned
19393      * @param element - raw DOM element
19394      */
19395     function isStaticPositioned(element) {
19396         return (getStyle(element, "position") || 'static') === 'static';
19397     }
19398
19399     /**
19400      * returns the closest, non-statically positioned parentOffset of a given element
19401      * @param element
19402      */
19403     var parentOffsetEl = function (element) {
19404         var docDomEl = $document[0];
19405         var offsetParent = element.offsetParent || docDomEl;
19406         while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent)) {
19407             offsetParent = offsetParent.offsetParent;
19408         }
19409         return offsetParent || docDomEl;
19410     };
19411
19412     return {
19413         /**
19414          * Provides read-only equivalent of jQuery's position function:
19415          * http://api.jquery.com/position/
19416          */
19417         position: function (element) {
19418             var elBCR = this.offset(element);
19419             var offsetParentBCR = {
19420                 top: 0,
19421                 left: 0
19422             };
19423             var offsetParentEl = parentOffsetEl(element[0]);
19424             if (offsetParentEl !== $document[0]) {
19425                 offsetParentBCR = this.offset(angular.element(offsetParentEl));
19426                 offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop;
19427                 offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft;
19428             }
19429
19430             return {
19431                 width: element.prop('offsetWidth'),
19432                 height: element.prop('offsetHeight'),
19433                 top: elBCR.top - offsetParentBCR.top,
19434                 left: elBCR.left - offsetParentBCR.left
19435             };
19436         },
19437
19438         /**
19439          * Provides read-only equivalent of jQuery's offset function:
19440          * http://api.jquery.com/offset/
19441          */
19442         offset: function (element) {
19443             var boundingClientRect = element[0].getBoundingClientRect();
19444             return {
19445                 width: element.prop('offsetWidth'),
19446                 height: element.prop('offsetHeight'),
19447                 top: boundingClientRect.top + ($window.pageYOffset || $document[0].body.scrollTop || $document[0].documentElement.scrollTop),
19448                 left: boundingClientRect.left + ($window.pageXOffset || $document[0].body.scrollLeft || $document[0].documentElement.scrollLeft)
19449             };
19450         },
19451                 
19452                  /**
19453          * Provides functionality to check whether an element is in view port.
19454          */
19455         isElementInViewport: function (element) {
19456             if (element) {
19457                 var rect = element[0].getBoundingClientRect();
19458                 return (
19459                     rect.top >= 0 &&
19460                     rect.left >= 0 &&
19461                     rect.bottom <= ($window.innerHeight || $document[0].documentElement.clientHeight) &&
19462                     rect.right <= ($window.innerWidth || $document[0].documentElement.clientWidth)
19463                 );
19464             } else {
19465                 return false;
19466             }
19467         }
19468     };
19469 }])
19470
19471 .factory('$isElement', [function () {
19472     var isElement = function (currentElem, targetElem, alternateElem) {
19473         if (currentElem[0] === targetElem[0]) {
19474             return true;
19475         } else if (currentElem[0] === alternateElem[0]) {
19476             return false;
19477         } else {
19478             return isElement((currentElem.parent()[0] && currentElem.parent()) || targetElem, targetElem, alternateElem);
19479         }
19480     };
19481
19482     return isElement;
19483 }])
19484
19485 .directive('attPosition', ['$position', function ($position) {
19486     return {
19487         restrict: 'A',
19488         link: function (scope, elem, attr) {
19489             scope.$watchCollection(function () {
19490                 return $position.position(elem);
19491             }, function (value) {
19492                 scope[attr.attPosition] = value;
19493             });
19494         }
19495     };
19496 }]);
19497
19498 angular.module('b2b.att.transition', [])
19499
19500 .factory('$transition', ['$q', '$timeout', '$rootScope', function($q, $timeout, $rootScope) {
19501
19502   var $transition = function(element, trigger, options) {
19503     options = options || {};
19504     var deferred = $q.defer();
19505     var endEventName = $transition[options.animation ? "animationEndEventName" : "transitionEndEventName"];
19506
19507     var transitionEndHandler = function() {
19508       $rootScope.$apply(function() {
19509         element.unbind(endEventName, transitionEndHandler);
19510         deferred.resolve(element);
19511       });
19512     };
19513
19514     if (endEventName) {
19515       element.bind(endEventName, transitionEndHandler);
19516     }
19517
19518     // Wrap in a timeout to allow the browser time to update the DOM before the transition is to occur
19519     $timeout(function() {
19520       if ( angular.isString(trigger) ) {
19521         element.addClass(trigger);
19522       } else if ( angular.isFunction(trigger) ) {
19523         trigger(element);
19524       } else if ( angular.isObject(trigger) ) {
19525         element.css(trigger);
19526       }
19527       //If browser does not support transitions, instantly resolve
19528       if ( !endEventName ) {
19529         deferred.resolve(element);
19530       }
19531     }, 100);
19532
19533     // Add our custom cancel function to the promise that is returned
19534     // We can call this if we are about to run a new transition, which we know will prevent this transition from ending,
19535     // i.e. it will therefore never raise a transitionEnd event for that transition
19536     deferred.promise.cancel = function() {
19537       if ( endEventName ) {
19538         element.unbind(endEventName, transitionEndHandler);
19539       }
19540       deferred.reject('Transition cancelled');
19541     };
19542
19543     return deferred.promise;
19544   };
19545
19546   // Work out the name of the transitionEnd event
19547   var transElement = document.createElement('trans');
19548   var transitionEndEventNames = {
19549     'WebkitTransition': 'webkitTransitionEnd',
19550     'MozTransition': 'transitionend',
19551     'OTransition': 'oTransitionEnd',
19552     'transition': 'transitionend'
19553   };
19554   var animationEndEventNames = {
19555     'WebkitTransition': 'webkitAnimationEnd',
19556     'MozTransition': 'animationend',
19557     'OTransition': 'oAnimationEnd',
19558     'transition': 'animationend'
19559   };
19560   function findEndEventName(endEventNames) {
19561     for (var name in endEventNames){
19562       if (transElement.style[name] !== undefined) {
19563         return endEventNames[name];
19564       }
19565     }
19566   }
19567   $transition.transitionEndEventName = findEndEventName(transitionEndEventNames);
19568   $transition.animationEndEventName = findEndEventName(animationEndEventNames);
19569   return $transition;
19570 }])
19571
19572 .factory('$scrollTo', ['$window', function($window) {
19573     var $scrollTo = function(offsetLeft, offsetTop, duration) {
19574         TweenMax.to($window, duration || 1, {scrollTo: {y: offsetTop, x: offsetLeft}, ease: Power4.easeOut});
19575     };
19576     return $scrollTo;
19577 }])
19578 .factory('animation', function(){
19579     return TweenMax;
19580 })
19581 .factory('$progressBar', function(){
19582
19583    //Provides a function to pass in code for closure purposes
19584    var loadingAnimationCreator = function(onUpdateCallback){
19585
19586       //Use closure to setup some resuable code
19587       var loadingAnimation = function(callback, duration){
19588           TweenMax.to({}, duration, {
19589               onUpdateParams: ["{self}"],
19590               onUpdate: onUpdateCallback,
19591               onComplete: callback
19592           });
19593       };
19594       //Returns a function that takes a callback function and a duration for the animation
19595       return (function(){
19596         return loadingAnimation;
19597       })();
19598     };
19599
19600   return loadingAnimationCreator;
19601 })
19602 .factory('$height', function(){
19603   var heightAnimation = function(element,duration,height,alpha){
19604     TweenMax.to(element,
19605       duration,
19606       {height:height, autoAlpha:alpha},
19607       0);
19608   };
19609   return heightAnimation;
19610 });
19611 angular.module('b2b.att.utilities', ['ngSanitize'])
19612 .constant('b2bUtilitiesConfig', {
19613     prev: '37',
19614     up: '38',
19615     next: '39',
19616     down: '40',
19617     type: 'list',
19618     columns: 1,
19619     enableSearch: false,
19620     searchTimer: 200,
19621     circularTraversal: false
19622 })
19623 .constant('b2bWhenScrollEndsConstants', {
19624     'threshold': 100,
19625     'width': 0,
19626     'height': 0
19627 })
19628 // All breakpoints ranges from >= min and < max
19629 .constant('b2bAwdBreakpoints', {
19630     breakpoints: {
19631         mobile: {
19632             min: 1,
19633             max: 768
19634         },
19635         tablet: {
19636             min: 768,
19637             max: 1025
19638         },
19639         desktop: {
19640             min: 1025,
19641             max: 1920
19642         }
19643     }
19644 })
19645 .filter('groupBy', function ($timeout) {
19646     //Custom GroupBy Filter for treeNav, returns key string and value.childarray as set of grouped elements
19647     return function (data, key) {
19648         if (!key) return data;
19649         var outputPropertyName = '__groupBy__' + key;
19650         if (!data[outputPropertyName]) {
19651             var result = {};
19652             for (var i = 0; i < data.length; i++) {
19653                 if (!result[data[i][key]])
19654                     result[data[i][key]] = {};
19655                 if (!result[data[i][key]].childArray) {
19656                     result[data[i][key]].childArray = [];
19657                 }
19658                 result[data[i][key]].childArray.push(data[i]);
19659                 if (data[i].activeGrp && data[i].activeGrp == true) {
19660                     result[data[i][key]].showGroup = true;
19661                 }
19662             }
19663             Object.defineProperty(result, 'length', {enumerable: false,value: Object.keys(result).length});
19664             Object.defineProperty(data, outputPropertyName, {enumerable: false,configurable: true,writable:false,value:result});
19665             $timeout(function(){delete data[outputPropertyName];},0,false);
19666         }
19667         return data[outputPropertyName];
19668     };
19669 })
19670 .filter('searchObjectPropertiesFilter', [function() {
19671     return function(items, searchText, attrs) {
19672         if(!searchText){
19673             return items;
19674         }
19675         var filtered = [];
19676         searchText = searchText.toLowerCase();
19677         angular.forEach(items, function(item) {
19678             angular.forEach(attrs, function(attr) {
19679                 if (item.hasOwnProperty(attr) && (item[attr].toLowerCase().indexOf(searchText) != -1)) {
19680                     filtered.push(item);
19681                     return;
19682                 }
19683             });
19684         });
19685         return filtered;
19686     };
19687 }])
19688 .filter('unsafe',[ '$sce', function ($sce) { 
19689     return function(val){ 
19690        return $sce.trustAsHtml(val); 
19691     }; 
19692 }])
19693 .filter('b2bHighlight', function () {
19694     function escapeRegexp(queryToEscape) {
19695         return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
19696     }
19697     return function (matchItem, query, className) {
19698         return query && matchItem ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '<span class=\"' + className + '\">$&</span>') : matchItem;
19699     }
19700 })
19701 /*License (MIT)
19702 Copyright Â© 2013 Matt Diamond
19703 https://github.com/cwilso/AudioRecorder/blob/master/js/recorderjs/recorder.js
19704 */
19705 .factory('b2bRecorder', function() {
19706
19707     var Recorder = function(source, cfg) {
19708         var WORKER_PATH = 'recorderWorker.js';
19709         var config = cfg || {};
19710         var bufferLen = config.bufferLen || 4096;
19711         this.context = source.context;
19712         if(!this.context.createScriptProcessor) {
19713             this.node = this.context.createJavacriptProcessor(bufferLen, 2, 2);
19714         } else {
19715             this.node = this.context.createScriptProcessor(bufferLen, 2, 2);
19716         }
19717         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()}};';
19718         var blob = new Blob([workerCode]);
19719
19720         var worker = new Worker(window.URL.createObjectURL(blob)); //TODO: Use a blob instead
19721         worker.postMessage({
19722             command: 'init',
19723             config: {
19724                 sampleRate: this.context.sampleRate
19725             }
19726         });
19727         var recording = false,
19728             currCallback;
19729
19730         this.node.onaudioprocess = function(e) {
19731             if (!recording) return;
19732             worker.postMessage({
19733                 command: 'record',
19734                 buffer: [
19735                     e.inputBuffer.getChannelData(0),
19736                     e.inputBuffer.getChannelData(1)
19737                 ]
19738             });
19739         };
19740
19741         this.configure = function(cfg) {
19742             for (var prop in cfg) {//TODO: look into using angular.extend() here
19743                 if (cfg.hasOwnProperty(prop)) {
19744                     config[prop] = cfg[prop];
19745                 }
19746             }
19747         };
19748
19749         this.record = function() {
19750             recording = true;
19751         };
19752
19753         this.stop = function() {
19754             recording = false;
19755         };
19756
19757         this.clear = function() {
19758             worker.postMessage({ command: 'clear' });
19759             window.URL.revokeObjectURL(blob);
19760         };
19761
19762         this.getBuffers = function(cb) {
19763             currCallback = cb || config.callback;
19764             worker.postMessage({ command: 'getBuffers' });
19765         };
19766
19767         this.exportWAV = function(cb, type) {
19768             currCallback = cb || config.callback;
19769             type = type || config.type || 'audio/wav';
19770             if (!currCallback) throw new Error('[b2bRecorder]: Callback not set!');
19771             worker.postMessage({
19772                 command: 'exportWAV',
19773                 type: type
19774             });
19775         };
19776
19777         this.exportMonoWAV = function(cb, type) {
19778             currCallback = cb || config.callback;
19779             type = type || config.type || 'audio/wav';
19780             if (!currCallback) throw new Error('[b2bRecorder]: Callback not set!');
19781             worker.postMessage({
19782                 command: 'exportMonoWAV',
19783                 type: type
19784             });
19785         };
19786
19787         worker.onmessage = function(e) {
19788             var blob = e.data;
19789             currCallback(blob);
19790         };
19791
19792         source.connect(this.node);
19793         this.node.connect(this.context.destination); // if the script node is not connected to an output the "onaudioprocess" event is not triggerd in Chrome
19794
19795     };
19796
19797     return Recorder;
19798
19799 })
19800 .factory('b2bViewport', function() {
19801   /* Source: https://gist.github.com/bjankord/2399828 */
19802   var _viewportWidth = function() {
19803     var vpw;
19804     var webkit = (!(window.webkitConvertPointFromNodeToPage == null));
19805     
19806     // Webkit:
19807     if ( webkit ) {
19808       var vpwtest = document.createElement( "div" );
19809       // Sets test div to width 100%, !important overrides any other misc. box model styles that may be set in the CSS
19810       vpwtest.style.cssText = "width:100% !important; margin:0 !important; padding:0 !important; border:none !important;";
19811       document.documentElement.insertBefore( vpwtest, document.documentElement.firstChild );
19812       vpw = vpwtest.offsetWidth;
19813       document.documentElement.removeChild( vpwtest );
19814     }
19815     // IE 6-8:
19816     else if ( window.innerWidth === undefined ) { 
19817       vpw = document.documentElement.clientWidth; 
19818     }
19819     // Other:
19820     else{
19821       vpw =  window.innerWidth;
19822     }
19823
19824     return (vpw);
19825   }
19826   return {
19827     viewportWidth: _viewportWidth
19828   };
19829 })
19830 .directive('b2bWhenScrollEnds', function(b2bWhenScrollEndsConstants, $log) {
19831     return {
19832         restrict: 'A',
19833         link: function (scope, element, attrs) {
19834             /**
19835             * Exposed Attributes:
19836             *       threshold - integer - number of pixels before scrollbar hits end that callback is called
19837             *       width - integer - override for element's width (px)
19838             *       height - integer - override for element's height (px)
19839             *       axis - string - x/y for scroll bar axis
19840             */
19841             var threshold = parseInt(attrs.threshold, 10) || b2bWhenScrollEndsConstants.threshold;
19842
19843             if (!attrs.axis || attrs.axis === '') {
19844                 $log.warn('axis attribute must be defined for b2bWhenScrollEnds.');
19845                 return;
19846             }
19847
19848             if (attrs.axis === 'x') {
19849                 visibleWidth = parseInt(attrs.width, 10) || b2bWhenScrollEndsConstants.width;
19850                 if (element.css('width')) {
19851                     visibleWidth = element.css('width').split('px')[0];  
19852                 }
19853
19854                 element[0].addEventListener('scroll', function() {
19855                     var scrollableWidth = element.prop('scrollWidth');
19856                     if (scrollableWidth === undefined) {
19857                         scrollableWidth = 1;
19858                     }
19859                     var hiddenContentWidth = scrollableWidth - visibleWidth;
19860
19861                     if (hiddenContentWidth - element[0].scrollLeft <= threshold) {
19862                         /* Scroll almost at bottom, load more rows */
19863                         scope.$apply(attrs.b2bWhenScrollEnds);
19864                     }
19865                 });
19866             } else if (attrs.axis === 'y') {
19867                 visibleHeight = parseInt(attrs.height, 10) || b2bWhenScrollEndsConstants.height;
19868                 if (element.css('width')) {
19869                     visibleHeight = element.css('height').split('px')[0]; 
19870                 }
19871
19872                 element[0].addEventListener('scroll', function() {
19873                     var scrollableHeight = element.prop('scrollHeight');
19874                     if (scrollableHeight === undefined) {
19875                         scrollableHeight = 1;
19876                     }
19877                     var hiddenContentHeight = scrollableHeight - visibleHeight;
19878
19879                     if (hiddenContentHeight - element[0].scrollTop <= threshold) {
19880                         /* Scroll almost at bottom, load more rows */
19881                         scope.$apply(attrs.b2bWhenScrollEnds);
19882                     }
19883                 });
19884             }
19885         }
19886     };
19887 })
19888
19889 .factory('$windowBind', ['$window', '$timeout', function($window, $timeout) {
19890     var win = angular.element($window);
19891     var _scroll = function (flag, callbackFunc, scope) {
19892         scope.$watch(flag, function (val) {
19893             $timeout(function () {
19894                 if (val) {
19895                     win.bind('scroll', callbackFunc);
19896                 } else {
19897                     win.unbind('scroll', callbackFunc);
19898                 }
19899             });
19900         });
19901     };
19902
19903     var throttle = function(type, name, obj) {
19904         obj = obj || window;
19905         var running = false;
19906         var func = function() {
19907             if (running) { return; }
19908             running = true;
19909              requestAnimationFrame(function() {
19910                 obj.dispatchEvent(new CustomEvent(name));
19911                 running = false;
19912             });
19913         };
19914         obj.addEventListener(type, func);
19915     };
19916
19917     var _resize = function(callbackFunc, scope) {
19918         throttle("resize", "optimizedResize");
19919         window.addEventListener("optimizedResize", function(event) {
19920             callbackFunc();
19921             //win.bind(event, callbackFunc);
19922             if (!scope.$$phase) {
19923                 scope.$digest();
19924             }
19925         });
19926     };
19927
19928     var _click = function (flag, callbackFunc, scope) {
19929         scope.$watch(flag, function (val) {
19930             $timeout(function () {
19931                 if (val) {
19932                     win.bind('click', callbackFunc);
19933                 } else {
19934                     win.unbind('click', callbackFunc);
19935                 }
19936             });
19937         });
19938     };
19939
19940     var _event = function (event, flag, callbackFunc, scope, timeoutFlag, timeoutValue) {
19941         if (timeoutFlag) {
19942             if (!(timeoutValue)) {
19943                 timeoutValue = 0;
19944             }
19945             scope.$watch(flag, function (newVal, oldVal) {
19946                 if (newVal !== oldVal) {
19947                     $timeout(function () {
19948                         if (newVal) {
19949                             win.bind(event, callbackFunc);
19950                         } else {
19951                             win.unbind(event, callbackFunc);
19952                         }
19953                     }, timeoutValue);
19954                 }
19955             });
19956         } else {
19957             scope.$watch(flag, function (newVal, oldVal) {
19958                 if (newVal !== oldVal) {
19959                     if (newVal) {
19960                         win.bind(event, callbackFunc);
19961                     } else {
19962                         win.unbind(event, callbackFunc);
19963                     }
19964                 }
19965             });
19966         }
19967     };
19968
19969     return {
19970         click: _click,
19971         scroll: _scroll,
19972         event: _event, 
19973         resize: _resize
19974     };
19975 }])
19976
19977 .factory('keymap', function () {
19978     return {
19979         KEY: {
19980             TAB: 9,
19981             ENTER: 13,
19982             ESC: 27,
19983             SPACE: 32,
19984             LEFT: 37,
19985             UP: 38,
19986             RIGHT: 39,
19987             DOWN: 40,
19988             SHIFT: 16,
19989             CTRL: 17,
19990             ALT: 18,
19991             PAGE_UP: 33,
19992             PAGE_DOWN: 34,
19993             HOME: 36,
19994             END: 35,
19995             BACKSPACE: 8,
19996             DELETE: 46,
19997             COMMAND: 91
19998         },
19999         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 : "'"
20000         },
20001         isControl: function (e) {
20002             var k = e.keyCode;
20003             switch (k) {
20004             case this.KEY.COMMAND:
20005             case this.KEY.SHIFT:
20006             case this.KEY.CTRL:
20007             case this.KEY.ALT:
20008                 return true;
20009             default:;
20010             }
20011
20012             if (e.metaKey) {
20013                 return true;
20014             }
20015
20016             return false;
20017         },
20018         isFunctionKey: function (k) {
20019             k = k.keyCode ? k.keyCode : k;
20020             return k >= 112 && k <= 123;
20021         },
20022         isVerticalMovement: function (k) {
20023             return ~[this.KEY.UP, this.KEY.DOWN].indexOf(k);
20024         },
20025         isHorizontalMovement: function (k) {
20026             return ~[this.KEY.LEFT, this.KEY.RIGHT, this.KEY.BACKSPACE, this.KEY.DELETE].indexOf(k);
20027         },
20028         isAllowedKey: function (k) {
20029             return (~[this.KEY.SPACE, this.KEY.ESC, this.KEY.ENTER].indexOf(k)) || this.isHorizontalMovement(k) || this.isVerticalMovement(k);
20030         },
20031         isNumericKey: function (e) {
20032             var k = e.keyCode;
20033             if ((k >= 48 && k <= 57) || (k >= 96 && k <= 105)) {
20034                 return true;
20035             } else {
20036                 return false;
20037             }
20038         },
20039         isAlphaNumericKey: function (e) {
20040             var k = e.keyCode;
20041             if ((k >= 48 && k <= 57) || (k >= 96 && k <= 105) || (k >= 65 && k <= 90)) {
20042                 return true;
20043             } else {
20044                 return false;
20045             }
20046         }
20047     };
20048 })
20049
20050 .factory('$isElement', [function () {
20051     var isElement = function (currentElem, targetElem, alternateElem) {
20052         if (currentElem[0] === targetElem[0]) {
20053             return true;
20054         } else if (currentElem[0] === alternateElem[0]) {
20055             return false;
20056         } else {
20057             return isElement((currentElem.parent()[0] && currentElem.parent()) || targetElem, targetElem, alternateElem);
20058         }
20059     };
20060
20061     return isElement;
20062 }])
20063
20064 .factory('events', function () {
20065     var _stopPropagation = function (evt) {
20066         if (evt.stopPropagation) {
20067             evt.stopPropagation();
20068         } else {
20069             evt.returnValue = false;
20070         }
20071     };
20072     var _preventDefault = function (evt) {
20073         if (evt.preventDefault) {
20074             evt.preventDefault();
20075         } else {
20076             evt.returnValue = false;
20077         }
20078     }
20079     return {
20080         stopPropagation: _stopPropagation,
20081         preventDefault: _preventDefault
20082     };
20083 })
20084
20085
20086 .factory('isHighContrast', function () {
20087     var _isHighContrast = function (idval)
20088
20089
20090      {
20091         var objDiv, objImage, strColor, strWidth, strReady;
20092         var strImageID = idval; // ID of image on the page
20093
20094         // Create a test div
20095         objDiv = document.createElement('div');
20096
20097         //Set its color style to something unusual
20098         objDiv.style.color = 'rgb(31, 41, 59)';
20099
20100         // Attach to body so we can inspect it
20101         document.body.appendChild(objDiv);
20102
20103         // Read computed color value
20104         strColor = document.defaultView ? document.defaultView.getComputedStyle(objDiv, null).color : objDiv.currentStyle.color;
20105         strColor = strColor.replace(/ /g, '');
20106
20107         // Delete the test DIV
20108         document.body.removeChild(objDiv);
20109
20110         // Check if we get the color back that we set. If not, we're in
20111         // high contrast mode.
20112         if (strColor !== 'rgb(31,41,59)') {
20113             return true;
20114         } else {
20115             return false;
20116         }
20117     };
20118
20119     return _isHighContrast;
20120 })
20121
20122 .run(['isHighContrast', '$document', function (isHighContrast, $document) {
20123     var html = $document.find('html').eq(0);
20124     if (isHighContrast()) {
20125         html.addClass('ds2-no-colors');
20126     } else {
20127         html.removeClass('ds2-no-colors');
20128     }
20129 }])
20130
20131 .factory('$documentBind', ['$document', '$timeout', function ($document, $timeout) {
20132     var _click = function (flag, callbackFunc, scope) {
20133         scope.$watch(flag, function (val) {
20134             $timeout(function () {
20135                 if (val) {
20136                     $document.bind('click', callbackFunc);
20137                 } else {
20138                     $document.unbind('click', callbackFunc);
20139                 }
20140             });
20141         });
20142     };
20143
20144     var _touch = function (flag, callbackFunc, scope) {
20145         scope.$watch(flag, function (val) {
20146             $timeout(function () {
20147                 if (val) {
20148                     $document.bind('touchstart', callbackFunc);
20149                 } else {
20150                     $document.unbind('touchstart', callbackFunc);
20151                 }
20152             });
20153         });
20154     };
20155
20156     var _scroll = function (flag, callbackFunc, scope) {
20157         scope.$watch(flag, function (val) {
20158             $timeout(function () {
20159                 if (val) {
20160                     $document.bind('scroll', callbackFunc);
20161                 } else {
20162                     $document.unbind('scroll', callbackFunc);
20163                 }
20164             });
20165         });
20166     };
20167
20168     var _event = function (event, flag, callbackFunc, scope, timeoutFlag, timeoutValue) {
20169         if (timeoutFlag) {
20170             if (!(timeoutValue)) {
20171                 timeoutValue = 0;
20172             }
20173             scope.$watch(flag, function (newVal, oldVal) {
20174                 if (newVal !== oldVal) {
20175                     $timeout(function () {
20176                         if (newVal) {
20177                             $document.bind(event, callbackFunc);
20178                         } else {
20179                             $document.unbind(event, callbackFunc);
20180                         }
20181                     }, timeoutValue);
20182                 }
20183             });
20184         } else {
20185             scope.$watch(flag, function (newVal, oldVal) {
20186                 if (newVal !== oldVal) {
20187                     if (newVal) {
20188                         $document.bind(event, callbackFunc);
20189                     } else {
20190                         $document.unbind(event, callbackFunc);
20191                     }
20192                 }
20193             });
20194         }
20195     };
20196
20197     return {
20198         click: _click,
20199         touch: _touch,
20200         scroll: _scroll,
20201         event: _event
20202     };
20203 }])
20204
20205 .directive('b2bOnlyNums', function (keymap) {
20206     return {
20207         restrict: 'A',
20208         require: 'ngModel',
20209         link: function (scope, elm, attrs, ctrl) {
20210             var maxChars = attrs.b2bOnlyNums ? attrs.b2bOnlyNums : 4;
20211             elm.on('keydown', function (event) {
20212                 if ((event.which >= 48 && event.which <= 57) || (event.which >= 96 && event.which <= 105)) {
20213                     // check for maximum characters allowed
20214                     if (elm.val().length < maxChars){
20215                         return true;
20216                     } else {
20217                         event.preventDefault();
20218                         return false;
20219                     }
20220                 } else if ([8, 9, 13, 27, 37, 38, 39, 40].indexOf(event.which) > -1) {
20221                     // to allow backspace, tab, enter, escape, arrows
20222                     return true;
20223                 } else if (event.altKey || event.ctrlKey) {
20224                     // to allow alter, control, and shift keys
20225                     return true;
20226                 } else {
20227                     // to stop others
20228                     event.preventDefault();
20229                     return false;
20230                 }
20231             });
20232
20233             var validateString = function (value) {
20234                 if (angular.isUndefined(value) || value === null || value === '') {
20235                     return ctrl.$modelValue;
20236                 }
20237                 return value;
20238             };
20239             ctrl.$parsers.unshift(validateString);
20240         }
20241     }
20242 })
20243
20244 .directive('b2bKeyupClick', [ function () {
20245     return {
20246         restrict: 'A',
20247         link: function (scope, elem, attr) {
20248             var keyCode = [];
20249             attr.$observe('b2bKeyupClick', function (value) {
20250                 if (value) {
20251                     keyCode = value.split(',');
20252                 }
20253             });
20254             elem.bind('keydown keyup', function (ev) {
20255                 var keyCodeCondition = function () {
20256                     var flag = false;
20257                     if (!(ev.keyCode)) {
20258                         if (ev.which) {
20259                             ev.keyCode = ev.which;
20260                         } else if (ev.charCode) {
20261                             ev.keyCode = ev.charCode;
20262                         }
20263                     }
20264                     if ((ev.keyCode && keyCode.indexOf(ev.keyCode.toString()) > -1)) {
20265                         flag = true;
20266                     }
20267                     return flag;
20268                 };
20269                 if (ev.type === 'keydown' && keyCodeCondition()) {
20270                     ev.preventDefault();
20271                 }
20272                 else if (ev.type === 'keyup' && keyCodeCondition()) {
20273                     elem[0].click();
20274                 }
20275             });
20276         }
20277     };
20278 }])
20279
20280 .factory('b2bDOMHelper', function() {
20281
20282     var _isTabable = function(node) {
20283         var element = angular.element(node);
20284         var tagName = element[0].tagName.toUpperCase();
20285
20286         if (isHidden(element)) {
20287             return false;
20288         }
20289         if (element.attr('tabindex') !== undefined) {
20290             return (parseInt(element.attr('tabindex'), 10) >= 0);
20291         }
20292         if (tagName === 'A' || tagName === 'AREA' || tagName === 'BUTTON' || tagName === 'INPUT' || tagName === 'TEXTAREA' || tagName === 'SELECT') {
20293             if (tagName === 'A' || tagName === 'AREA') {
20294                 // anchors/areas without href are not focusable
20295                 return (element[0].href !== '');
20296             }
20297             return !(element[0].disabled);
20298         }
20299         return false;
20300     };
20301
20302     function isValidChild(child) {
20303         return child.nodeType == 1 && child.nodeName != 'SCRIPT' && child.nodeName != 'STYLE';
20304     }
20305     
20306     function isHidden(obj) {
20307         var elem = angular.element(obj);
20308         var elemStyle = undefined;
20309         if(obj instanceof HTMLElement){
20310             elemStyle = window.getComputedStyle(obj);
20311         }
20312         else {
20313             elemStyle = window.getComputedStyle(obj[0]);
20314         }
20315         return elem.hasClass('ng-hide') || elem.css('display') === 'none' || elemStyle.display === 'none' || elemStyle.visibility === 'hidden' || elem.css('visibility') === 'hidden';
20316     }
20317
20318     function hasValidParent(obj) {
20319         return (isValidChild(obj) && obj.parentElement.nodeName !== 'BODY');
20320     }
20321
20322     function traverse(obj, fromTop) {
20323         var obj = obj || document.getElementsByTagName('body')[0];
20324         if (isValidChild(obj) && _isTabable(obj)) {
20325             return obj;
20326         }
20327         // If object is hidden, skip it's children
20328         if (isValidChild(obj) && isHidden(obj)) {
20329             return undefined;
20330         } 
20331         // If object is hidden, skip it's children
20332         if (angular.element(obj).hasClass('ng-hide')) {
20333             return undefined;
20334         }  
20335         if (obj.hasChildNodes()) {
20336             var child;
20337             if (fromTop) {
20338                 child = obj.firstChild;
20339             } else {
20340                 child = obj.lastChild;
20341             }
20342             while(child) {
20343                 var res =  traverse(child, fromTop);
20344                 if(res){
20345                     return res;
20346                 }
20347                 else{
20348                     if (fromTop) {
20349                         child = child.nextSibling;
20350                     } else {
20351                         child = child.previousSibling;
20352                     }
20353                 }
20354             }
20355         }
20356         else{
20357             return undefined;
20358         }
20359     }
20360
20361     var _previousElement = function(el, isFocusable){
20362
20363         var elem = el;
20364         if (el.hasOwnProperty('length')) {
20365             elem = el[0];
20366         }
20367
20368         var parent = elem.parentElement;
20369         var previousElem = undefined;
20370
20371         if(isFocusable) {
20372             if (hasValidParent(elem)) {
20373                 var siblings = angular.element(parent).children();
20374                 if (siblings.length > 0) {
20375                     // Good practice to splice out the elem from siblings if there, saving some time.
20376                     // We allow for a quick check for jumping to parent first before removing. 
20377                     if (siblings[0] === elem) {
20378                         // If we are looking at immidiate parent and elem is first child, we need to go higher
20379                         var e = _previousElement(angular.element(elem).parent(), isFocusable);
20380                         if (_isTabable(e)) {
20381                             return e;
20382                         }
20383                     } else {
20384                         // I need to filter myself and any nodes next to me from the siblings
20385                         var indexOfElem = Array.prototype.indexOf.call(siblings, elem);
20386                         siblings = Array.prototype.filter.call(siblings, function(item, itemIndex) {
20387                             if (!angular.equals(elem, item) && itemIndex < indexOfElem) {
20388                                 return true;
20389                             }
20390                         });
20391                     }
20392                     // We need to search backwards
20393                     for (var i = 0; i <= siblings.length-1; i++) {//for (var i = siblings.length-1; i >= 0; i--) {
20394                         var ret = traverse(siblings[i], false);
20395                         if (ret !== undefined) {
20396                             return ret;
20397                         }
20398                     }
20399
20400                     var e = _previousElement(angular.element(elem).parent(), isFocusable);
20401                     if (_isTabable(e)) {
20402                         return e;
20403                     }
20404                 }
20405             }
20406         } else {
20407             var siblings = angular.element(parent).children();
20408             if (siblings.length > 1) {
20409                 // Since indexOf is on Array.prototype and parent.children is a NodeList, we have to use call()
20410                 var index = Array.prototype.indexOf.call(siblings, elem);
20411                 previousElem = siblings[index-1];
20412             }
20413         }
20414         return previousElem;
20415     };
20416
20417     var _lastTabableElement = function(el) {
20418         /* This will return the first tabable element from the parent el */
20419         var elem = el;
20420         if (el.hasOwnProperty('length')) {
20421             elem = el[0];
20422         }
20423
20424         return traverse(elem, false);
20425     };
20426
20427     var _firstTabableElement = function(el) {
20428         /* This will return the first tabable element from the parent el */
20429         var elem = el;
20430         if (el.hasOwnProperty('length')) {
20431             elem = el[0];
20432         }
20433
20434         return traverse(elem, true);
20435     };
20436
20437     var _isInDOM = function(obj) {
20438       return document.documentElement.contains(obj);
20439     }
20440
20441     return {
20442         firstTabableElement: _firstTabableElement,
20443         lastTabableElement: _lastTabableElement,
20444         previousElement: _previousElement,
20445         isInDOM: _isInDOM,
20446         isTabable: _isTabable,
20447         isHidden: isHidden
20448     };
20449 })
20450
20451 .factory('windowOrientation', ['$window', function ($window) {
20452     var _isPotrait = function () {
20453         if ($window.innerHeight > $window.innerWidth) {
20454             return true;
20455         } else {
20456             return false;
20457         }
20458     };
20459     var _isLandscape = function () {
20460         if ($window.innerHeight < $window.innerWidth) {
20461             return true;
20462         } else {
20463             return false;
20464         }
20465     };
20466
20467     return {
20468         isPotrait: _isPotrait,
20469         isLandscape: _isLandscape
20470     };
20471 }])
20472 .directive('b2bNextElement', function() {
20473   return {
20474     restrict: 'A',
20475     transclude: false,
20476     link: function (scope, elem, attr, ctrls) {
20477
20478         var keys = attr.b2bNextElement.split(',');
20479
20480         elem.bind('keydown', function (e) {
20481             var nextElement = elem.next();
20482             if(e.keyCode == 39 || e.keyCode == 40){ // if e.keyCode in keys
20483                 if(nextElement.length) {
20484                     e.preventDefault();
20485                     nextElement[0].focus();
20486                 }
20487             }
20488         });
20489     }
20490   }
20491 })
20492
20493 .directive('b2bAccessibilityClick', [function () {
20494     return {
20495         restrict: 'A',
20496         link: function (scope, elem, attr, ctrl) {
20497             var keyCode = [];
20498             attr.$observe('b2bAccessibilityClick', function (value) {
20499                 if (value) {
20500                     keyCode = value.split(',');
20501                 }
20502             });
20503             elem.bind('keydown keypress', function (ev) {
20504                 var keyCodeCondition = function () {
20505                     var flag = false;
20506                     if (!(ev.keyCode)) {
20507                         if (ev.which) {
20508                             ev.keyCode = ev.which; 
20509                         } else if (ev.charCode) {
20510                             ev.keyCode = ev.charCode;
20511                         }
20512                     }
20513                     if ((ev.keyCode && keyCode.indexOf(ev.keyCode.toString()) > -1)) {
20514                         flag = true;
20515                     }
20516                     return flag;
20517                 };
20518                 if (keyCode.length > 0 && keyCodeCondition()) {
20519                     elem[0].click();
20520                     ev.preventDefault();
20521                 }
20522             });
20523         }
20524     };
20525 }])
20526
20527 .directive('b2bReset', ['$compile', function ($compile) {
20528         return {
20529             restrict: 'A',
20530             require: ['?ngModel', 'b2bReset'],
20531             controller: ['$scope', function ($scope) {
20532                 var resetButton = angular.element('<button type="button" class="reset-field" tabindex="-1" aria-label="Click to reset" aria-hidden="true" role="button"></button>');
20533
20534                 this.getResetButton = function () {
20535                     return resetButton;
20536                 };
20537             }],
20538             link: function (scope, element, attrs, ctrls) {
20539
20540                 var ngModelCtrl = ctrls[0];
20541                 var ctrl = ctrls[1];
20542
20543                 var resetButton = ctrl.getResetButton();
20544
20545
20546                 resetButton.on('click', function () {
20547                     element[0].value = '';
20548
20549                     if (ngModelCtrl) {
20550                         if (attrs.b2bReset) {
20551                             ngModelCtrl.$setViewValue(attrs.b2bReset);
20552                         } else {
20553                             ngModelCtrl.$setViewValue('');
20554                         }
20555                         element[0].value = ngModelCtrl.$viewValue;
20556                         ngModelCtrl.$render();
20557                         scope.$digest();
20558                     }
20559                     element[0].focus();
20560                     element[0].select();
20561                 });
20562
20563                 var addResetButton = function () {
20564                     element.after(resetButton);
20565                     element.unbind('focus input', addResetButton);
20566                 };
20567
20568                 element.bind('focus input', addResetButton);
20569             }
20570         };
20571     }])
20572
20573 .directive('b2bPrevElement', ['b2bDOMHelper', 'keymap', function (b2bDOMHelper, keymap) {
20574   return {
20575     restrict: 'A',
20576     transclude: false,
20577     link: function (scope, elem, attr) {
20578
20579         elem.bind('keydown', function (e) {
20580             if(e.keyCode == 37 || e.keyCode == 38){
20581                 var prev = b2bDOMHelper.previousElement(elem, false);
20582                 if(prev !== undefined) {
20583                     e.preventDefault();
20584                     prev.focus();
20585                 }
20586             }
20587         });
20588     }
20589   }
20590 }])
20591 /**
20592  * @param {integer} delay - Timeout before first and last focusable elements are found
20593  * @param {boolean} trigger - A variable on scope that will trigger refinding first/last focusable elements 
20594  */
20595 .directive('b2bTrapFocusInsideElement', ['$timeout', 'b2bDOMHelper', 'keymap', 'events', function ($timeout, b2bDOMHelper, keymap, events) {
20596     return {
20597         restrict: 'A',
20598         transclude: false,
20599         link: function (scope, elem, attr) {
20600
20601             var delay = parseInt(attr.delay, 10) || 10;
20602
20603             /* Before opening modal, find the focused element */
20604             var firstTabableElement = undefined,
20605                 lastTabableElement = undefined;
20606                 
20607             function init() {
20608                 $timeout(function () {
20609                     firstTabableElement = b2bDOMHelper.firstTabableElement(elem);
20610                     lastTabableElement = b2bDOMHelper.lastTabableElement(elem);
20611                     angular.element(firstTabableElement).bind('keydown', firstTabableElementKeyhandler);
20612                     angular.element(lastTabableElement).bind('keydown', lastTabableElementKeyhandler);
20613                 }, delay, false);
20614             }
20615
20616             if (attr.trigger !== undefined) {
20617                 scope.$watch('trigger', function() {
20618                     if (scope.trigger) {
20619                         init();
20620                     }
20621                 });
20622             }
20623
20624             var firstTabableElementKeyhandler = function(e) {
20625                 if (!e.keyCode) {
20626                     e.keyCode = e.which;
20627                 }
20628                 if (e.keyCode === keymap.KEY.TAB && e.shiftKey) {
20629                     if (attr.trapFocusInsideElement === 'true') {
20630                         var temp = b2bDOMHelper.lastTabableElement(elem);
20631                         if (lastTabableElement !== temp) {
20632                             // Unbind keydown handler on lastTabableElement
20633                             angular.element(lastTabableElement).unbind('keydown', lastTabableElementKeyhandler);
20634                             lastTabableElement = temp;
20635                             angular.element(lastTabableElement).bind('keydown', lastTabableElementKeyhandler);
20636                         }
20637                     }
20638                     lastTabableElement.focus();
20639                     events.preventDefault(e);
20640                     events.stopPropagation(e);
20641                 }
20642             };
20643
20644             var lastTabableElementKeyhandler = function(e) {
20645                 if (!e.keyCode) {
20646                     e.keyCode = e.which;
20647                 }
20648                 if (e.keyCode === keymap.KEY.TAB && !e.shiftKey) {
20649                     if (attr.trapFocusInsideElement === 'true') {
20650                         var temp = b2bDOMHelper.firstTabableElement(elem);
20651                         if (firstTabableElement !== temp) {
20652                             // Unbind keydown handler on firstTabableElement
20653                             angular.element(firstTabableElement).unbind('keydown', firstTabableElementKeyhandler);
20654                             firstTabableElement = temp;
20655                             angular.element(firstTabableElement).bind('keydown', firstTabableElementKeyhandler);
20656                         }
20657                     }
20658                     firstTabableElement.focus();
20659                     events.preventDefault(e);
20660                     events.stopPropagation(e);
20661                 }
20662             };
20663
20664             init();
20665         }
20666     };
20667 }])
20668
20669 .factory('trapFocusInElement', ['$document', '$isElement', 'b2bDOMHelper', 'keymap', '$interval', function ($document, $isElement, b2bDOMHelper, keymap, $interval) {
20670     var elementStack = [];
20671     var stackHead = undefined;
20672     var stopInterval = undefined;
20673     var intervalRequired = false;
20674     var interval = 1000;
20675     var firstTabableElement, lastTabableElement;
20676
20677     var trapKeyboardFocusInFirstElement = function (e) {
20678         if (!e.keyCode) {
20679             e.keyCode = e.which;
20680         }
20681
20682         if (e.shiftKey === true && e.keyCode === keymap.KEY.TAB) {
20683             lastTabableElement[0].focus();
20684             e.preventDefault(e);
20685             e.stopPropagation(e);
20686         }
20687
20688     };
20689
20690     var trapKeyboardFocusInLastElement = function (e) {
20691         if (!e.keyCode) {
20692             e.keyCode = e.which;
20693         }
20694
20695         if (e.shiftKey === false && e.keyCode === keymap.KEY.TAB) {
20696             firstTabableElement[0].focus();
20697             e.preventDefault(e);
20698             e.stopPropagation(e);
20699         }
20700     };
20701
20702     var trapFocusInElement = function (flag, firstTabableElementParam, lastTabableElementParam) {
20703         var bodyElements = $document.find('body').children();
20704
20705         firstTabableElement = firstTabableElementParam ? firstTabableElementParam : angular.element(b2bDOMHelper.firstTabableElement(stackHead));
20706         lastTabableElement = lastTabableElementParam ? lastTabableElementParam : angular.element(b2bDOMHelper.lastTabableElement(stackHead));
20707
20708         if (flag) {
20709             for (var i = 0; i < bodyElements.length; i++) {
20710                 if (bodyElements[i] !== stackHead[0]) {
20711                     bodyElements.eq(i).attr('aria-hidden', true);
20712                 }
20713             }
20714             firstTabableElement.bind('keydown', trapKeyboardFocusInFirstElement);
20715             lastTabableElement.bind('keydown', trapKeyboardFocusInLastElement);
20716         } else {
20717             for (var j = 0; j < bodyElements.length; j++) {
20718                 if (bodyElements[j] !== stackHead[0]) {
20719                     bodyElements.eq(j).removeAttr('aria-hidden');
20720                 }
20721             }
20722             firstTabableElement.unbind('keydown', trapKeyboardFocusInFirstElement);
20723             lastTabableElement.unbind('keydown', trapKeyboardFocusInLastElement);
20724         }
20725
20726         if (intervalRequired && flag) {
20727             stopInterval = $interval(function () {
20728                 var firstTabableElementTemp = angular.element(b2bDOMHelper.firstTabableElement(stackHead));
20729                 var lastTabableElementTemp = angular.element(b2bDOMHelper.lastTabableElement(stackHead));
20730                 if (firstTabableElementTemp[0] !== firstTabableElement[0] || lastTabableElementTemp[0] !== lastTabableElement[0]) {
20731                     $interval.cancel(stopInterval);
20732                     stopInterval = undefined;
20733                     trapFocusInElement(false, firstTabableElement, lastTabableElement);
20734                     trapFocusInElement(true, firstTabableElementTemp, lastTabableElementTemp);
20735                 }
20736             }, interval);
20737         } else {
20738             if (stopInterval) {
20739                 $interval.cancel(stopInterval);
20740                 stopInterval = undefined;
20741             }
20742         }
20743     };
20744     var toggleTrapFocusInElement = function (flag, element, intervalRequiredParam, intervalParam) {
20745         intervalRequired = intervalRequiredParam ? intervalRequiredParam : intervalRequired;
20746         interval = intervalParam ? intervalParam : interval;
20747         if (angular.isDefined(flag) && angular.isDefined(element)) {
20748             if (flag && angular.isUndefined(stackHead)) {
20749                 stackHead = element;
20750                 trapFocusInElement(flag);
20751             } else {
20752                 if (flag) {
20753                     trapFocusInElement(false);
20754                     elementStack.push(stackHead);
20755                     stackHead = element;
20756                     trapFocusInElement(true);
20757                 } else {
20758                     if (angular.isDefined(stackHead) && (stackHead[0] === element[0])) {
20759                         trapFocusInElement(false);
20760                         stackHead = elementStack.pop();
20761                         if (angular.isDefined(stackHead)) {
20762                             trapFocusInElement(true);
20763                         }
20764                     }
20765                 }
20766             }
20767         } else {
20768             if (angular.isDefined(stackHead)) {
20769                 trapFocusInElement(false, firstTabableElement, lastTabableElement);
20770                 trapFocusInElement(true);
20771             }
20772         }
20773     };
20774
20775     return toggleTrapFocusInElement;
20776 }])
20777 .factory('draggedElement', function(){
20778     var draggedElement;
20779     return {
20780         setElement: function(data){
20781             draggedElement = data;
20782         },
20783         getElement: function(){
20784             return draggedElement;
20785         }
20786     }
20787 })
20788
20789 .directive('draggable', ['draggedElement',function (draggedElement) { 
20790     return function(scope, element) { 
20791  
20792       element[0].draggable = true; 
20793  
20794       element.bind('dragstart', function(e) {
20795         draggedElement.setElement(this.parentElement.parentElement); 
20796         e.dataTransfer.effectAllowed = 'move'; 
20797         e.dataTransfer.setDragImage(this.parentElement.parentElement, 0, 0); 
20798         this.parentElement.parentElement.classList.add('b2-drag-element');
20799         return false; 
20800       }); 
20801  
20802       element.bind('dragend', function(e) { 
20803         draggedElement.setElement(e); 
20804         this.parentElement.parentElement.classList.remove('b2-drag-element'); 
20805         return false; 
20806       });
20807     }; 
20808 }]) 
20809  
20810 .directive('droppable', ['draggedElement',function (draggedElement) { 
20811     return { 
20812         restrict: 'EA', 
20813         replace: true, 
20814         scope: { 
20815           rowData: '=' 
20816         }, 
20817         link: function(scope, element, attr) {
20818             if(attr.droppable === 'true') {
20819               element.bind('dragover', function(e) { 
20820                 e.dataTransfer.dropEffect = 'move'; 
20821                 this.classList.add('b2b-drag-over') 
20822                 if (e.preventDefault) e.preventDefault(); // allows us to drop 
20823                 return false; 
20824               }); 
20825
20826               element.bind('dragstart', function(e) {
20827                 if(!e.target.parentElement.classList.contains('b2b-draggable')) {
20828                     e.preventDefault();
20829                     return false;
20830                 }
20831               }); 
20832
20833               element.bind('dragenter', function(e) { 
20834                 if(e.target.getAttribute('droppable') ==='true') {
20835                     this.click();
20836                 }
20837               });
20838
20839               element.bind('dragleave', function(e) { 
20840                 this.classList.remove('b2b-drag-over'); 
20841                 return false; 
20842               });
20843
20844               element.bind('drop', function(e) { 
20845                 var ele = draggedElement.getElement();
20846                 if (e.stopPropagation) e.stopPropagation(); 
20847                 if (e.preventDefault) e.preventDefault(); 
20848                 this.classList.remove('b2b-drag-over'); 
20849
20850                 if(ele && ele.hasAttribute('data-index')){
20851                     var element = scope.rowData[parseInt(ele.getAttribute('data-index'))]; 
20852                     if(element !== undefined) { 
20853                         scope.rowData.splice(parseInt(ele.getAttribute('data-index')), 1); 
20854                         scope.rowData.splice(parseInt(e.currentTarget.getAttribute('data-index')), 0 , element); 
20855                     }
20856                 }
20857                 scope.$apply(); 
20858      
20859                 return false; 
20860               }); 
20861           }
20862         } 
20863     } 
20864 }])
20865 .directive('b2bSetNextFocusOn', ['b2bDOMHelper', '$timeout', function(b2bDOMHelper, $timeout) {
20866     return {
20867         restrict: 'A',
20868         scope: true,
20869         link: function (scope, elem, attr) {
20870             elem.bind('click', function(){
20871                 var firstFocusableElement = undefined; 
20872                 var containerElem = undefined; 
20873                 var containerArray = [];
20874                 var timeout = parseInt(attr.setNextFocusTimeout, 0) | 100;
20875                 var index = parseInt(attr.b2bSetNextFocusIndex, 0) | 0;
20876
20877                                  /*
20878                                   *Fix for IE7 and lower 
20879                                   *polyfill src: https://github.com/HubSpot/pace/issues/102
20880                                   */
20881                                 if (!document.querySelectorAll) {
20882                                         document.querySelectorAll = function (selectors) {
20883                                                 var style = document.createElement('style'), elements = [], element;
20884                                                 document.documentElement.firstChild.appendChild(style);
20885                                                 document._qsa = [];
20886
20887                                                 style.styleSheet.cssText = selectors + '{x-qsa:expression(document._qsa && document._qsa.push(this))}';
20888                                                 window.scrollBy(0, 0);
20889                                                 style.parentNode.removeChild(style);
20890
20891                                                 while (document._qsa.length) {
20892                                                         element = document._qsa.shift();
20893                                                         element.style.removeAttribute('x-qsa');
20894                                                         elements.push(element);
20895                                                 }
20896                                                 document._qsa = null;
20897                                                 return elements;
20898                                         };
20899                                 }
20900
20901                 if (attr.b2bSetNextFocusOn === '') {
20902                     return;
20903                 } else {
20904                     containerArray = attr.b2bSetNextFocusOn.split(' ');
20905                 }
20906                 $timeout(function(){
20907                     var i = 0;
20908                     do { // cycles thru containerArray until finds a match in DOM to set focus to
20909                         containerElem = document.querySelectorAll(containerArray[i])[index]; 
20910                         i++;
20911                     } while ( (!containerElem) && (i < containerArray.length) );
20912                     if(containerElem){
20913                         if (!angular.isDefined(firstFocusableElement)) { 
20914                             firstFocusableElement = b2bDOMHelper.firstTabableElement(containerElem); 
20915                         }
20916                         firstFocusableElement.focus(); 
20917                     }
20918                 }, timeout, false)
20919             });
20920         }
20921
20922     };
20923 }])
20924
20925 .directive('b2bInputAllow', [function() {
20926     return {
20927         restrict: 'A',
20928         require: 'ngModel',
20929         link: function (scope, elem, attr, ctrl) {
20930             var regexExpression = null;
20931             attr.$observe('b2bInputAllow', function (value) {
20932                 if (value) {
20933                     regexExpression = new RegExp(value);
20934                 }
20935             });
20936             var isValid = function(str) {
20937                 if (regexExpression !== null) {
20938                     return regexExpression.test(str);
20939                 }
20940                 return false;
20941             };
20942             elem.bind('keypress', function($event) {
20943                 var charcode = String.fromCharCode($event.which || $event.keyCode);
20944                 if (!isValid(charcode)) {
20945                     $event.preventDefault();
20946                     $event.stopPropagation();
20947                 }
20948             });
20949             elem.bind('input', function (evt) {
20950                 var inputString = ctrl.$viewValue;
20951                 if (isValid(inputString)) {
20952                     ctrl.$setViewValue(inputString);
20953                     ctrl.$render();
20954                     scope.$apply();
20955                 }
20956             });
20957         }
20958     };
20959 }])
20960
20961 .directive('b2bInputDeny', [function() {
20962     return {
20963         restrict: 'A',
20964         require: 'ngModel',
20965         link: function (scope, elem, attr, ctrl) {
20966             var regexExpression = null;
20967             attr.$observe('b2bInputDeny', function (value) {
20968                 if (value) {
20969                     regexExpression = new RegExp(value, 'g');
20970                 }
20971             });
20972             elem.bind('input', function () {
20973                 var inputString = ctrl.$viewValue && ctrl.$viewValue.replace(regexExpression, '');
20974                 if (inputString !== ctrl.$viewValue) {
20975                     ctrl.$setViewValue(inputString);
20976                     ctrl.$render();
20977                     scope.$apply();
20978                 }
20979             });
20980         }
20981     };
20982 }])
20983
20984 .directive('b2bDragonInput', [function() {
20985     return {
20986         restrict: 'A',
20987         require: 'ngModel',
20988         link: function (scope, elem, attr, ctrl) {
20989             elem.on('focus keyup', function(){
20990                 elem.triggerHandler('change');
20991             });
20992         }
20993     };
20994 }])
20995
20996 .directive('b2bKey', ['b2bUtilitiesConfig', '$timeout', 'keymap', function (b2bUtilitiesConfig, $timeout, keymap) {
20997     return {
20998         restrict: 'EA',
20999         controller: ['$scope', '$element', '$attrs', function ($scope, $element,attr) {
21000             this.childElements = [];
21001             this.disableNodes = {};
21002             this.enableSearch = attr.enableSearch !== undefined ? true : b2bUtilitiesConfig.enableSearch;
21003             this.circularTraversal = attr.circularTraversal !== undefined ? true : b2bUtilitiesConfig.circularTraversal;
21004             this.counter = -1;
21005             if (this.enableSearch) {
21006                 this.searchKeys = [];
21007             }
21008             var searchString = '';
21009
21010             var selfCtrl = this;
21011
21012             this.childElementsList = [];
21013
21014             this.b2bKeyID = "";
21015
21016             if (angular.isDefined(attr.b2bKey)) {
21017                 this.b2bKeyID = attr.b2bKey;
21018             }
21019
21020             this.calculateChildElementsList = function () {
21021                 return $element[0].querySelectorAll("[b2b-key-item='" + this.b2bKeyID + "']:not([disabled])");
21022             };
21023
21024             this.resetChildElementsList = function () {
21025                 return $timeout(function () {
21026                     selfCtrl.childElementsList = selfCtrl.calculateChildElementsList();
21027                 });
21028             };
21029
21030             this.resetChildElementsList();
21031
21032             $scope.$on('b2b-key-reset-child-elements-list', function () {
21033                 selfCtrl.resetChildElementsList();
21034             });
21035
21036
21037             this.registerElement = function (childElement, searchKey) {
21038                 this.childElements.push(childElement);
21039                 if (this.enableSearch) {
21040                     this.searchKeys.push(searchKey);
21041                 }
21042                 var count = this.childElements.length - 1;
21043                 this.maxLength = count + 1;
21044                 return count;
21045             };
21046             this.toggleDisable = function (count, state) {
21047                 this.disableNodes[count] = state;
21048             };
21049             this.searchElement = function (searchExp) {
21050                 var regex = new RegExp("\\b" + searchExp, "gi");
21051                 var position = this.searchKeys.regexIndexOf(regex, this.counter + 1, true);
21052                 if (position > -1) {
21053                     this.counter = position;
21054                     this.moveFocus(this.counter);
21055                 }
21056             };
21057             this.startTimer = function (time) {
21058                 if (searchString === '') {
21059                     $timeout(function () {
21060                         searchString = '';
21061                     }, time);
21062                 }
21063             };
21064             this.resetCounter = function (count) {
21065                 this.counter = count;
21066             };
21067             this.moveNext = function (count) {
21068                 this.counter = (this.counter + count) < this.maxLength ? this.counter + count : (this.circularTraversal ? 0 : this.counter);
21069                 if (this.disableNodes[this.counter]) {
21070                     if ((this.counter + count) < this.maxLength) {
21071                         this.moveNext(count);
21072                     }
21073                 } else {
21074                     this.moveFocus(this.counter);
21075                 }
21076             };
21077             this.movePrev = function (count) {
21078                 this.counter = (this.counter - count) > -1 ? this.counter - count : (this.circularTraversal ? this.maxLength-1 : this.counter);
21079                 if (this.disableNodes[this.counter]) {
21080                     if ((this.counter - count) > -1) {
21081                         this.movePrev(count);
21082                     }
21083                 } else {
21084                     this.moveFocus(this.counter);
21085                 }
21086             };
21087             this.moveFocus = function (index) {
21088                 this.childElements[index][0].focus();
21089             };
21090
21091             this.keyDownHandler = function (ev, count) {
21092                 if (angular.isDefined(count) && !isNaN(count) && count !== this.counter) {
21093                     this.resetCounter(count);
21094                 }
21095                 if (!ev.keyCode) {
21096                     if (ev.which) {
21097                         ev.keyCode = ev.which;
21098                     } else if (ev.charCode) {
21099                         ev.keyCode = ev.charCode;
21100                     }
21101                 }
21102                 if (ev.keyCode) {
21103                     if (this.prev && this.prev.indexOf(ev.keyCode.toString()) > -1) {
21104                         this.movePrev(1);
21105                         ev.preventDefault();
21106                         ev.stopPropagation();
21107                     } else if (this.next && this.next.indexOf(ev.keyCode.toString()) > -1) {
21108                         this.moveNext(1);
21109                         ev.preventDefault();
21110                         ev.stopPropagation();
21111                     } else if (this.up && this.up.indexOf(ev.keyCode.toString()) > -1) {
21112                         if (this.type === 'table') {
21113                             this.movePrev(this.columns);
21114                             ev.preventDefault();
21115                             ev.stopPropagation();
21116                         }
21117                     } else if (this.down && this.down.indexOf(ev.keyCode.toString()) > -1) {
21118                         if (this.type === 'table') {
21119                             this.moveNext(this.columns);
21120                             ev.preventDefault();
21121                             ev.stopPropagation();
21122                         }
21123                     } else if (ev.keyCode === keymap.KEY.HOME) {
21124                         var firstIndex = 0;
21125                         while (this.disableNodes[firstIndex] !== false) {
21126                             firstIndex++;
21127                         };
21128                         var count = this.counter - firstIndex;
21129                         this.movePrev(count);
21130                         ev.preventDefault();
21131                         ev.stopPropagation();
21132                     } else if (ev.keyCode === keymap.KEY.END) {
21133                         var lastIndex = this.childElements.length - 1;
21134                         while (this.disableNodes[lastIndex] !== false) {
21135                             lastIndex--;
21136                         };
21137                         var count = lastIndex - this.counter;
21138                         this.moveNext(count);
21139                         ev.preventDefault();
21140                         ev.stopPropagation();
21141                     } else if (ev.keyCode >= 48 && ev.keyCode <= 105) {
21142                         if (this.enableSearch) {
21143                             this.startTimer(b2bUtilitiesConfig.searchTimer);
21144                             searchString = searchString + (keymap.MAP[ev.keyCode] || '');
21145                             this.searchElement(searchString);
21146                             ev.preventDefault();
21147                             ev.stopPropagation();
21148                         }
21149                     }
21150                 }
21151             };
21152         }],
21153         link: function (scope, elem, attr, ctrl) {
21154             ctrl.prev = attr.prev ? attr.prev.split(',') : b2bUtilitiesConfig.prev.split(',');
21155             ctrl.next = attr.next ? attr.next.split(',') : b2bUtilitiesConfig.next.split(',');
21156             ctrl.type = attr.type ? attr.type : b2bUtilitiesConfig.type;
21157             if (ctrl.type === 'table') {
21158                 ctrl.up = attr.up ? attr.up.split(',') : b2bUtilitiesConfig.up.split(',');
21159                 ctrl.down = attr.down ? attr.down.split(',') : b2bUtilitiesConfig.down.split(',');
21160                 ctrl.columns = attr.columns ? parseInt(attr.columns, 10) : b2bUtilitiesConfig.columns;
21161             }
21162
21163             elem.bind('keydown', function (ev) {
21164                 ctrl.keyDownHandler(ev);
21165             });
21166         }
21167     };
21168 }])
21169
21170 .directive('b2bKeyItem', [function () {
21171     return {
21172         restrict: 'EA',
21173         link: function (scope, elem, attr, ctrl) {
21174             var parentCtrl = (elem.parent() && elem.parent().controller('b2bKey')) || undefined;
21175             if (angular.isDefined(parentCtrl)) {
21176                 var count = parentCtrl.registerElement(elem, attr.searchKey);
21177                 elem.bind('keydown', function (ev) {
21178                     parentCtrl.keyDownHandler(ev, count);
21179                 });
21180                 scope.$watch(attr.b2bKeyItem, function (value) {
21181                     value = value === undefined ? true : value;
21182                     parentCtrl.toggleDisable(count, !value); 
21183                 });
21184                 scope.$on('$destroy', function () {
21185                     parentCtrl.toggleDisable(count, true);
21186                 });
21187             }
21188         }
21189     };
21190 }])
21191
21192 .directive('b2bElementFocus', [function () {
21193     return {
21194         restrict: 'A',
21195         link: function (scope, elem, attr, ctrl) {
21196             scope.$watch(attr.b2bElementFocus, function (value) {
21197                 if (value === true) {
21198                     elem[0].focus();
21199                 }
21200             });
21201         }
21202     };
21203 }])
21204
21205
21206 .directive('b2bAppendElement', ['$compile', function ($compile) {
21207     return {
21208         restrict: 'A',
21209         link: function (scope, elem, attr, ctrl) {
21210             var parameters = attr.b2bAppendElement.split(':');
21211             if (parameters.length === 1) {
21212                 elem.append(scope.$eval(parameters[0]));
21213             } else if (parameters.length === 2) {
21214                 if (parameters[1] === 'compile') {
21215                     var element = angular.element('<span>' + scope.$eval(parameters[0]) + '</span>');
21216                     elem.append($compile(element)(scope));
21217                 }
21218             }
21219
21220         }
21221     };
21222 }])
21223
21224 .directive('b2bKeyItemRefreshInNgRepeat', [function () {
21225     return {
21226         restrict: 'EA',
21227         require: '^^b2bKey',
21228         link: function (scope, elem, attr, parentCtrl) {
21229             if (angular.isDefined(parentCtrl)) {
21230
21231                 var attrToObserve = 'attrToObserve';
21232
21233                 if (attr.b2bKeyItemRefreshInNgRepeat) {
21234                     attrToObserve = 'b2bKeyItemRefreshInNgRepeat';
21235                 }
21236
21237                 attr.$observe(attrToObserve, function (newVal, oldVal) {
21238                     if (newVal && newVal !== oldVal) {
21239                         parentCtrl.resetChildElementsList();
21240                     }
21241                 });
21242             }
21243         }
21244     };
21245 }])
21246
21247 .constant('b2bMaskConfig', {
21248     maskDefinitions: {
21249         '9': /\d/,
21250         'A': /[a-zA-Z]/,
21251         '*': /[a-zA-Z0-9]/
21252     },
21253     clearOnBlur: false,
21254     clearOnBlurPlaceholder: false,
21255     escChar: '\\',
21256     eventsToHandle: ['input', 'keyup', 'click', 'focus'],
21257     addDefaultPlaceholder: true,
21258     allowInvalidValue: true
21259 })
21260 /**
21261  * @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.
21262  * @param {String} maskPlaceholder - Allows customizing the mask placeholder when a user has focused the input element and while typing in their value
21263  * @param {String} maskPlaceholderChar - Allows customizing the mask placeholder character. The default mask placeholder is _.
21264  * @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.
21265  */
21266 .directive('b2bMask', ['b2bMaskConfig', function(b2bMaskConfig) {
21267     return {
21268         require: 'ngModel',
21269         restrict: 'A',
21270         link: function(scope, element, attrs, ctrl) {
21271             var maskProcessed = false, eventsBound = false,
21272                 maskCaretMap, maskPatterns, maskPlaceholder, maskComponents,
21273                 // Minimum required length of the value to be considered valid
21274                 minRequiredLength,
21275                 value, valueMasked, isValid,
21276                 // Vars for initializing/uninitializing
21277                 originalPlaceholder = attrs.placeholder,
21278                 originalMaxlength = attrs.maxlength,
21279                 // Vars used exclusively in eventHandler()
21280                 oldValue, oldValueUnmasked, oldCaretPosition, oldSelectionLength,
21281                 // Used for communicating if a backspace operation should be allowed between
21282                 // keydownHandler and eventHandler
21283                 preventBackspace;
21284
21285             var options = b2bMaskConfig;
21286
21287             function isFocused (elem) {
21288               return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
21289             }
21290
21291             var originalIsEmpty = ctrl.$isEmpty;
21292             ctrl.$isEmpty = function(value) {
21293                 if (maskProcessed) {
21294                     return originalIsEmpty(unmaskValue(value || ''));
21295                 } else {
21296                     return originalIsEmpty(value);
21297                 }
21298             };
21299
21300             function initialize(maskAttr) {
21301                 if (!angular.isDefined(maskAttr)) {
21302                     return uninitialize();
21303                 }
21304                 processRawMask(maskAttr);
21305                 if (!maskProcessed) {
21306                     return uninitialize();
21307                 }
21308                 initializeElement();
21309                 bindEventListeners();
21310                 return true;
21311             }
21312
21313             function initPlaceholder(placeholderAttr) {
21314                 if ( ! placeholderAttr) {
21315                     return;
21316                 }
21317                 maskPlaceholder = placeholderAttr;
21318                 /* If the mask is processed, then we need to update the value
21319                    but don't set the value if there is nothing entered into the element
21320                    and there is a placeholder attribute on the element because that
21321                    will only set the value as the blank maskPlaceholder
21322                    and override the placeholder on the element */
21323                 if (maskProcessed && !(element.val().length === 0 && angular.isDefined(attrs.placeholder))) {
21324                     element.val(maskValue(unmaskValue(element.val())));
21325                 }
21326             }
21327
21328             function initPlaceholderChar() {
21329                 return initialize(attrs.uiMask);
21330             }
21331
21332             var modelViewValue = false;
21333
21334             attrs.$observe('modelViewValue', function(val) {
21335                 if (val === 'true') {
21336                     modelViewValue = true;
21337                 }
21338             });
21339
21340             attrs.$observe('allowInvalidValue', function(val) {
21341                 linkOptions.allowInvalidValue = val === ''? true : !!val;
21342                 formatter(ctrl.$modelValue);
21343             });
21344
21345             function formatter(fromModelValue) {
21346                 if (!maskProcessed) {
21347                     return fromModelValue;
21348                 }
21349                 value = unmaskValue(fromModelValue || '');
21350                 isValid = validateValue(value);
21351                 ctrl.$setValidity('mask', isValid);
21352
21353                 if (!value.length) return undefined;
21354                 if (isValid || linkOptions.allowInvalidValue) {
21355                     return maskValue(value);
21356                 } else {
21357                     return undefined;
21358                 }
21359             }
21360
21361             function parser(fromViewValue) {
21362                 if (!maskProcessed) {
21363                     return fromViewValue;
21364                 }
21365                 value = unmaskValue(fromViewValue || '');
21366                 isValid = validateValue(value);
21367                 /* We have to set viewValue manually as the reformatting of the input
21368                    value performed by eventHandler() doesn't happen until after
21369                    this parser is called, which causes what the user sees in the input
21370                    to be out-of-sync with what the ctrl's $viewValue is set to. */
21371                 ctrl.$viewValue = value.length ? maskValue(value) : '';
21372                 ctrl.$setValidity('mask', isValid);
21373
21374                 if (isValid || linkOptions.allowInvalidValue) {
21375                     return modelViewValue ? ctrl.$viewValue : value;
21376                 }
21377             }
21378
21379             var linkOptions = {};
21380
21381             // to do 
21382             if (attrs.b2bMaskOptions) {
21383                 linkOptions = scope.$eval('[' + attrs.b2bMaskOptions + ']');
21384                 if (angular.isObject(linkOptions[0])) {
21385                     // we can't use angular.copy nor angular.extend, they lack the power to do a deep merge
21386                     linkOptions = (function(original, current) {
21387                         for (var i in original) {
21388                             if (Object.prototype.hasOwnProperty.call(original, i)) {
21389                                 if (current[i] === undefined) {
21390                                     current[i] = angular.copy(original[i]);
21391                                 } else {
21392                                     if (angular.isObject(current[i]) && !angular.isArray(current[i])) {
21393                                         current[i] = angular.extend({}, original[i], current[i]);
21394                                     }
21395                                 }
21396                             }
21397                         }
21398                         return current;
21399                     })(options, linkOptions[0]);
21400                 } else {
21401                     linkOptions = options;  //gotta be a better way to do this..
21402                 }
21403             } else {
21404                 linkOptions = options;
21405             }
21406
21407             attrs.$observe('b2bMask', initialize);
21408             if (angular.isDefined(attrs.maskPlaceholder)) {
21409                 attrs.$observe('maskPlaceholder', initPlaceholder);
21410             }
21411             else {
21412                 attrs.$observe('placeholder', initPlaceholder);
21413             }
21414             if (angular.isDefined(attrs.maskPlaceholderChar)) {
21415                 attrs.$observe('maskPlaceholderChar', initPlaceholderChar);
21416             }
21417
21418             ctrl.$formatters.unshift(formatter);
21419             ctrl.$parsers.unshift(parser);
21420
21421             function uninitialize() {
21422                 maskProcessed = false;
21423                 unbindEventListeners();
21424
21425                 if (angular.isDefined(originalPlaceholder)) {
21426                     element.attr('placeholder', originalPlaceholder);
21427                 } else {
21428                     element.removeAttr('placeholder');
21429                 }
21430
21431                 if (angular.isDefined(originalMaxlength)) {
21432                     element.attr('maxlength', originalMaxlength);
21433                 } else {
21434                     element.removeAttr('maxlength');
21435                 }
21436
21437                 element.val(ctrl.$modelValue);
21438                 ctrl.$viewValue = ctrl.$modelValue;
21439                 return false;
21440             }
21441
21442             function initializeElement() {
21443                 value = oldValueUnmasked = unmaskValue(ctrl.$modelValue || '');
21444                 valueMasked = oldValue = maskValue(value);
21445                 isValid = validateValue(value);
21446                 if (attrs.maxlength) { // Double maxlength to allow pasting new val at end of mask
21447                     element.attr('maxlength', maskCaretMap[maskCaretMap.length - 1] * 2);
21448                 }
21449                 if ( ! originalPlaceholder && linkOptions.addDefaultPlaceholder) {
21450                     element.attr('placeholder', maskPlaceholder);
21451                 }
21452                 var viewValue = ctrl.$modelValue;
21453                 var idx = ctrl.$formatters.length;
21454                 while(idx--) {
21455                     viewValue = ctrl.$formatters[idx](viewValue);
21456                 }
21457                 ctrl.$viewValue = viewValue || '';
21458                 ctrl.$render();
21459             }
21460
21461             function bindEventListeners() {
21462                 if (eventsBound) {
21463                     return;
21464                 }
21465                 element.bind('blur', blurHandler);
21466                 element.bind('mousedown mouseup', mouseDownUpHandler);
21467                 element.bind('keydown', keydownHandler);
21468                 element.bind(linkOptions.eventsToHandle.join(' '), eventHandler);
21469                 eventsBound = true;
21470             }
21471
21472             function unbindEventListeners() {
21473                 if (!eventsBound) {
21474                     return;
21475                 }
21476                 element.unbind('blur', blurHandler);
21477                 element.unbind('mousedown', mouseDownUpHandler);
21478                 element.unbind('mouseup', mouseDownUpHandler);
21479                 element.unbind('keydown', keydownHandler);
21480                 element.unbind('input', eventHandler);
21481                 element.unbind('keyup', eventHandler);
21482                 element.unbind('click', eventHandler);
21483                 element.unbind('focus', eventHandler);
21484                 eventsBound = false;
21485             }
21486
21487             function validateValue(value) {
21488                 // Zero-length value validity is ngRequired's determination
21489                 return value.length ? value.length >= minRequiredLength : true;
21490             }
21491
21492              function unmaskValue(value) {
21493                 var valueUnmasked = '',
21494                     input = element[0],
21495                     maskPatternsCopy = maskPatterns.slice(),
21496                     selectionStart = oldCaretPosition,
21497                     selectionEnd = selectionStart + getSelectionLength(input),
21498                     valueOffset, valueDelta, tempValue = '';
21499                 // Preprocess by stripping mask components from value
21500                 value = value.toString();
21501                 valueOffset = 0;
21502                 valueDelta = value.length - maskPlaceholder.length;
21503                 angular.forEach(maskComponents, function(component) {
21504                     var position = component.position;
21505                     //Only try and replace the component if the component position is not within the selected range
21506                     //If component was in selected range then it was removed with the user input so no need to try and remove that component
21507                     if (!(position >= selectionStart && position < selectionEnd)) {
21508                         if (position >= selectionStart) {
21509                             position += valueDelta;
21510                         }
21511                         if (value.substring(position, position + component.value.length) === component.value) {
21512                             tempValue += value.slice(valueOffset, position);// + value.slice(position + component.value.length);
21513                             valueOffset = position + component.value.length;
21514                         }
21515                     }
21516                 });
21517                 value = tempValue + value.slice(valueOffset);
21518                 angular.forEach(value.split(''), function(chr) {
21519                     if (maskPatternsCopy.length && maskPatternsCopy[0].test(chr)) {
21520                         valueUnmasked += chr;
21521                         maskPatternsCopy.shift();
21522                     }
21523                 });
21524
21525                 return valueUnmasked;
21526             }
21527
21528             function maskValue(unmaskedValue) {
21529                 var valueMasked = '',
21530                         maskCaretMapCopy = maskCaretMap.slice();
21531
21532                 angular.forEach(maskPlaceholder.split(''), function(chr, i) {
21533                     if (unmaskedValue.length && i === maskCaretMapCopy[0]) {
21534                         valueMasked += unmaskedValue.charAt(0) || '_';
21535                         unmaskedValue = unmaskedValue.substr(1);
21536                         maskCaretMapCopy.shift();
21537                     }
21538                     else {
21539                         valueMasked += chr;
21540                     }
21541                 });
21542                 return valueMasked;
21543             }
21544
21545             function getPlaceholderChar(i) {
21546                 var placeholder = angular.isDefined(attrs.uiMaskPlaceholder) ? attrs.uiMaskPlaceholder : attrs.placeholder,
21547                     defaultPlaceholderChar;
21548
21549                 if (angular.isDefined(placeholder) && placeholder[i]) {
21550                     return placeholder[i];
21551                 } else {
21552                     defaultPlaceholderChar = angular.isDefined(attrs.uiMaskPlaceholderChar) && attrs.uiMaskPlaceholderChar ? attrs.uiMaskPlaceholderChar : '_';
21553                     return (defaultPlaceholderChar.toLowerCase() === 'space') ? ' ' : defaultPlaceholderChar[0];
21554                 }
21555             }
21556
21557             /* Generate array of mask components that will be stripped from a masked value
21558                before processing to prevent mask components from being added to the unmasked value.
21559                E.g., a mask pattern of '+7 9999' won't have the 7 bleed into the unmasked value. */
21560             function getMaskComponents() {
21561                 var maskPlaceholderChars = maskPlaceholder.split(''),
21562                         maskPlaceholderCopy, components;
21563
21564                 /* maskCaretMap can have bad values if the input has the ui-mask attribute implemented as an obversable property, e.g. the demo page */
21565                 if (maskCaretMap && !isNaN(maskCaretMap[0])) {
21566                     /* Instead of trying to manipulate the RegEx based on the placeholder characters
21567                        we can simply replace the placeholder characters based on the already built
21568                        maskCaretMap to underscores and leave the original working RegEx to get the proper
21569                        mask components */
21570                     angular.forEach(maskCaretMap, function(value) {
21571                         maskPlaceholderChars[value] = '_';
21572                     });
21573                 }
21574                 maskPlaceholderCopy = maskPlaceholderChars.join('');
21575                 components = maskPlaceholderCopy.replace(/[_]+/g, '_').split('_');
21576                 components = components.filter(function(s) {
21577                     return s !== '';
21578                 });
21579
21580                 /* need a string search offset in cases where the mask contains multiple identical components
21581                    E.g., a mask of 99.99.99-999.99 */
21582                 var offset = 0;
21583                 return components.map(function(c) {
21584                     var componentPosition = maskPlaceholderCopy.indexOf(c, offset);
21585                     offset = componentPosition + 1;
21586                     return {
21587                         value: c,
21588                         position: componentPosition
21589                     };
21590                 });
21591             }
21592
21593             function processRawMask(mask) {
21594                 var characterCount = 0;
21595
21596                 maskCaretMap = [];
21597                 maskPatterns = [];
21598                 maskPlaceholder = '';
21599
21600                 if (angular.isString(mask)) {
21601                     minRequiredLength = 0;
21602
21603                     var isOptional = false,
21604                             numberOfOptionalCharacters = 0,
21605                             splitMask = mask.split('');
21606
21607                     var inEscape = false;
21608                     angular.forEach(splitMask, function(chr, i) {
21609                         if (inEscape) {
21610                             inEscape = false;
21611                             maskPlaceholder += chr;
21612                             characterCount++;
21613                         }
21614                         else if (linkOptions.escChar === chr) {
21615                             inEscape = true;
21616                         }
21617                         else if (linkOptions.maskDefinitions[chr]) {
21618                             maskCaretMap.push(characterCount);
21619
21620                             maskPlaceholder += getPlaceholderChar(i - numberOfOptionalCharacters);
21621                             maskPatterns.push(linkOptions.maskDefinitions[chr]);
21622
21623                             characterCount++;
21624                             if (!isOptional) {
21625                                 minRequiredLength++;
21626                             }
21627
21628                             isOptional = false;
21629                         }
21630                         else if (chr === '?') {
21631                             isOptional = true;
21632                             numberOfOptionalCharacters++;
21633                         }
21634                         else {
21635                             maskPlaceholder += chr;
21636                             characterCount++;
21637                         }
21638                     });
21639                 }
21640                 // Caret position immediately following last position is valid.
21641                 maskCaretMap.push(maskCaretMap.slice().pop() + 1);
21642
21643                 maskComponents = getMaskComponents();
21644                 maskProcessed = maskCaretMap.length > 1 ? true : false;
21645             }
21646
21647             var prevValue = element.val();
21648             function blurHandler() {
21649                 if (linkOptions.clearOnBlur || ((linkOptions.clearOnBlurPlaceholder) && (value.length === 0) && attrs.placeholder)) {
21650                     oldCaretPosition = 0;
21651                     oldSelectionLength = 0;
21652                     if (!isValid || value.length === 0) {
21653                         valueMasked = '';
21654                         element.val('');
21655                         scope.$apply(function() {
21656                             //only $setViewValue when not $pristine to avoid changing $pristine state.
21657                             if (!ctrl.$pristine) {
21658                                 ctrl.$setViewValue('');
21659                             }
21660                         });
21661                     }
21662                 }
21663                 //Check for different value and trigger change.
21664                 if (value !== prevValue) {
21665                     var currentVal = element.val();
21666                     var isTemporarilyEmpty = value === '' && currentVal && angular.isDefined(attrs.uiMaskPlaceholderChar) && attrs.uiMaskPlaceholderChar === 'space';
21667                     if(isTemporarilyEmpty) {
21668                         element.val('');
21669                     }
21670                     triggerChangeEvent(element[0]);
21671                     if(isTemporarilyEmpty) {
21672                         element.val(currentVal);
21673                     }
21674                 }
21675                 prevValue = value;
21676             }
21677
21678             function triggerChangeEvent(element) {
21679                 var change;
21680                 if (angular.isFunction(window.Event) && !element.fireEvent) {
21681                     // modern browsers and Edge
21682                     try {
21683                         change = new Event('change', {
21684                             view: window,
21685                             bubbles: true,
21686                             cancelable: false
21687                         });
21688                     } catch (ex) {
21689                         //this is for certain mobile browsers that have the Event object
21690                         //but don't support the Event constructor 
21691                         change = document.createEvent('HTMLEvents');
21692                         change.initEvent('change', false, true);
21693                     } finally {
21694                         element.dispatchEvent(change);
21695                     }
21696                 } else if ('createEvent' in document) {
21697                     // older browsers
21698                     change = document.createEvent('HTMLEvents');
21699                     change.initEvent('change', false, true);
21700                     element.dispatchEvent(change);
21701                 }
21702                 else if (element.fireEvent) {
21703                     // IE <= 11
21704                     element.fireEvent('onchange');
21705                 }
21706             }
21707
21708             function mouseDownUpHandler(e) {
21709                 if (e.type === 'mousedown') {
21710                     element.bind('mouseout', mouseoutHandler);
21711                 } else {
21712                     element.unbind('mouseout', mouseoutHandler);
21713                 }
21714             }
21715
21716             element.bind('mousedown mouseup', mouseDownUpHandler);
21717
21718             function mouseoutHandler() {
21719                 oldSelectionLength = getSelectionLength(this);
21720                 element.unbind('mouseout', mouseoutHandler);
21721             }
21722
21723             function keydownHandler(e) {
21724                 var isKeyBackspace = e.which === 8,
21725                 caretPos = getCaretPosition(this) - 1 || 0, //value in keydown is pre change so bump caret position back to simulate post change
21726                 isCtrlZ = e.which === 90 && e.ctrlKey; //ctrl+z pressed
21727
21728                 if (isKeyBackspace) {
21729                     while(caretPos >= 0) {
21730                         if (isValidCaretPosition(caretPos)) {
21731                             //re-adjust the caret position.
21732                             //Increment to account for the initial decrement to simulate post change caret position
21733                             setCaretPosition(this, caretPos + 1);
21734                             break;
21735                         }
21736                         caretPos--;
21737                     }
21738                     preventBackspace = caretPos === -1;
21739                 }
21740
21741                 if (isCtrlZ) {
21742                     // prevent IE bug - value should be returned to initial state
21743                     element.val('');
21744                     e.preventDefault();
21745                 }
21746             }
21747
21748             function eventHandler(e) {
21749                 e = e || {};
21750                 // Allows more efficient minification
21751                 var eventWhich = e.which,
21752                         eventType = e.type;
21753
21754                 // Prevent shift and ctrl from mucking with old values
21755                 if (eventWhich === 16 || eventWhich === 91) {
21756                     return; 
21757                 }
21758
21759                 var val = element.val(),
21760                         valOld = oldValue,
21761                         valMasked,
21762                         valAltered = false,
21763                         valUnmasked = unmaskValue(val),
21764                         valUnmaskedOld = oldValueUnmasked,
21765                         caretPos = getCaretPosition(this) || 0,
21766                         caretPosOld = oldCaretPosition || 0,
21767                         caretPosDelta = caretPos - caretPosOld,
21768                         caretPosMin = maskCaretMap[0],
21769                         caretPosMax = maskCaretMap[valUnmasked.length] || maskCaretMap.slice().shift(),
21770                         selectionLenOld = oldSelectionLength || 0,
21771                         isSelected = getSelectionLength(this) > 0,
21772                         wasSelected = selectionLenOld > 0,
21773                         // Case: Typing a character to overwrite a selection
21774                         isAddition = (val.length > valOld.length) || (selectionLenOld && val.length > valOld.length - selectionLenOld),
21775                         // Case: Delete and backspace behave identically on a selection
21776                         isDeletion = (val.length < valOld.length) || (selectionLenOld && val.length === valOld.length - selectionLenOld),
21777                         isSelection = (eventWhich >= 37 && eventWhich <= 40) && e.shiftKey, // Arrow key codes
21778
21779                         isKeyLeftArrow = eventWhich === 37,
21780                         // Necessary due to "input" event not providing a key code
21781                         isKeyBackspace = eventWhich === 8 || (eventType !== 'keyup' && isDeletion && (caretPosDelta === -1)),
21782                         isKeyDelete = eventWhich === 46 || (eventType !== 'keyup' && isDeletion && (caretPosDelta === 0) && !wasSelected),
21783                         // Handles cases where caret is moved and placed in front of invalid maskCaretMap position. Logic below
21784                         // ensures that, on click or leftward caret placement, caret is moved leftward until directly right of
21785                         // non-mask character. Also applied to click since users are (arguably) more likely to backspace
21786                         // a character when clicking within a filled input.
21787                         caretBumpBack = (isKeyLeftArrow || isKeyBackspace || eventType === 'click') && caretPos > caretPosMin;
21788
21789                 oldSelectionLength = getSelectionLength(this);
21790
21791                 // These events don't require any action
21792                 if (isSelection || (isSelected && (eventType === 'click' || eventType === 'keyup' || eventType === 'focus'))) {
21793                     return;
21794                 }
21795
21796                 if (isKeyBackspace && preventBackspace) {
21797                     element.val(maskPlaceholder);
21798                     // This shouldn't be needed but for some reason after aggressive backspacing the ctrl $viewValue is incorrect.
21799                     // This keeps the $viewValue updated and correct.
21800                     scope.$apply(function () {
21801                         ctrl.$setViewValue(''); // $setViewValue should be run in angular context, otherwise the changes will be invisible to angular and user code.
21802                     });
21803                     setCaretPosition(this, caretPosOld);
21804                     return;
21805                 }
21806
21807                 // User attempted to delete but raw value was unaffected--correct this grievous offense
21808                 if ((eventType === 'input') && isDeletion && !wasSelected && valUnmasked === valUnmaskedOld) {
21809                     while (isKeyBackspace && caretPos > caretPosMin && !isValidCaretPosition(caretPos)) {
21810                         caretPos--;
21811                     }
21812                     while (isKeyDelete && caretPos < caretPosMax && maskCaretMap.indexOf(caretPos) === -1) {
21813                         caretPos++;
21814                     }
21815                     var charIndex = maskCaretMap.indexOf(caretPos);
21816                     // Strip out non-mask character that user would have deleted if mask hadn't been in the way.
21817                     valUnmasked = valUnmasked.substring(0, charIndex) + valUnmasked.substring(charIndex + 1);
21818
21819                     // If value has not changed, don't want to call $setViewValue, may be caused by IE raising input event due to placeholder
21820                     if (valUnmasked !== valUnmaskedOld)
21821                         valAltered = true;
21822                 }
21823
21824                 // Update values
21825                 valMasked = maskValue(valUnmasked);
21826
21827                 oldValue = valMasked;
21828                 oldValueUnmasked = valUnmasked;
21829
21830                 //additional check to fix the problem where the viewValue is out of sync with the value of the element.
21831                 //better fix for commit 2a83b5fb8312e71d220a497545f999fc82503bd9 (I think)
21832                 if (!valAltered && val.length > valMasked.length)
21833                     valAltered = true;
21834
21835                 element.val(valMasked);
21836
21837                 //we need this check.  What could happen if you don't have it is that you'll set the model value without the user
21838                 //actually doing anything.  Meaning, things like pristine and touched will be set.
21839                 if (valAltered) {
21840                     scope.$apply(function () {
21841                         ctrl.$setViewValue(valMasked); // $setViewValue should be run in angular context, otherwise the changes will be invisible to angular and user code.
21842                     });
21843                 }
21844
21845                 // Caret Repositioning
21846                 // Ensure that typing always places caret ahead of typed character in cases where the first char of
21847                 // the input is a mask char and the caret is placed at the 0 position.
21848                 if (isAddition && (caretPos <= caretPosMin)) {
21849                     caretPos = caretPosMin + 1;
21850                 }
21851
21852                 if (caretBumpBack) {
21853                     caretPos--;
21854                 }
21855
21856                 // Make sure caret is within min and max position limits
21857                 caretPos = caretPos > caretPosMax ? caretPosMax : caretPos < caretPosMin ? caretPosMin : caretPos;
21858
21859                 // Scoot the caret back or forth until it's in a non-mask position and within min/max position limits
21860                 while (!isValidCaretPosition(caretPos) && caretPos > caretPosMin && caretPos < caretPosMax) {
21861                     caretPos += caretBumpBack ? -1 : 1;
21862                 }
21863
21864                 if ((caretBumpBack && caretPos < caretPosMax) || (isAddition && !isValidCaretPosition(caretPosOld))) {
21865                     caretPos++;
21866                 }
21867                 oldCaretPosition = caretPos;
21868                 setCaretPosition(this, caretPos);
21869             }
21870
21871             function isValidCaretPosition(pos) {
21872                 return maskCaretMap.indexOf(pos) > -1;
21873             }
21874
21875             function getCaretPosition(input) {
21876                 if (!input)
21877                     return 0;
21878                 if (input.selectionStart !== undefined) {
21879                     return input.selectionStart;
21880                 } else if (document.selection) {
21881                     if (isFocused(element[0])) {
21882                         // For IE
21883                         input.focus();
21884                         var selection = document.selection.createRange();
21885                         selection.moveStart('character', input.value ? -input.value.length : 0);
21886                         return selection.text.length;
21887                     }
21888                 }
21889                 return 0;
21890             }
21891
21892             function setCaretPosition(input, pos) {
21893                 if (!input)
21894                     return 0;
21895                 if (input.offsetWidth === 0 || input.offsetHeight === 0) {
21896                     return; // Input's hidden
21897                 }
21898                 if (input.setSelectionRange) {
21899                     if (isFocused(element[0])) {
21900                         input.focus();
21901                         input.setSelectionRange(pos, pos);
21902                     }
21903                 }
21904                 else if (input.createTextRange) {
21905                     // For IE
21906                     var range = input.createTextRange();
21907                     range.collapse(true);
21908                     range.moveEnd('character', pos);
21909                     range.moveStart('character', pos);
21910                     range.select();
21911                 }
21912             }
21913
21914             function getSelectionLength(input) {
21915                 if (!input)
21916                     return 0;
21917                 if (input.selectionStart !== undefined) {
21918                     return (input.selectionEnd - input.selectionStart);
21919                 }
21920                 if (window.getSelection) {
21921                     return (window.getSelection().toString().length);
21922                 }
21923                 if (document.selection) {
21924                     return (document.selection.createRange().text.length);
21925                 }
21926                 return 0;
21927             }
21928         }
21929     };
21930 }])
21931 .filter('b2bMultiSepartorHighlight', function($sce) {
21932         return function(text, searchText, searchSeperator) {
21933             var splitText = function(string) {
21934                 if(angular.isDefined(searchSeperator)){
21935                     if (string.indexOf(searchSeperator) > -1) {
21936                         return string.split(searchSeperator);
21937                     } else {
21938                         return string
21939                     }
21940                 }else{
21941                     return string;
21942                 }
21943             }
21944             if (text) {
21945                 var newText = splitText(text);
21946                 var newPhrase = splitText(searchText);
21947                 if (angular.isArray(newPhrase)) {
21948                     for (var i = 0; i < newText.length; i++) {
21949                         if (i <= 0) {
21950                             text = newText[i].replace(new RegExp('(' + newPhrase[i] + ')', 'gi'),
21951                                 '<span class="b2b-search-hightlight">$1</span>');
21952                         } else {
21953                             text = text + searchSeperator + ' ' + (newPhrase[i] ? newText[i].replace(new RegExp('(' + newPhrase[i] + ')', 'gi'),
21954                                 '<span class="b2b-search-hightlight">$1</span>') : newText[i]);
21955                         }
21956                     }
21957                 } else {
21958                     text = text.replace(new RegExp('(' + searchText + ')', 'gi'),
21959                         '<span class="b2b-search-hightlight">$1</span>');
21960                 }
21961             }
21962             return $sce.trustAsHtml(text)
21963         }
21964     })
21965     
21966     .factory('b2bUserAgent', [function() {
21967         var _isMobile = function() {
21968             if(/Android/i.test(navigator.userAgent)){
21969                 return /Mobile/i.test(navigator.userAgent);
21970             }else{
21971                 return /Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
21972             }
21973             
21974         };
21975         var _notMobile = function() {
21976             if(/Android/i.test(navigator.userAgent)){
21977                 return !/Mobile/i.test(navigator.userAgent);
21978             }else{
21979                 return !/Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
21980             }
21981             
21982         };
21983         var _isIE = function() {
21984             return /msie|trident/i.test(navigator.userAgent);
21985         };
21986         var _isFF = function() {
21987             return /Firefox/.test(navigator.userAgent);
21988         };
21989         var _isChrome = function() {
21990             return /Chrome/.test(navigator.userAgent);
21991         };
21992         var _isSafari = function() {
21993             return /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent);
21994         };
21995
21996         return {
21997             isMobile: _isMobile,
21998             notMobile: _notMobile,
21999             isIE: _isIE,
22000             isFF: _isFF,
22001             isChrome: _isChrome,
22002             isSafari: _isSafari
22003         };
22004     }])
22005     .run(['$document', 'b2bUserAgent', function($document, b2bUserAgent) {
22006         var html = $document.find('html').eq(0);
22007         if (b2bUserAgent.isIE()) {
22008             html.addClass('isIE');
22009         } else {
22010             html.removeClass('isIE');
22011         }
22012     }]);
22013     
22014
22015 (function () {
22016     String.prototype.toSnakeCase = function () {
22017         return this.replace(/([A-Z])/g, function ($1) {
22018             return "-" + $1.toLowerCase();
22019         });
22020     };
22021     var concat = function (character, times) {
22022         character = character || '';
22023         times = (!isNaN(times) && times) || 0;
22024         var finalChar = '';
22025         for (var i = 0; i < times; i++) {
22026             finalChar += character;
22027         }
22028         return finalChar;
22029     };
22030
22031     // direction: true for left and false for right
22032     var pad = function (actualString, width, character, direction) {
22033         actualString = actualString || '';
22034         width = (!isNaN(width) && width) || 0;
22035         character = character || '';
22036         if (width > actualString.length) {
22037             if (direction) {
22038                 return concat(character, (width - actualString.length)) + actualString;
22039             } else {
22040                 return actualString + concat(character, (width - actualString.length));
22041             }
22042         }
22043         return actualString;
22044     };
22045
22046     String.prototype.lPad = function (width, character) {
22047         return pad(this, width, character, true);
22048     };
22049
22050     String.prototype.rPad = function (width, character) {
22051         return pad(this, width, character, false);
22052     };
22053
22054     if (!Array.prototype.indexOf) {
22055         Array.prototype.indexOf = function (val) {
22056             for (var index = 0; index < this.length; index++) {
22057                 if (this[index] === val) {
22058                     return index;
22059                 }
22060             }
22061             return -1;
22062         };
22063     }
22064
22065     if (!Array.prototype.regexIndexOf) {
22066         Object.defineProperty(Array.prototype, 'regexIndexOf', {
22067             enumerable: false,
22068             value: function (regex, startIndex, loop) {
22069                 startIndex = startIndex && startIndex > -1 ? startIndex : 0;
22070                 for (var index = startIndex; index < this.length; index++) {
22071                     if (this[index].toString().match(regex)) {
22072                         return index;
22073                     }
22074                 }
22075                 if (loop) {
22076                     for (var index = 0; index < startIndex; index++) {
22077                         if (this[index].toString().match(regex)) {
22078                             return index;
22079                         }
22080                     }
22081                 }
22082                 return -1;
22083             }
22084         })
22085     }
22086 })();
22087 angular.module("b2bTemplate/audioPlayer/audioPlayer.html", []).run(["$templateCache", function($templateCache) {
22088   $templateCache.put("b2bTemplate/audioPlayer/audioPlayer.html",
22089     "<div class=\"b2b-audio\">\n" +
22090     "   <audio preload=\"auto\">\n" +
22091     "           <source ng-src=\"{{audio.mp3 | trustedAudioUrl}}\" type=\"audio/mp3\"></source>\n" +
22092     "           <i>Your browser does not support the audio element.</i>\n" +
22093     "    </audio>\n" +
22094     "\n" +
22095     "    <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" +
22096     "           <i class=\"icoControls-pointer\" ng-show='!isPlayInProgress'></i>\n" +
22097     "           <i class=\"icoControls-pause\" ng-show='isPlayInProgress'></i>\n" +
22098     "    </div>\n" +
22099     "\n" +
22100     "    <div class=\"seek-bar-container-wrapper\">\n" +
22101     "           <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" +
22102     "           <div class=\"timing-container\">\n" +
22103     "                   <span class=\"timing-container-left\">{{timeFormatter(audio.currentTime)}}</span>\n" +
22104     "                   <span class=\"timing-container-right\">{{timeFormatter(audio.duration)}}</span>\n" +
22105     "                   <div class=\"timing-container-spacer\"></div>\n" +
22106     "           </div>\n" +
22107     "    </div>\n" +
22108     "           \n" +
22109     "    <b2b-flyout>\n" +
22110     "           <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" +
22111     "                   <i class=\"icoControls-mutespeakers\" ng-show=\"audio.currentVolume === 0\"></i>\n" +
22112     "                   <i class=\"icoControls-volumedown\" ng-show=\"audio.currentVolume > 0 && audio.currentVolume <= 50\"></i>\n" +
22113     "                   <i class=\"icoControls-volumeup\" ng-show=\"audio.currentVolume > 50\"></i>\n" +
22114     "           </div> \n" +
22115     "           \n" +
22116     "           <b2b-flyout-content horizontal-placement=\"center\" flyout-style=\"width:70px; height:190px;\" vertical-placement=\"above\">\n" +
22117     "                   <div class=\"b2b-audio-popover text-center\">\n" +
22118     "                           <span>Max</span>\n" +
22119     "                           <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" +
22120     "                           <div class=\"min-label\">Min</div>\n" +
22121     "                   </div>\n" +
22122     "           </b2b-flyout-content>\n" +
22123     "   </b2b-flyout>\n" +
22124     "</div>");
22125 }]);
22126
22127 angular.module("b2bTemplate/audioRecorder/audioRecorder.html", []).run(["$templateCache", function($templateCache) {
22128   $templateCache.put("b2bTemplate/audioRecorder/audioRecorder.html",
22129     "<div class=\"b2b-audio-recorder row\">\n" +
22130     "   <div class=\"b2b-elapsed-time span11\">\n" +
22131     "           <div ng-if=\"isRecording\">\n" +
22132     "                   <span style=\"padding-right: 25px;\">{{config.whileRecordingMessage}}</span>\n" +
22133     "                   <span>{{timeFormatter(elapsedTime)}}</span>\n" +
22134     "           </div>\n" +
22135     "           <span ng-if=\"!isRecording\">{{config.startRecordingMessage}}</span>\n" +
22136     "   </div>      \n" +
22137     "   <div class=\"b2b-controls\" title=\"{{isRecording ? 'Stop' : 'REC'}}\" b2b-accessibility-click=\"13,32\" ng-click=\"toggleRecording()\" role=\"button\">\n" +
22138     "           <i ng-if=\"isRecording\" class=\"icoControls-stop\" ></i>\n" +
22139     "           <i ng-if=\"!isRecording\" class=\"icoControls-record\"></i>\n" +
22140     "    </div>\n" +
22141     "</div>");
22142 }]);
22143
22144 angular.module("b2bTemplate/backToTop/backToTop.html", []).run(["$templateCache", function($templateCache) {
22145   $templateCache.put("b2bTemplate/backToTop/backToTop.html",
22146     "<button class=\"btn-arrow b2b-backtotop-button\" type=\"button\" aria-label=\"Back to top\">\n" +
22147     "    <div class=\"btn-secondary b2b-top-btn\">\n" +
22148     "        <i class=\"icoControls-upPRIMARY\" role=\"img\"></i>\n" +
22149     "    </div>\n" +
22150     "</button>\n" +
22151     "");
22152 }]);
22153
22154 angular.module("b2bTemplate/boardstrip/b2bAddBoard.html", []).run(["$templateCache", function($templateCache) {
22155   $templateCache.put("b2bTemplate/boardstrip/b2bAddBoard.html",
22156     "<div tabindex=\"0\" role=\"menuitem\" b2b-accessibility-click=\"13,32\" ng-click=\"addBoard()\" aria-label=\"Add Board\" class=\"boardstrip-item--add\">\n" +
22157     "    <div class=\"centered\"><i aria-hidden=\"true\" class=\"icoControls-add-maximize\"></i> Add board</div>\n" +
22158     "</div> ");
22159 }]);
22160
22161 angular.module("b2bTemplate/boardstrip/b2bBoard.html", []).run(["$templateCache", function($templateCache) {
22162   $templateCache.put("b2bTemplate/boardstrip/b2bBoard.html",
22163     "<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" +
22164     "    <div ng-transclude></div>\n" +
22165     "    <div class=\"board-caret\" ng-if=\"getCurrentIndex()===boardIndex\">\n" +
22166     "        <div class=\"board-caret-indicator\"></div>\n" +
22167     "        <div class=\"board-caret-arrow-up\"></div>\n" +
22168     "    </div>\n" +
22169     "</li>");
22170 }]);
22171
22172 angular.module("b2bTemplate/boardstrip/b2bBoardstrip.html", []).run(["$templateCache", function($templateCache) {
22173   $templateCache.put("b2bTemplate/boardstrip/b2bBoardstrip.html",
22174     "<div class=\"b2b-boardstrip\">\n" +
22175     "   <div class=\"boardstrip-reel\" role=\"menu\">\n" +
22176     "           <div class=\"prev-items\">\n" +
22177     "                   <!-- <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" +
22178     "                   <button class=\"btn-arrow arrow\" b2b-accessibility-click=\"13,32\" ng-click=\"prevBoard()\" ng-disabled=\"!isPrevBoard()\">\n" +
22179     "                       <div class=\"btn btn-small btn-alt\"><i class=\"icon-primary-left\"></i>\n" +
22180     "                       </div>\n" +
22181     "                       <span class=\"offscreen-text\">Previous boards</span>\n" +
22182     "                   </button>\n" +
22183     "           </div>\n" +
22184     "           <div b2b-add-board on-add-board=\"onAddBoard()\"></div>\n" +
22185     "           <div class=\"board-viewport\"><ul role=\"menu\" class=\"boardstrip-container\" ng-transclude></ul></div>\n" +
22186     "           <div class=\"next-items\">\n" +
22187     "                   <!-- <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" +
22188     "                   <button class=\"btn-arrow arrow\" b2b-accessibility-click=\"13,32\" ng-click=\"nextBoard()\" ng-disabled=\"!isNextBoard()\">\n" +
22189     "                       <div class=\"btn btn-small btn-alt\"><i class=\"icon-primary-right\"></i>\n" +
22190     "                       </div>\n" +
22191     "                       <span class=\"offscreen-text\">Next boards</span>\n" +
22192     "                   </button>\n" +
22193     "           </div>\n" +
22194     "   </div>\n" +
22195     "</div>\n" +
22196     "");
22197 }]);
22198
22199 angular.module("b2bTemplate/calendar/datepicker-popup.html", []).run(["$templateCache", function($templateCache) {
22200   $templateCache.put("b2bTemplate/calendar/datepicker-popup.html",
22201     "<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" +
22202     "    <div class=\"datepicker-days\" style=\"display: block;\">\n" +
22203     "        <div ng-repeat=\"header in headers\" class=\"text-left\" style=\"width: 100%;\" b2b-append-element=\"header\"></div>\n" +
22204     "        <table class=\"table-condensed\">\n" +
22205     "            <thead>\n" +
22206     "                <tr>\n" +
22207     "                    <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" +
22208     "                    <th id=\"month\" tabindex=\"-1\" aria-label=\"{{title}}\" class=\"datepicker-switch\" colspan=\"{{rows[0].length - 2}}\">{{title}}</th>\n" +
22209     "                    <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" +
22210     "                </tr>\n" +
22211     "                <tr ng-show=\"labels.length > 0\">\n" +
22212     "                    <th id=\"{{label.post}}\" class=\"dow\" ng-repeat=\"label in labels\" aria-hidden=\"true\"><span aria-hidden=\"true\">{{label.pre}}</span></th>\n" +
22213     "                </tr>\n" +
22214     "            </thead>\n" +
22215     "            <tbody>\n" +
22216     "                <tr ng-repeat=\"row in rows\">\n" +
22217     "                    <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" +
22218     "                        <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" +
22219     "                </tr>\n" +
22220     "            </tbody>\n" +
22221     "            <tfoot>\n" +
22222     "                <tr ng-repeat=\"footer in footers\">\n" +
22223     "                    <th colspan=\"7\" class=\"text-left\" style=\"width: 278px;\" b2b-append-element=\"footer\"></th>\n" +
22224     "                </tr>\n" +
22225     "            </tfoot>\n" +
22226     "        </table>\n" +
22227     "    </div>\n" +
22228     "</div>");
22229 }]);
22230
22231 angular.module("b2bTemplate/calendar/datepicker.html", []).run(["$templateCache", function($templateCache) {
22232   $templateCache.put("b2bTemplate/calendar/datepicker.html",
22233     "<div>\n" +
22234     "    <span class=\"icon-primary-calendar span12\" ng-class=\"{'disabled': ngDisabled}\" ng-transclude></span>\n" +
22235     "</div>");
22236 }]);
22237
22238 angular.module("b2bTemplate/coachmark/coachmark.html", []).run(["$templateCache", function($templateCache) {
22239   $templateCache.put("b2bTemplate/coachmark/coachmark.html",
22240     "<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" +
22241     "   <i class=\"b2b-coachmark-caret\"></i>\n" +
22242     "   <div class=\"b2b-coachmark-header\">\n" +
22243     "           <div class=\"b2b-coachmark-countlabel\"><span ng-if=\"coachmarkIndex !== 0\">{{coachmarkIndex}} of {{(coachmarks.length-1)}}<span></div>\n" +
22244     "           <div class=\"corner-button\">\n" +
22245     "                   <button type=\"button\" ng-focus=\"closeButtonFocus()\" class=\"close\" title=\"close\" aria-label=\"Close\" ng-click=\"closeCoachmark()\"></button>\n" +
22246     "           </div>\n" +
22247     "   </div>\n" +
22248     "   <div class=\"b2b-coachmark-content\">   \n" +
22249     "           <i class=\"icon-misc-dimmer\"></i>\n" +
22250     "           <div class=\"b2b-coachmark-content-header\"><span class=\"offscreen-text\">{{currentCoachmark.offscreenText}}</span>{{currentCoachmark.contentHeader}}</div>\n" +
22251     "           <div class=\"b2b-coachmark-description\">{{currentCoachmark.content}}</div>\n" +
22252     "           <div class=\"b2b-coachmark-btn-group\">\n" +
22253     "                   <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" +
22254     "                   <button class=\"btn btn-alt\" ng-if=\"currentCoachmark.buttonLabel !== '' && currentCoachmark.buttonLabel !== undefined\" ng-click=\"actionCoachmark(currentCoachmark.buttonLabel)\">{{currentCoachmark.buttonLabel}}</button>\n" +
22255     "           </div>  \n" +
22256     "   </div>  \n" +
22257     "</div>");
22258 }]);
22259
22260 angular.module("b2bTemplate/dropdowns/b2bDropdownDesktop.html", []).run(["$templateCache", function($templateCache) {
22261   $templateCache.put("b2bTemplate/dropdowns/b2bDropdownDesktop.html",
22262     "<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" +
22263     "    <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" +
22264     "    <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" +
22265     "    <div ng-class=\"{'selectWrapper': (isInputDropdown), 'moduleWrapper': (!isInputDropdown)}\">\n" +
22266     "        <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" +
22267     "        <ul class=\"module-optinalcta\" ng-if=\"toggleFlag && optionalCta\" tabindex=\"-1\" aria-hidden=\"false\">\n" +
22268     "            <li class=\"module-list-item\" tabindex=\"-1\" role=\"menuitem\" value=\"\" aria-label=\"Optinal CTA\" aria-selected=\"true\">\n" +
22269     "                <span class=\"module-data\" b2b-append-element=\"optionalCta\"></span>\n" +
22270     "            </li>\n" +
22271     "        </ul>\n" +
22272     "</div>\n" +
22273     "<i class=\"icon-primary-down\" aria-hidden=\"true\"></i>\n" +
22274     "</span>");
22275 }]);
22276
22277 angular.module("b2bTemplate/dropdowns/b2bDropdownGroupDesktop.html", []).run(["$templateCache", function($templateCache) {
22278   $templateCache.put("b2bTemplate/dropdowns/b2bDropdownGroupDesktop.html",
22279     "<li b2b-dropdown-group-desktop class=\"optgroup-wrapper\">{{groupHeader}}\n" +
22280     "    <ul class=\"optgroup\" role=\"group\" aria-label=\"{{groupHeader}}\"></ul>\n" +
22281     "</li>");
22282 }]);
22283
22284 angular.module("b2bTemplate/dropdowns/b2bDropdownListDesktop.html", []).run(["$templateCache", function($templateCache) {
22285   $templateCache.put("b2bTemplate/dropdowns/b2bDropdownListDesktop.html",
22286     "<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>");
22287 }]);
22288
22289 angular.module("b2bTemplate/fileUpload/fileUpload.html", []).run(["$templateCache", function($templateCache) {
22290   $templateCache.put("b2bTemplate/fileUpload/fileUpload.html",
22291     "<label class=\"b2b-file-container\">\n" +
22292     "   <span class=\"b2b-upload-link\" ng-transclude></span>\n" +
22293     "   <input type=\"file\" b2b-file-change>\n" +
22294     "</label>");
22295 }]);
22296
22297 angular.module("b2bTemplate/flyout/flyout.html", []).run(["$templateCache", function($templateCache) {
22298   $templateCache.put("b2bTemplate/flyout/flyout.html",
22299     "<span class=\"b2b-flyout\"  b2b-flyout-trap-focus-inside>\n" +
22300     "    <span ng-transclude></span>\n" +
22301     "</span>");
22302 }]);
22303
22304 angular.module("b2bTemplate/flyout/flyoutContent.html", []).run(["$templateCache", function($templateCache) {
22305   $templateCache.put("b2bTemplate/flyout/flyoutContent.html",
22306     "<div class=\"b2b-flyout-container\" aria-live=\"polite\" aria-atomic=\"false\" ng-class=\"{'b2b-flyout-left':horizontalPlacement==='left',\n" +
22307     "                'b2b-flyout-center':horizontalPlacement==='center', \n" +
22308     "                'b2b-flyout-right':horizontalPlacement==='right',\n" +
22309     "                'b2b-flyout-centerLeft':horizontalPlacement==='centerLeft',\n" +
22310     "                'b2b-flyout-centerRight':horizontalPlacement==='centerRight',  \n" +
22311     "                'b2b-flyout-above':verticalPlacement==='above', \n" +
22312     "                'b2b-flyout-below':verticalPlacement==='below',\n" +
22313     "                'open-flyout': openFlyout,\n" +
22314     "                'b2b-close-flyout': !openFlyout}\">\n" +
22315     "    <i class=\"b2b-flyout-caret\" ng-class=\"{'open-flyout': openFlyout, \n" +
22316     "                                   'b2b-flyout-caret-above':verticalPlacement==='above',\n" +
22317     "                                   'b2b-flyout-caret-below':verticalPlacement==='below'}\"></i>\n" +
22318     "    <span ng-transclude></span>\n" +
22319     "</div>");
22320 }]);
22321
22322 angular.module("b2bTemplate/footer/footer_column_switch_tpl.html", []).run(["$templateCache", function($templateCache) {
22323   $templateCache.put("b2bTemplate/footer/footer_column_switch_tpl.html",
22324     "<div class=\"footer-columns \" ng-class=\"{'five-column':footerColumns===5, 'four-column':footerColumns===4, 'three-column':footerColumns===3}\" ng-repeat=\"item in footerLinkItems\">\n" +
22325     "    <h3 class=\"b2b-footer-header\">{{item.categoryName}}</h3>\n" +
22326     "    <ul>\n" +
22327     "        <li ng-repeat=\"i in item.values\">\n" +
22328     "            <a href=\"{{i.href}}\" title=\"{{item.categoryName}} - {{i.displayLink}}\">{{i.displayLink}}</a>  \n" +
22329     "        </li>\n" +
22330     "    </ul>\n" +
22331     "\n" +
22332     "</div>\n" +
22333     "\n" +
22334     "<div ng-transclude></div>\n" +
22335     "");
22336 }]);
22337
22338 angular.module("b2bTemplate/horizontalTable/horizontalTable.html", []).run(["$templateCache", function($templateCache) {
22339   $templateCache.put("b2bTemplate/horizontalTable/horizontalTable.html",
22340     "<div class=\"b2b-horizontal-table\">\n" +
22341     "    <div class=\"b2b-horizontal-table-arrows row span12\">\n" +
22342     "        <div class=\"span4 b2b-prev-link\">\n" +
22343     "            <a href=\"javascript:void(0)\" ng-click=\"moveViewportLeft()\" ddh-accessibility-click=\"13,32\" ng-if=\"!disableLeft\">Previous</a>\n" +
22344     "            <span ng-if=\"disableLeft\" class=\"b2b-disabled-text\">Previous</span>\n" +
22345     "        </div>\n" +
22346     "        \n" +
22347     "        <span class=\"span5 b2b-horizontal-table-column-info\" aria-live=\"polite\" tabindex=\"-1\">\n" +
22348     "            Showing {{countDisplayText}} {{getColumnSet()[0]+1}}-{{getColumnSet()[1]+1}} of {{numOfCols}} columns\n" +
22349     "        </span>\n" +
22350     "\n" +
22351     "        <div ng-if=\"legendContent\" class=\"span2 b2b-horizontal-table-legend\">\n" +
22352     "           | <b2b-flyout>\n" +
22353     "                <div tabindex=\"0\" role=\"button\" aria-haspopup=\"true\" b2b-flyout-toggler b2b-accessibility-click=\"13,32\" aria-expanded=\"{{flyoutOpened ? 'true' : 'false'}}\">\n" +
22354     "                    Legend\n" +
22355     "                    <i class=\"icoControls-down\" role=\"img\"></i>\n" +
22356     "                </div>\n" +
22357     "              <b2b-flyout-content horizontal-placement=\"center\" vertical-placement=\"below\">\n" +
22358     "                <div ng-bind-html=\"legendContent\"></div>\n" +
22359     "              </b2b-flyout-content>\n" +
22360     "            </b2b-flyout>\n" +
22361     "        </div>\n" +
22362     "        \n" +
22363     "        <div class=\"span3 text-right b2b-next-link\">\n" +
22364     "            <a href=\"javascript:void(0)\" ng-click=\"moveViewportRight()\" ddh-accessibility-click=\"13,32\" ng-if=\"!disableRight\">Next</a>\n" +
22365     "            <span ng-if=\"disableRight\" class=\"b2b-disabled-text\">Next</span>\n" +
22366     "        </div>\n" +
22367     "    </div>\n" +
22368     "    <div class=\"b2b-horizontal-table-inner-container\">\n" +
22369     "        <span ng-transclude></span>\n" +
22370     "    </div>\n" +
22371     "</div>");
22372 }]);
22373
22374 angular.module("b2bTemplate/hourPicker/b2bHourpicker.html", []).run(["$templateCache", function($templateCache) {
22375   $templateCache.put("b2bTemplate/hourPicker/b2bHourpicker.html",
22376     "<div class=\"hp-container\">\n" +
22377     "    <div class=\"hp-selected\">\n" +
22378     "        <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" +
22379     "    </div>\n" +
22380     "    <div b2b-hourpicker-panel></div>\n" +
22381     "</div>");
22382 }]);
22383
22384 angular.module("b2bTemplate/hourPicker/b2bHourpickerPanel.html", []).run(["$templateCache", function($templateCache) {
22385   $templateCache.put("b2bTemplate/hourPicker/b2bHourpickerPanel.html",
22386     "<form name=\"{{'hourpickerForm' + $id}}\">\n" +
22387     "    <div class=\"hp-checkbox\" role=\"group\">\n" +
22388     "        <label class=\"checkbox\" for=\"checkbox_{{dayOption.title}}_{{$id}}\" ng-repeat=\"dayOption in hourpicker.dayOptions\">\n" +
22389     "            <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" +
22390     "        </label>\n" +
22391     "    </div>\n" +
22392     "    <div class=\"row hp-dropdowns\">\n" +
22393     "        <div class=\"span4\">\n" +
22394     "            <label for=\"{{'hourpickerStartTime' + $id}}\">From</label>\n" +
22395     "            <select id=\"{{'hourpickerStartTime' + $parent.$id}}\" b2b-dropdown type=\"\" ng-model=\"hourpickerPanelValue.startTime\">\n" +
22396     "                <option b2b-dropdown-list value=\"\">From</option>\n" +
22397     "                <option b2b-dropdown-list option-repeat=\"startTimeOption in hourpicker.startTimeOptions\" value=\"{{startTimeOption}}\">{{startTimeOption}}</option>\n" +
22398     "            </select>\n" +
22399     "        </div>\n" +
22400     "        <div class=\"span8 radio-buttons\" role=\"radiogroup\" aria-label=\"Select AM or PM\">\n" +
22401     "            <label class=\"radio\" for=\"hourpickerStartMeridiem_AM_{{$id}}\">\n" +
22402     "                <input type=\"radio\" id=\"hourpickerStartMeridiem_AM_{{$id}}\" name=\"{{'hourpickerStartMeridiem' + $id}}\" value=\"am\" ng-model=\"hourpickerPanelValue.startMeridiem\" /><i class=\"skin\"></i><span>AM</span>\n" +
22403     "            </label>\n" +
22404     "            <label class=\"radio\" for=\"hourpickerStartMeridiem_PM_{{$id}}\">\n" +
22405     "                <input type=\"radio\" id=\"hourpickerStartMeridiem_PM_{{$id}}\" name=\"{{'hourpickerStartMeridiem' + $id}}\" value=\"pm\" ng-model=\"hourpickerPanelValue.startMeridiem\" /><i class=\"skin\"></i><span>PM</span>\n" +
22406     "            </label>\n" +
22407     "        </div>\n" +
22408     "    </div>\n" +
22409     "    <div class=\"row hp-dropdowns\">\n" +
22410     "        <div class=\"span4\">\n" +
22411     "            <label for=\"{{'hourpickerEndTime' + $id}}\">To</label>\n" +
22412     "            <select id=\"{{'hourpickerEndTime' + $parent.$id}}\" b2b-dropdown ng-model=\"hourpickerPanelValue.endTime\">\n" +
22413     "                <option b2b-dropdown-list value=\"\">To</option>\n" +
22414     "                <option b2b-dropdown-list option-repeat=\"endTimeOption in hourpicker.endTimeOptions\" value=\"{{endTimeOption}}\">{{endTimeOption}}</option>\n" +
22415     "            </select>\n" +
22416     "        </div>\n" +
22417     "        <div class=\"span8 radio-buttons\" role=\"radiogroup\" aria-label=\"Select AM or PM\">\n" +
22418     "            <label class=\"radio\" for=\"hourpickerEndMeridiem_AM_{{$id}}\">\n" +
22419     "                <input type=\"radio\" id=\"hourpickerEndMeridiem_AM_{{$id}}\" name=\"{{'hourpickerEndMeridiem' + $id}}\" value=\"am\" ng-model=\"hourpickerPanelValue.endMeridiem\" /><i class=\"skin\"></i><span>AM</span>\n" +
22420     "            </label>\n" +
22421     "            <label class=\"radio\" for=\"hourpickerEndMeridiem_PM_{{$id}}\">\n" +
22422     "                <input type=\"radio\" id=\"hourpickerEndMeridiem_PM_{{$id}}\" name=\"{{'hourpickerEndMeridiem' + $id}}\" value=\"pm\" ng-model=\"hourpickerPanelValue.endMeridiem\" /><i class=\"skin\"></i><span>PM</span>\n" +
22423     "            </label>\n" +
22424     "        </div>\n" +
22425     "    </div>\n" +
22426     "    <div class=\"row hp-buttons\">\n" +
22427     "        <div class=\"span12\">\n" +
22428     "            <div style=\"float:right\">\n" +
22429     "                <button class=\"btn btn-secondary btn-small\" ng-click=\"resetHourpickerPanelValue()\">Clear</button>\n" +
22430     "                <button class=\"btn btn-alt btn-small\" ng-disabled = \"disableAddBtn\" ng-click=\"updateHourpickerValue()\">{{hourpicker.editMode > -1 ? 'Update' : 'Add'}}</button>\n" +
22431     "            </div>\n" +
22432     "        </div>\n" +
22433     "    </div>\n" +
22434     "</form>");
22435 }]);
22436
22437 angular.module("b2bTemplate/hourPicker/b2bHourpickerValue.html", []).run(["$templateCache", function($templateCache) {
22438   $templateCache.put("b2bTemplate/hourPicker/b2bHourpickerValue.html",
22439     "<div class=\"selected-days\">\n" +
22440     "    <span class=\"day\">{{hourpickerValue.days}} &nbsp; {{hourpickerValue.startTime}} {{hourpickerValue.startMeridiem}} - {{hourpickerValue.endTime}} {{hourpickerValue.endMeridiem}}</span>\n" +
22441     "    <span style=\"float:right\">\n" +
22442     "        <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" +
22443     "        <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" +
22444     "    </span>\n" +
22445     "    <div style=\"clear:both\"></div>\n" +
22446     "</div>");
22447 }]);
22448
22449 angular.module("b2bTemplate/leftNavigation/leftNavigation.html", []).run(["$templateCache", function($templateCache) {
22450   $templateCache.put("b2bTemplate/leftNavigation/leftNavigation.html",
22451     "<div class=\"b2b-nav-menu\">\n" +
22452     "    <div class=\"b2b-subnav-container\">\n" +
22453     "        <ul class=\"b2b-subnav-content\">\n" +
22454     "            <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" +
22455     "                <ul ng-class=\"{expand: idx==$index}\">\n" +
22456     "                    <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" +
22457     "                </ul>\n" +
22458     "            </li>\n" +
22459     "        </ul>\n" +
22460     "    </div>\n" +
22461     "</div>");
22462 }]);
22463
22464 angular.module("b2bTemplate/listbox/listbox.html", []).run(["$templateCache", function($templateCache) {
22465   $templateCache.put("b2bTemplate/listbox/listbox.html",
22466     "<div class=\"b2b-list-box\" tabindex=\"0\" role=\"listbox\" ng-transclude>\n" +
22467     "</div>");
22468 }]);
22469
22470 angular.module("b2bTemplate/modalsAndAlerts/b2b-backdrop.html", []).run(["$templateCache", function($templateCache) {
22471   $templateCache.put("b2bTemplate/modalsAndAlerts/b2b-backdrop.html",
22472     "<div class=\"b2b-modal-backdrop fade in hidden-by-modal\" aria-hidden=\"true\" tabindex=\"-1\"></div>");
22473 }]);
22474
22475 angular.module("b2bTemplate/modalsAndAlerts/b2b-window.html", []).run(["$templateCache", function($templateCache) {
22476   $templateCache.put("b2bTemplate/modalsAndAlerts/b2b-window.html",
22477     "<div class=\"modalwrapper active {{windowClass}}\" ng-class=\"{'modal-landscape': isModalLandscape}\" role=\"{{isNotifDialog?'alertdialog':'dialog'}}\" tabindex=\"-1\" aria-labelledby=\"{{title}}\" aria-describedby=\"{{content}}\">\n" +
22478     "    <div class=\"modal fade in {{sizeClass}}\" ng-transclude></div>\n" +
22479     "</div>");
22480 }]);
22481
22482 angular.module("b2bTemplate/monthSelector/monthSelector-popup.html", []).run(["$templateCache", function($templateCache) {
22483   $templateCache.put("b2bTemplate/monthSelector/monthSelector-popup.html",
22484     "<div id=\"monthselector{{$id}}\" class=\"datepicker dropdown-menu monthselector\" \n" +
22485     "     ng-class=\"{'datepicker-dropdown datepicker-orient-top': !inline, 'datepicker-orient-left': !inline && orientation === 'left', 'datepicker-orient-right': !inline && orientation === 'right'}\" \n" +
22486     "     ng-style=\"{position: inline && 'relative', 'z-index': inline && '0', top: !inline && position.top + 'px' || 0, left: !inline && position.left + 'px'}\" \n" +
22487     "     style=\"display: block;\" aria-hidden=\"false\" role=\"dialog presentation\" tabindex=\"-1\">\n" +
22488     "    <div class=\"datepicker-days\" style=\"display: block;\">\n" +
22489     "        <span class=\"offscreen-text\" aria-live=\"polite\" aria-atomic=\"true\">{{title}} displaying</span>\n" +
22490     "        <table class=\"table-condensed\" role=\"grid\">\n" +
22491     "            <thead>\n" +
22492     "                <tr ng-repeat=\"header in headers\">\n" +
22493     "                    <th colspan=\"7\" class=\"text-left\" style=\"width: 278px;\" b2b-append-element=\"header\"></th>\n" +
22494     "                </tr>\n" +
22495     "                <tr>\n" +
22496     "                    <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" +
22497     "                    <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" +
22498     "                    <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" +
22499     "                </tr>\n" +
22500     "                <tr ng-show=\"labels.length > 0\">\n" +
22501     "                    <th id=\"{{label.post}}\" class=\"dow\" ng-repeat=\"label in labels\" aria-hidden=\"true\"><span aria-hidden=\"true\">{{label.pre}}</span></th>\n" +
22502     "                </tr>\n" +
22503     "            </thead>\n" +
22504     "            <tbody b2b-key type=\"table\" columns=\"4\" >\n" +
22505     "                <tr ng-repeat=\"row in rows\">\n" +
22506     "                    <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" +
22507     "                        <div aria-hidden=\"true\"  tabindex=\"-1\" class=\"show-date\" ng-if=\"!(dt.oldMonth || dt.nextMonth)\">{{dt.label | limitTo: 3}}</div>\n" +
22508     "                    </td>\n" +
22509     "                </tr>\n" +
22510     "            </tbody>\n" +
22511     "            <tfoot>\n" +
22512     "                <tr ng-repeat=\"footer in footers\">\n" +
22513     "                    <th colspan=\"7\" class=\"text-left\" b2b-append-element=\"footer\"></th>\n" +
22514     "                </tr>\n" +
22515     "            </tfoot>\n" +
22516     "        </table>\n" +
22517     "    </div>\n" +
22518     "</div>");
22519 }]);
22520
22521 angular.module("b2bTemplate/monthSelector/monthSelector.html", []).run(["$templateCache", function($templateCache) {
22522   $templateCache.put("b2bTemplate/monthSelector/monthSelector.html",
22523     "<div>\n" +
22524     "    <span class=\"icon-primary-calendar span12\" ng-class=\"{'disabled': ngDisabled}\" ng-transclude></span>\n" +
22525     "</div>");
22526 }]);
22527
22528 angular.module("b2bTemplate/monthSelector/monthSelectorLink.html", []).run(["$templateCache", function($templateCache) {
22529   $templateCache.put("b2bTemplate/monthSelector/monthSelectorLink.html",
22530     "<div>\n" +
22531     "    <span class=\"span12\" ng-transclude></span>\n" +
22532     "</div>");
22533 }]);
22534
22535 angular.module("b2bTemplate/pagination/b2b-pagination.html", []).run(["$templateCache", function($templateCache) {
22536   $templateCache.put("b2bTemplate/pagination/b2b-pagination.html",
22537     "<div class=\"b2b-pager\">\n" +
22538     "    <div ng-if=\"notMobile && totalPages > 1\">\n" +
22539     "        <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" +
22540     "            <i class=\"icon-primary-left\"></i>\n" +
22541     "        </a>\n" +
22542     "        <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" +
22543     "            1<span class=\"offscreen-text\" ng-if=\"currentPage === 1\"> is selected</span>\n" +
22544     "        </a>\n" +
22545     "\n" +
22546     "        <span class=\"b2b-pager__item\" ng-if=\"totalPages > 10 && currentPage > 6\">...</span>\n" +
22547     "\n" +
22548     "        <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" +
22549     "            {{page}}<span class=\"offscreen-text\" ng-if=\"checkSelectedPage(page)\"> is selected</span>\n" +
22550     "        </a>\n" +
22551     "\n" +
22552     "        <span class=\"b2b-pager__item\" ng-if=\"totalPages > 10 && currentPage <= (totalPages - boundary)\">...</span>\n" +
22553     "\n" +
22554     "        <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" +
22555     "          {{totalPages}}<span class=\"offscreen-text\" ng-if=\"checkSelectedPage(page)\"> is selected</span>\n" +
22556     "        </a>\n" +
22557     "\n" +
22558     "\n" +
22559     "        <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" +
22560     "            <i class=\"icon-primary-right\"></i>\n" +
22561     "        </a>\n" +
22562     "        \n" +
22563     "        <div class=\"fieldLabel b2b-go-to-page\" ng-class=\"{'b2b-go-to-page-inline' : inputClass !== undefined }\" ng-show=\"totalPages > 20\">    \n" +
22564     "            <label for=\"{{inputId}}\">Go to Page:</label>\n" +
22565     "            <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" +
22566     "            <button class=\"btn-arrow\" ng-click=\"gotoBtnClick()\" ng-disabled=\"$parent.gotoPage !== 0 || $parent.gotoPage !== undefined\" aria-label=\"Go to\">\n" +
22567     "                <div class=\"btn btn-small btn-secondary\">\n" +
22568     "                    <i class=\"icon-primary-right\"></i>\n" +
22569     "                </div>\n" +
22570     "            </button>\n" +
22571     "        </div>\n" +
22572     "    </div>\n" +
22573     "    <div ng-if=\"isMobile && totalPages > 1\" ng-swipe-right=\"prev()\" ng-swipe-left=\"next()\" ng-class=\"isMobile ? 'b2b-mobile-view': '' \">\n" +
22574     "        <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" +
22575     "    </div>\n" +
22576     "</div>\n" +
22577     "");
22578 }]);
22579
22580 angular.module("b2bTemplate/paneSelector/paneSelector.html", []).run(["$templateCache", function($templateCache) {
22581   $templateCache.put("b2bTemplate/paneSelector/paneSelector.html",
22582     "<div class=\"panes\" ng-transclude></div>");
22583 }]);
22584
22585 angular.module("b2bTemplate/paneSelector/paneSelectorPane.html", []).run(["$templateCache", function($templateCache) {
22586   $templateCache.put("b2bTemplate/paneSelector/paneSelectorPane.html",
22587     "<div class=\"pane-block\" ng-transclude></div>");
22588 }]);
22589
22590 angular.module("b2bTemplate/profileCard/profileCard-addUser.html", []).run(["$templateCache", function($templateCache) {
22591   $templateCache.put("b2bTemplate/profileCard/profileCard-addUser.html",
22592     "<div  class=\"span3 b2b-profile-card b2b-add-user\">\n" +
22593     "    <div class=\"atcenter\">\n" +
22594     "        <div class=\"circle\"><i class=\"icon-primary-add-maximize\"></i></div>\n" +
22595     "        <div>Create new user</div>\n" +
22596     "    </div>\n" +
22597     "</div>");
22598 }]);
22599
22600 angular.module("b2bTemplate/profileCard/profileCard.html", []).run(["$templateCache", function($templateCache) {
22601   $templateCache.put("b2bTemplate/profileCard/profileCard.html",
22602     "<div class=\"span3 b2b-profile-card\">\n" +
22603     "    <div class=\"top-block\">\n" +
22604     "       <div class=\"profile-image\">\n" +
22605     "            <img ng-if=\"image\" profile-name=\"{{profile.name}}\" ng-src=\"{{profile.img}}\" alt=\"{{profile.name}}\">\n" +
22606     "            <span ng-if=\"!image\" class=\"default-img\">{{initials}}</span>\n" +
22607     "\n" +
22608     "            <h4 class=\"name\">{{profile.name}}</h4>\n" +
22609     "\n" +
22610     "            <p class=\"status\">\n" +
22611     "                <span class=\"status-icon\" ng-class=\"{'status-green':colorIcon==='green','status-red':colorIcon==='red','status-blue':colorIcon==='blue','status-yellow':colorIcon==='yellow'}\">   \n" +
22612     "                </span>\n" +
22613     "                <span>{{profile.state}}<span ng-if=\"badge\" class=\"status-badge\">Admin</span></span>\n" +
22614     "            </p>\n" +
22615     "        </div>\n" +
22616     "    </div>\n" +
22617     "    <div class=\"bottom-block\">\n" +
22618     "         <div class=\"profile-details\">\n" +
22619     "            <label>Username</label>\n" +
22620     "            <div ng-if=\"shouldClip(profile.userName)\" ng-mouseover=\"showUserNameTooltip = true;\" ng-mouseleave=\"showUserNameTooltip = false;\">\n" +
22621     "                <div ng-if=\"shouldClip(profile.userName)\" class=\"tooltip\" b2b-tooltip show-tooltip=\"showUserNameTooltip\">\n" +
22622     "                    {{profile.userName.slice(0, 25)+'...'}}\n" +
22623     "                    <div class=\"arrow\"></div>\n" +
22624     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +
22625     "                        <div class=\"tooltip-size-control\">\n" +
22626     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +
22627     "                                {{profile.userName}}\n" +
22628     "                            </div>\n" +
22629     "                        </div>\n" +
22630     "                    </div>\n" +
22631     "                </div>\n" +
22632     "            </div>\n" +
22633     "            <div ng-if=\"!shouldClip(profile.userName)\">\n" +
22634     "                {{profile.userName}}\n" +
22635     "            </div>\n" +
22636     "            <label>Email</label>\n" +
22637     "            <div ng-if=\"shouldClip(profile.email)\" ng-mouseover=\"showEmailTooltip = true;\" ng-mouseleave=\"showEmailTooltip = false;\">\n" +
22638     "                <div ng-if=\"shouldClip(profile.email)\" class=\"tooltip\" data-placement=\"bottom\" b2b-tooltip show-tooltip=\"showEmailTooltip\">\n" +
22639     "                    {{profile.email.slice(0, 25)+'...'}}\n" +
22640     "                    <div class=\"arrow\"></div>\n" +
22641     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +
22642     "                        <div class=\"tooltip-size-control\">\n" +
22643     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +
22644     "                                {{profile.email}}\n" +
22645     "                            </div>\n" +
22646     "                        </div>\n" +
22647     "                    </div>\n" +
22648     "                </div>\n" +
22649     "            </div>\n" +
22650     "            <div ng-if=\"!shouldClip(profile.email)\">\n" +
22651     "                {{profile.email}}\n" +
22652     "            </div>\n" +
22653     "            <label>Role</label>\n" +
22654     "            <div ng-if=\"shouldClip(profile.role)\" ng-mouseover=\"showRoleTooltip = true;\" ng-mouseleave=\"showRoleTooltip = false;\">\n" +
22655     "                <div ng-if=\"shouldClip(profile.role)\" class=\"tooltip\" b2b-tooltip show-tooltip=\"showRoleTooltip\">\n" +
22656     "                    {{profile.role.slice(0, 25)+'...'}}\n" +
22657     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +
22658     "                        <div class=\"tooltip-size-control\">\n" +
22659     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +
22660     "                                {{profile.role}}\n" +
22661     "                            </div>\n" +
22662     "                        </div>\n" +
22663     "                    </div>\n" +
22664     "                </div>\n" +
22665     "            </div>\n" +
22666     "            <div ng-if=\"!shouldClip(profile.role)\">\n" +
22667     "                {{profile.role}}\n" +
22668     "            </div>\n" +
22669     "            <label>Last login</label>\n" +
22670     "            <div ng-if=\"shouldClip(profile.lastLogin)\" ng-mouseover=\"showLastLoginTooltip = true;\" ng-mouseleave=\"showLastLoginTooltip = false;\">\n" +
22671     "                <div ng-if=\"shouldClip(profile.lastLogin)\" class=\"tooltip\" b2b-tooltip show-tooltip=\"showLastLoginTooltip\">\n" +
22672     "                    {{profile.lastLogin.slice(0, 25)+'...'}}\n" +
22673     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +
22674     "                        <div class=\"tooltip-size-control\">\n" +
22675     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +
22676     "                                {{profile.lastLogin}}\n" +
22677     "                            </div>\n" +
22678     "                        </div>\n" +
22679     "                    </div>\n" +
22680     "                </div>\n" +
22681     "            </div>\n" +
22682     "            <div ng-if=\"!shouldClip(profile.lastLogin)\">\n" +
22683     "                {{profile.lastLogin}}\n" +
22684     "            </div>\n" +
22685     "         </div>\n" +
22686     "    </div>\n" +
22687     "</div>");
22688 }]);
22689
22690 angular.module("b2bTemplate/searchField/searchField.html", []).run(["$templateCache", function($templateCache) {
22691   $templateCache.put("b2bTemplate/searchField/searchField.html",
22692     "<div class=\"search-bar\">\n" +
22693     "    <div class='input-container' ng-blur=\"blurInput()\">\n" +
22694     "        <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" +
22695     "            <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" +
22696     "    </div>\n" +
22697     "    <div class=\"search-suggestion-wrapper\" ng-if=\"filterList.length >=0\" ng-show=\"showListFlag\">\n" +
22698     "        <ul class=\"search-suggestion-list\" role=\"listbox\">      \n" +
22699     "            <li class=\"no-result\" ng-if=\"filterList.length == 0 && configObj.display\">{{configObj.resultText}}</li>\n" +
22700     "            <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" +
22701     "                {{item.title}}     \n" +
22702     "            </li>\n" +
22703     "        </ul>\n" +
22704     "    </div>\n" +
22705     "</div>");
22706 }]);
22707
22708 angular.module("b2bTemplate/seekBar/seekBar.html", []).run(["$templateCache", function($templateCache) {
22709   $templateCache.put("b2bTemplate/seekBar/seekBar.html",
22710     "<div class=\"b2b-seek-bar-container\" ng-class=\"{vertical:verticalSeekBar}\">\n" +
22711     "    <div class=\"b2b-seek-bar-track-container\">\n" +
22712     "        <div class=\"b2b-seek-bar-track\"></div>\n" +
22713     "        <div class=\"b2b-seek-bar-track-fill\"></div>\n" +
22714     "    </div>\n" +
22715     "    <div class=\"b2b-seek-bar-knob-container\" role=\"menu\"  >\n" +
22716     "        <div class=\"b2b-seek-bar-knob\" tabindex=\"0\" role=\"menuitem\"></div>\n" +
22717     "    </div>\n" +
22718     "</div>");
22719 }]);
22720
22721 angular.module("b2bTemplate/slider/slider.html", []).run(["$templateCache", function($templateCache) {
22722   $templateCache.put("b2bTemplate/slider/slider.html",
22723     "<div class=\"b2b-slider-container\" ng-class=\"{'vertical':verticalSlider}\">\n" +
22724     "    <div class=\"slider-track-container\">\n" +
22725     "        <div class=\"slider-track\"></div>\n" +
22726     "        <div class=\"slider-track-fill\" ng-style=\"{backgroundColor:trackFillColor}\"></div>\n" +
22727     "    </div>\n" +
22728     "    <div class=\"slider-knob-container\" ng-class=\"{'slider-knob-hidden':hideKnob}\">\n" +
22729     "        <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" +
22730     "    </div>\n" +
22731     "</div>");
22732 }]);
22733
22734 angular.module("b2bTemplate/spinButton/spinButton.html", []).run(["$templateCache", function($templateCache) {
22735   $templateCache.put("b2bTemplate/spinButton/spinButton.html",
22736     "<div class=\"btn-group btn-spinbutton-toggle\" ng-class=\"{'disabled': disabledFlag}\">\n" +
22737     "    <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" +
22738     "    <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" +
22739     "    <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" +
22740     "</div>");
22741 }]);
22742
22743 angular.module("b2bTemplate/statusTracker/statusTracker.html", []).run(["$templateCache", function($templateCache) {
22744   $templateCache.put("b2bTemplate/statusTracker/statusTracker.html",
22745     "<div class=\"b2b-status-tracker row\">\n" +
22746     "   <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" +
22747     "       <div class=\"btn btn-small btn-secondary\">\n" +
22748     "           <i class=\"icon-primary-left\"></i>\n" +
22749     "       </div>\n" +
22750     "   </button>\n" +
22751     "   <div ng-repeat=\"status in statuses\" class=\"b2b-status-tracker-step {{ status.state }}\" ng-show=\"isInViewport($index)\">\n" +
22752     "       <p class=\"b2b-status-tracker-heading\">{{status.heading}}</p>\n" +
22753     "       <div class=\"progress\">\n" +
22754     "           <div class=\"progress-bar\">\n" +
22755     "                   <span class=\"hidden-spoken\">\n" +
22756     "                   {{ removeCamelCase(status.state) }}\n" +
22757     "                   </span>\n" +
22758     "           </div>\n" +
22759     "       </div>\n" +
22760     "       <div class=\"b2b-status-tracker-estimate {{status.state}}\">\n" +
22761     "           <i ng-show=\"status.estimate !== '' && status.estimate !== undefined\" ng-class=\"b2bStatusTrackerConfig.icons[status.state]\"></i>\n" +
22762     "           &nbsp;\n" +
22763     "           <span ng-bind-html=\"status.estimate\"></span>\n" +
22764     "       </div>\n" +
22765     "       \n" +
22766     "       <div class=\"b2b-status-tracker-description\" ng-bind-html=\"status.description\"> \n" +
22767     "       </div>\n" +
22768     "   </div>\n" +
22769     "   <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" +
22770     "       <div class=\"btn btn-small btn-secondary\">\n" +
22771     "           <i class=\"icon-primary-right\"></i>\n" +
22772     "       </div>\n" +
22773     "   </button>\n" +
22774     "</div>");
22775 }]);
22776
22777 angular.module("b2bTemplate/stepTracker/stepTracker.html", []).run(["$templateCache", function($templateCache) {
22778   $templateCache.put("b2bTemplate/stepTracker/stepTracker.html",
22779     "<div class=\"b2b-step-tracker\">\n" +
22780     "    <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" +
22781     "           <div class=\"btn btn-left btn-small btn-secondary\"><i class=\"icon-primary-left\"></i></div>\n" +
22782     "   </button>\n" +
22783     "    <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" +
22784     "           <div class=\"btn btn-small btn-right btn-secondary\"><i class=\"icon-primary-right\"></i></div>\n" +
22785     "   </button>\n" +
22786     "    <ul class=\"b2b-steps\">\n" +
22787     "        <li ng-class=\"{'b2b-step-done':$index < currentIndex - 1 ,'b2b-step-on':$index == currentIndex - 1}\" \n" +
22788     "            ng-repeat=\"stepsItem in stepsItemsObject\" ng-show=\"isInViewport($index)\">\n" +
22789     "                   <p class=\"b2b-step-text\" data-sm-text=\"{{stepsItem.dataMobile}}\" data-large-text=\"{{stepsItem.dataDesktop}}\">{{stepsItem.text}}</p>\n" +
22790     "            <span class=\"hidden-spoken\">\n" +
22791     "                {{($index < currentIndex - 1)? 'Complete. '+stepsItem.text+' '+stepsItem.dataMobile:''}} \n" +
22792     "                {{($index == currentIndex - 1)? 'In Progress. '+stepsItem.text+' '+stepsItem.dataMobile:''}} \n" +
22793     "                {{($index > currentIndex - 1)? 'Incomplete. '+stepsItem.text+' '+stepsItem.dataMobile:''}}\n" +
22794     "            </span>\n" +
22795     "        </li>\n" +
22796     "    </ul>\n" +
22797     "</div>");
22798 }]);
22799
22800 angular.module("b2bTemplate/switches/switches-spanish.html", []).run(["$templateCache", function($templateCache) {
22801   $templateCache.put("b2bTemplate/switches/switches-spanish.html",
22802     "<div class=\"switch-overlay\" aria-hidden=\"true\">\n" +
22803     "    <span class=\"btn-slider-on\"><span class=\"hidden-spoken\">seleccione para hacer </span><i class=\"activo\">activo</i></span>\n" +
22804     "    <span class=\"switch-handle\"></span>\n" +
22805     "    <span class=\"btn-slider-off\"><span class=\"hidden-spoken\">seleccione para hacer </span><i class=\"inactivo\">inactivo</i></span>\n" +
22806     "</div>");
22807 }]);
22808
22809 angular.module("b2bTemplate/switches/switches.html", []).run(["$templateCache", function($templateCache) {
22810   $templateCache.put("b2bTemplate/switches/switches.html",
22811     "<div class=\"switch-overlay\" aria-hidden=\"true\">\n" +
22812     "    <span class=\"btn-slider-on\">On</span>\n" +
22813     "    <span class=\"switch-handle\"></span>\n" +
22814     "    <span class=\"btn-slider-off\">Off</span>\n" +
22815     "</div>");
22816 }]);
22817
22818 angular.module("b2bTemplate/tableMessages/tableMessage.html", []).run(["$templateCache", function($templateCache) {
22819   $templateCache.put("b2bTemplate/tableMessages/tableMessage.html",
22820     "<div class=\"b2b-table-message\">\n" +
22821     "    <div class=\"b2b-message\" ng-if=\"msgType === 'noMatchingResults'\">\n" +
22822     "        <div class=\"b2b-magnify-glass\"></div>\n" +
22823     "        <div>\n" +
22824     "            <div ng-transclude></div>\n" +
22825     "        </div>\n" +
22826     "    </div>\n" +
22827     "    <div class=\"b2b-message\" ng-if=\"msgType == 'infoCouldNotLoad'\">\n" +
22828     "        <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" +
22829     "        <div>Oops!</div>\n" +
22830     "        <div>The information could not load at this time.</div>\n" +
22831     "        <div>Please <a href=\"javascript:void(0)\" title=\"Refresh the page\" ng-click=\"refreshAction($event)\">refresh the page</a>\n" +
22832     "        </div>\n" +
22833     "    </div>\n" +
22834     "    <div class=\"b2b-message\" ng-if=\"msgType == 'magnifySearch'\">\n" +
22835     "        <div class=\"b2b-magnify-glass\"></div>\n" +
22836     "        <div>\n" +
22837     "            <p class=\"b2b-message-title\">Please input values to\n" +
22838     "                <br/> begin your search.</p>\n" +
22839     "        </div>\n" +
22840     "    </div>\n" +
22841     "    <div class=\"b2b-message\" ng-if=\"msgType === 'loadingTable'\">\n" +
22842     "        <div class=\"icon-primary-spinner-ddh b2b-loading-dots\"></div>\n" +
22843     "        <div ng-transclude></div>\n" +
22844     "    </div>\n" +
22845     "</div>\n" +
22846     "");
22847 }]);
22848
22849 angular.module("b2bTemplate/tableScrollbar/tableScrollbar.html", []).run(["$templateCache", function($templateCache) {
22850   $templateCache.put("b2bTemplate/tableScrollbar/tableScrollbar.html",
22851     "<div class=\"b2b-table-scrollbar\">\n" +
22852     "    <div class=\"b2b-scrollbar-arrows\">\n" +
22853     "        <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" +
22854     "        <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" +
22855     "    </div>\n" +
22856     "    <div class=\"b2b-table-inner-container\">\n" +
22857     "        <span ng-transclude></span>\n" +
22858     "    </div>\n" +
22859     "</div>");
22860 }]);
22861
22862 angular.module("b2bTemplate/tables/b2bTable.html", []).run(["$templateCache", function($templateCache) {
22863   $templateCache.put("b2bTemplate/tables/b2bTable.html",
22864     "<table ng-class=\"{'striped': responsive, 'complex-table': responsive && active}\" ng-transclude></table>");
22865 }]);
22866
22867 angular.module("b2bTemplate/tables/b2bTableBody.html", []).run(["$templateCache", function($templateCache) {
22868   $templateCache.put("b2bTemplate/tables/b2bTableBody.html",
22869     "<td ng-hide=\"isHidden()\" ng-transclude></td>");
22870 }]);
22871
22872 angular.module("b2bTemplate/tables/b2bTableHeaderSortable.html", []).run(["$templateCache", function($templateCache) {
22873   $templateCache.put("b2bTemplate/tables/b2bTableHeaderSortable.html",
22874     "<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" +
22875     "    <span ng-transclude></span>\n" +
22876     "    <i ng-class=\"{'icon-controls-upPRIMARY active': sortPattern === 'ascending', 'icon-controls-down active down': sortPattern === 'descending'}\"></i>\n" +
22877     "</th>");
22878 }]);
22879
22880 angular.module("b2bTemplate/tables/b2bTableHeaderUnsortable.html", []).run(["$templateCache", function($templateCache) {
22881   $templateCache.put("b2bTemplate/tables/b2bTableHeaderUnsortable.html",
22882     "<th scope=\"col\" ng-hide=\"isHidden()\" ng-transclude></th>");
22883 }]);
22884
22885 angular.module("b2bTemplate/tabs/b2bTab.html", []).run(["$templateCache", function($templateCache) {
22886   $templateCache.put("b2bTemplate/tabs/b2bTab.html",
22887     "<li role=\"tab\" aria-selected=\"{{isTabActive()}}\" aria-controls=\"{{tabPanelId}}\" class=\"tab\" \n" +
22888     "    ng-class=\"{'active': isTabActive()}\" ng-click=\"clickTab()\" ng-hide=\"tabItem.disabled\">\n" +
22889     "    <a href=\"javascript:void(0)\"  tabindex=\"{{(isTabActive() && tabItem.disabled)?-1:0}}\"\n" +
22890     "       ng-disabled=\"tabItem.disabled\" aria-expanded=\"{{(isTabActive() && !tabItem.disabled)}}\" \n" +
22891     "       b2b-accessibility-click=\"13,32\" ng-transclude></a>\n" +
22892     "    <span class=\"hidden-spoken\" ng-if=\"isTabActive()\">Active tab</span>\n" +
22893     "</li>");
22894 }]);
22895
22896 angular.module("b2bTemplate/tabs/b2bTabset.html", []).run(["$templateCache", function($templateCache) {
22897   $templateCache.put("b2bTemplate/tabs/b2bTabset.html",
22898     "<ul class=\"tabs promo-tabs\" role=\"tablist\" ng-transclude></ul>");
22899 }]);
22900
22901 angular.module("b2bTemplate/treeNav/groupedTree.html", []).run(["$templateCache", function($templateCache) {
22902   $templateCache.put("b2bTemplate/treeNav/groupedTree.html",
22903     "<ul role=\"group\">\n" +
22904     "    <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" +
22905     "        <ul role=\"group\">\n" +
22906     "            <b2b-member ng-repeat='member in value.childArray' member='member' time-delay='{{timeDelay}}' group-it='groupIt'></b2b-member>\n" +
22907     "        </ul>\n" +
22908     "    </li>\n" +
22909     "</ul>");
22910 }]);
22911
22912 angular.module("b2bTemplate/treeNav/treeMember.html", []).run(["$templateCache", function($templateCache) {
22913   $templateCache.put("b2bTemplate/treeNav/treeMember.html",
22914     "<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" +
22915     "    <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" +
22916     "        <span class=\"{{!member.child?'end':''}} b2b-tree-node-icon\">\n" +
22917     "            <i class=\"b2b-tree-expandCollapse-icon\" ng-class=\"{'icon-primary-expanded':member.active}\"></i>\n" +
22918     "        </span>\n" +
22919     "         <div id=\"description_{{$id}}\" class=\"offscreen-text\">\n" +
22920     "           {{member.descriptionText}}\n" +
22921     "        </div>\n" +
22922     "        <div class=\"b2b-tree-tooltip\" ng-if=\"member.showTooltip\">\n" +
22923     "           <span class=\"b2b-tree-arrow-left\"></span>\n" +
22924     "           <div class=\"b2b-tree-tooltip-content\">\n" +
22925     "                   {{member.tooltipContent}}\n" +
22926     "           </div>  \n" +
22927     "        </div>\n" +
22928     "    </a>\n" +
22929     "</li>");
22930 }]);
22931
22932 angular.module("b2bTemplate/treeNav/ungroupedTree.html", []).run(["$templateCache", function($templateCache) {
22933   $templateCache.put("b2bTemplate/treeNav/ungroupedTree.html",
22934     "<ul role=\"{{setRole}}\"><b2b-member ng-repeat='member in collection' member='member' group-it='groupIt'></b2b-member></ul>");
22935 }]);
22936
22937 angular.module("b2bTemplate/treeNodeCheckbox/groupedTree.html", []).run(["$templateCache", function($templateCache) {
22938   $templateCache.put("b2bTemplate/treeNodeCheckbox/groupedTree.html",
22939     "<ul role=\"group\">\n" +
22940     "    <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" +
22941     "        <span class=\"ng-hide\">\n" +
22942     "            <label class=\"checkbox\">\n" +
22943     "                <input type=\"checkbox\" tabindex=\"-1\" class=\"treeCheckBox grpTreeCheckbox\" style=\"margin-top:2px;\"/><i class=\"skin\"></i><span> {{(key)?key:''}}</span>\n" +
22944     "            </label>\n" +
22945     "        </span>\n" +
22946     "        <span>\n" +
22947     "            {{(key)?key:''}}    \n" +
22948     "        </span>\n" +
22949     "        <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" +
22950     "        <ul role=\"group\">\n" +
22951     "            <b2b-tree-member ng-repeat='member in value.childArray' member='member' group-it='groupIt'></b2b-tree-member>\n" +
22952     "        </ul>\n" +
22953     "    </li>\n" +
22954     "</ul>");
22955 }]);
22956
22957 angular.module("b2bTemplate/treeNodeCheckbox/treeMember.html", []).run(["$templateCache", function($templateCache) {
22958   $templateCache.put("b2bTemplate/treeNodeCheckbox/treeMember.html",
22959     "<li role=\"treeitem\" aria-expanded=\"{{(member.active?true:false)}}\" aria-label=\"{{member.name}}\" ng-class=\"{'bg':member.selected}\"  b2b-tree-node-link>\n" +
22960     "    <a tabindex=\"-1\" title=\"{{member.name}}\" href=\"javascript:void(0)\" ng-class=\"{'active':member.active}\">\n" +
22961     "           <span ng-show=\"member.displayCheckbox\">\n" +
22962     "                           <label class=\"checkbox\">\n" +
22963     "                <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" +
22964     "            </label>\n" +
22965     "        </span>\n" +
22966     "           <span ng-show=\"!member.displayCheckbox\">\n" +
22967     "                   {{member.name}} \n" +
22968     "           </span>\n" +
22969     "        <span class=\"nodeIcon {{!member.child?'end':''}}\">\n" +
22970     "            <i class=\"expandCollapseIcon\" ng-class=\"{'icon-primary-expanded':member.active}\"></i>\n" +
22971     "        </span>\n" +
22972     "    </a>\n" +
22973     "</li>");
22974 }]);
22975
22976 angular.module("b2bTemplate/treeNodeCheckbox/ungroupedTree.html", []).run(["$templateCache", function($templateCache) {
22977   $templateCache.put("b2bTemplate/treeNodeCheckbox/ungroupedTree.html",
22978     "<ul role=\"{{setRole}}\"><b2b-tree-member ng-repeat='member in collection' member='member' group-it='groupIt'></b2b-tree-member></ul>");
22979 }]);