0e62a349480bb34f62ad58314787243770f7dab4
[portal/sdk.git] /
1 /*! b2b-angular-library - v1.0.1 - Last updated: 2017-03-02. 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.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.headings','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.selectorModule','b2b.att.separators','b2b.att.slider','b2b.att.spinButton','b2b.att.staticRouteTemplate','b2b.att.statusTracker','b2b.att.stepTracker','b2b.att.switches','b2b.att.tableMessages','b2b.att.tables','b2b.att.tableScrollbar','b2b.att.tabs','b2b.att.tagBadges','b2b.att.textArea','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 Navigation.att:breadcrumbs
1011  *
1012  * @description
1013  *  <file src="src/breadcrumbs/docs/readme.md" />
1014  * @usage
1015     <ul class="breadcrumb">
1016         <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>
1017     </ul>
1018  * @example
1019  <example module="b2b.att">
1020  <file src="src/breadcrumbs/docs/demo.html" />
1021  <file src="src/breadcrumbs/docs/demo.js" />
1022  </example>
1023  */
1024 angular.module('b2b.att.breadcrumbs',[])
1025 /**
1026  * @ngdoc directive
1027  * @name Buttons, links & UI controls.att:buttonGroups
1028  *
1029  * @description
1030  *  <file src="src/buttonGroups/docs/readme.md" />
1031  *
1032  * @usage
1033 <h2>Radio Aproach</h2>
1034 <div class="btn-group" b2b-key prev="37,38" next="39,40" circular-traversal role="radiogroup">
1035     <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>
1036     <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>
1037     <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>
1038 </div>
1039
1040 <h2>Checkbox Aproach</h2>
1041 <span b2b-button-group class="btn-group btn-fullwidth" role="group" max-select="3" ng-model="checkModel1">
1042     <button type="button" class="btn btn-secondary" ng-model="checkModel1.Button1" b2b-btn-checkbox>Button1</button>
1043     <button type="button" class="btn btn-secondary" ng-model="checkModel1.Button2" b2b-btn-checkbox>Button2</button>
1044     <button type="button" class="btn btn-secondary" ng-model="checkModel1.Button3" b2b-btn-checkbox>Button3</button>
1045     <button type="button" class="btn btn-secondary" ng-model="checkModel1.Button4" b2b-btn-checkbox>Button4</button>
1046     <button type="button" class="btn btn-secondary" ng-model="checkModel1.Button5" b2b-btn-checkbox>Button5</button>
1047 </span>
1048  *
1049  * @example
1050  *  <section id="code">
1051         <example module="b2b.att">
1052             <file src="src/buttonGroups/docs/demo.html" />
1053             <file src="src/buttonGroups/docs/demo.js" />
1054        </example>
1055         </section>
1056  *
1057  */
1058 angular.module('b2b.att.buttonGroups', ['b2b.att.utilities'])
1059     .constant('buttonConfig', {
1060         activeClass: 'active',
1061         toggleEvent: 'click'
1062     })
1063     .directive('b2bBtnRadio', ['buttonConfig', function (buttonConfig) {
1064         var activeClass = buttonConfig.activeClass || 'active';
1065         var toggleEvent = buttonConfig.toggleEvent || 'click';
1066
1067         return {
1068             require: 'ngModel',
1069             link: function (scope, element, attrs, ngModelCtrl) {
1070                 var notMobile = !/Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
1071
1072                 if (notMobile) {
1073                     element.bind('focus', function () {
1074                         scope.$apply(function () {
1075                             ngModelCtrl.$setViewValue(scope.$eval(attrs.b2bBtnRadio));
1076                             ngModelCtrl.$render();
1077                         });
1078                     });
1079                 }
1080
1081                 element.attr('role', 'radio');
1082
1083                 //model -> UI
1084                 ngModelCtrl.$render = function () {
1085                     element.toggleClass(activeClass, angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.b2bBtnRadio)));
1086                     if (angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.b2bBtnRadio))) {
1087                         element.attr("aria-checked", true);
1088                     } else {
1089                         element.attr("aria-checked", false);
1090                     }
1091                 };
1092
1093                 //ui->model
1094                 element.bind(toggleEvent, function () {
1095                     if (!element.hasClass(activeClass)) {
1096                         scope.$apply(function () {
1097                             ngModelCtrl.$setViewValue(scope.$eval(attrs.b2bBtnRadio));
1098                             ngModelCtrl.$render();
1099                         });
1100                     }
1101                 });
1102             }
1103         };
1104     }])
1105     .directive('b2bBtnCheckbox', ['buttonConfig', function (buttonConfig) {
1106         var activeClass = buttonConfig.activeClass || 'active';
1107         var toggleEvent = buttonConfig.toggleEvent || 'click';
1108
1109         return {
1110             require: ['ngModel', '^^b2bButtonGroup'],
1111             link: function (scope, element, attrs, ctrls) {
1112
1113                 var ngModelCtrl = ctrls[0];
1114                 var parentCtrl = ctrls[1];
1115
1116                 element.attr('role', 'checkbox');
1117                 element.attr('aria-describedby', parentCtrl.getStateDescriptionElemId());
1118
1119                 function getTrueValue() {
1120                     var trueValue = scope.$eval(attrs.b2bBtnCheckboxTrue);
1121                     return angular.isDefined(trueValue) ? trueValue : true;
1122                 }
1123
1124                 function getFalseValue() {
1125                     var falseValue = scope.$eval(attrs.b2bBtnCheckboxFalse);
1126                     return angular.isDefined(falseValue) ? falseValue : false;
1127                 }
1128
1129                 //model -> UI
1130                 ngModelCtrl.$render = function () {
1131                     element.toggleClass(activeClass, angular.equals(ngModelCtrl.$modelValue, getTrueValue()));
1132                     if ((angular.equals(ngModelCtrl.$modelValue, getTrueValue()))) {
1133                         element.attr("aria-checked", true);
1134                     } else {
1135                         element.attr("aria-checked", false);
1136                     }
1137                 };
1138
1139                 //ui->model
1140                 element.bind(toggleEvent, function () {
1141                     scope.$apply(function () {
1142                         ngModelCtrl.$setViewValue(element.hasClass(activeClass) ? getFalseValue() : getTrueValue());
1143                         ngModelCtrl.$render();
1144                     });
1145                 });
1146             }
1147         };
1148     }])
1149     .directive('b2bButtonGroup', ['$timeout', '$compile', function ($timeout, $compile) {
1150         return {
1151             restrict: 'A',
1152             scope: {
1153                 maxSelect: "=",
1154                 ngModelButtonState: '=ngModel'
1155             },
1156             controller: ['$scope', '$element', function ($scope, $element) {
1157                 $scope.nSel = 0;
1158
1159                 var stateDescriptionElem = angular.element('<span id="b2b_button_group_' + $scope.$id + '" class="hide" aria-hidden="true">{{nSel}} of {{maxSelect}} options selected.</span>');
1160                 $compile(stateDescriptionElem)($scope);
1161                 $element.after(stateDescriptionElem);
1162
1163                 this.getStateDescriptionElemId = function () {
1164                     return stateDescriptionElem.attr('id');
1165                 };
1166             }],
1167             link: function (scope, element) {
1168
1169
1170                 var executeFxn = function () {
1171                     scope.nSel = 0;
1172                     angular.forEach(scope.ngModelButtonState, function (value, key) {
1173                         if (value === true) {
1174                             scope.nSel += 1;
1175                         }
1176                     });
1177
1178                     if (scope.nSel >= scope.maxSelect) {
1179                         angular.forEach(element.children(), function (chd) {
1180                             if (chd.className.indexOf('active') < 0) {
1181                                 chd.disabled = true;
1182                                 chd.setAttribute('aria-disabled', true);
1183                             }
1184                         });
1185                     } else {
1186                         angular.forEach(element.children(), function (chd) {
1187                             chd.disabled = false;
1188                             chd.setAttribute('aria-disabled', false);
1189                         });
1190                     }
1191                     scope.$digest();
1192                 };
1193
1194                 $timeout(function () {
1195                     executeFxn();
1196                 });
1197                 element.bind('click', executeFxn);
1198             }
1199         };
1200     }]);
1201 /**
1202  * @ngdoc directive
1203  * @name Buttons, links & UI controls.att:buttons
1204  * @element input
1205  * @function
1206  *
1207  * @description
1208  *  <file src="src/buttons/docs/readme.md" />
1209  * @usage
1210  *
1211 Button shape
1212 <button class="btn" type="button">Button</button> button.btn (button shape only)
1213 <button aria-label="Custom aria label" class="btn" type="button">Button</button> button.btn (button shape only) with custom aria label
1214 <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
1215 <a b2b-keyup-click="32" href="javascript:void(0)" class="btn" role="button">Button</a> a.btn (button shape only)
1216 <button class="btn btn-primary">Button</button> .btn-primary
1217 <a b2b-keyup-click="32" href="javascript:void(0)" class="btn btn-primary" role="button">Button</a> a.btn-primary
1218
1219 5 Button colors
1220 <button class="btn btn-secondary">Button</button> .btn-secondary
1221 <a b2b-keyup-click="32" href="javascript:void(0)" class="btn btn-secondary" role="button">Button</a> a.btn-secondary
1222 <button class="btn btn-alt">Button</button> .btn-alt
1223 <a b2b-keyup-click="32" href="javascript:void(0)" class="btn btn-alt" role="button">Button</a> a.btn-alt
1224 <button class="btn btn-specialty">Button</button> .btn-specialty
1225 <a b2b-keyup-click="32" href="javascript:void(0)" class="btn btn-specialty" role="button">Button</a> a.btn-specialty
1226 <button class="btn btn-specialty" disabled="">Button</button> disabled="disabled"
1227 <a b2b-keyup-click="32" aria-disabled="true" href="javascript:void(0)" class="btn btn-primary disabled" role="button">Button</a> a.disabled
1228
1229 3 button heights
1230 <button class="btn btn-secondary">Button</button> .btn is default and 46px height
1231 <button class="btn btn-secondary btn-medium">Button</button> .btn-medium is 42px
1232 <button class="btn btn-secondary btn-small">Button</button> .btn-small is 36px
1233
1234 .row-nowrap 2 up buttons
1235 <div class="row-nowrap">
1236     <button class="btn btn-secondary btn-fullwidth" type="button">Cancel</button>
1237     <button class="btn btn-primary btn-fullwidth" type="button">Continue</button>
1238 </div>
1239
1240 .row 2 up buttons (desktop) stacked (mobile) (different order)
1241 <div class="row cta-button-group">
1242     <button class="span btn btn-secondary btn-fullwidth hidden-phone" type="button">Cancel</button>
1243     <button class="span btn btn-primary btn-fullwidth" type="button">Continue</button>
1244     <button class="span btn btn-secondary btn-fullwidth visible-phone" type="button">Cancel</button>
1245 </div>
1246
1247  * @example
1248  *  <section id="code">
1249                <b>HTML + AngularJS</b>
1250  *              <example module="b2b.att">
1251  *              <file src="src/buttons/docs/demo.html" />
1252                  <file src="src/buttons/docs/demo.js" />
1253  *              </example>
1254             </section>
1255  *
1256  */
1257 angular.module('b2b.att.buttons', ['b2b.att.utilities']);
1258 /**
1259  * @ngdoc directive
1260  * @name Forms.att:calendar
1261  *
1262  * @description
1263  *  <file src="src/calendar/docs/readme.md" />
1264  * @usage
1265  *  <input type="text" ng-model="dt" b2b-datepicker>
1266  *
1267  * @example
1268    <section id="code">
1269     <b>HTML + AngularJS</b>
1270     <example module="b2b.att">
1271      <file src="src/calendar/docs/demo.html" />
1272      <file src="src/calendar/docs/demo.js" />
1273     </example>
1274    </section>
1275  */
1276 angular.module('b2b.att.calendar', ['b2b.att.position', 'b2b.att.utilities'])
1277
1278 .constant('b2bDatepickerConfig', {
1279     dateFormat: 'MM/dd/yyyy',
1280     dayFormat: 'd',
1281     monthFormat: 'MMMM',
1282     yearFormat: 'yyyy',
1283     dayHeaderFormat: 'EEEE',
1284     dayTitleFormat: 'MMMM yyyy',
1285     disableWeekend: false,
1286     disableSunday: false,
1287     disableDates: null,
1288     onSelectClose: null,
1289     startingDay: 0,
1290     minDate: null,
1291     maxDate: null,
1292     dueDate: null,
1293     fromDate: null,
1294     legendIcon: null,
1295     legendMessage: null,
1296     calendarDisabled: false,
1297     collapseWait: 0,
1298     orientation: 'left',
1299     inline: false,
1300     helperText: 'The date you selected is $date. In case of mobile double tap to open calendar. Select a date to close the calendar.',
1301     datepickerEvalAttributes: ['dateFormat', 'dayFormat', 'monthFormat', 'yearFormat', 'dayHeaderFormat', 'dayTitleFormat', 'disableWeekend', 'disableSunday', 'startingDay', 'collapseWait', 'orientation'],
1302     datepickerWatchAttributes: ['min', 'max', 'due', 'from', 'legendIcon', 'legendMessage', 'ngDisabled'],
1303     datepickerFunctionAttributes: ['disableDates', 'onSelectClose']
1304 })
1305
1306 .factory('b2bDatepickerService', ['b2bDatepickerConfig', 'dateFilter', function (b2bDatepickerConfig, dateFilter) {
1307     var setAttributes = function (attr, elem) {
1308         if (angular.isDefined(attr) && attr !== null && angular.isDefined(elem) && elem !== null) {
1309             var attributes = b2bDatepickerConfig.datepickerEvalAttributes.concat(b2bDatepickerConfig.datepickerWatchAttributes, b2bDatepickerConfig.datepickerFunctionAttributes);
1310             for (var key in attr) {
1311                 var val = attr[key];
1312                 if (attributes.indexOf(key) !== -1 && angular.isDefined(val)) {
1313                     elem.attr(key.toSnakeCase(), key);
1314                 }
1315             }
1316         }
1317     };
1318
1319     var bindScope = function (attr, scope) {
1320         if (angular.isDefined(attr) && attr !== null && angular.isDefined(scope) && scope !== null) {
1321             var evalFunction = function (key, val) {
1322                 scope[key] = scope.$parent.$eval(val);
1323             };
1324
1325             var watchFunction = function (key, val) {
1326                 scope.$parent.$watch(val, function (value) {
1327                     scope[key] = value;
1328                 });
1329                 scope.$watch(key, function (value) {
1330                     scope.$parent[val] = value;
1331                 });
1332             };
1333
1334             var evalAttributes = b2bDatepickerConfig.datepickerEvalAttributes;
1335             var watchAttributes = b2bDatepickerConfig.datepickerWatchAttributes;
1336             for (var key in attr) {
1337                 var val = attr[key];
1338                 if (evalAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {
1339                     evalFunction(key, val);
1340                 } else if (watchAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {
1341                     watchFunction(key, val);
1342                 }
1343             }
1344         }
1345     };
1346
1347     return {
1348         setAttributes: setAttributes,
1349         bindScope: bindScope
1350     };
1351 }])
1352
1353 .controller('b2bDatepickerController', ['$scope', '$attrs', 'dateFilter', '$element', '$position', 'b2bDatepickerConfig', function ($scope, $attrs, dateFilter, $element, $position, dtConfig) {
1354     var format = {
1355             date: getValue($attrs.dateFormat, dtConfig.dateFormat),
1356             day: getValue($attrs.dayFormat, dtConfig.dayFormat),
1357             month: getValue($attrs.monthFormat, dtConfig.monthFormat),
1358             year: getValue($attrs.yearFormat, dtConfig.yearFormat),
1359             dayHeader: getValue($attrs.dayHeaderFormat, dtConfig.dayHeaderFormat),
1360             dayTitle: getValue($attrs.dayTitleFormat, dtConfig.dayTitleFormat),
1361             disableWeekend: getValue($attrs.disableWeekend, dtConfig.disableWeekend),
1362             disableSunday: getValue($attrs.disableSunday, dtConfig.disableSunday),
1363             disableDates: getValue($attrs.disableDates, dtConfig.disableDates)
1364         },
1365         startingDay = getValue($attrs.startingDay, dtConfig.startingDay);
1366
1367     $scope.minDate = dtConfig.minDate ? $scope.resetTime(dtConfig.minDate) : null;
1368     $scope.maxDate = dtConfig.maxDate ? $scope.resetTime(dtConfig.maxDate) : null;
1369     $scope.dueDate = dtConfig.dueDate ? $scope.resetTime(dtConfig.dueDate) : null;
1370     $scope.fromDate = dtConfig.fromDate ? $scope.resetTime(dtConfig.fromDate) : null;
1371     $scope.legendIcon = dtConfig.legendIcon ? dtConfig.legendIcon : null;
1372     $scope.legendMessage = dtConfig.legendMessage ? dtConfig.legendMessage : null;
1373     $scope.ngDisabled = dtConfig.calendarDisabled ? dtConfig.calendarDisabled : null;
1374     $scope.collapseWait = getValue($attrs.collapseWait, dtConfig.collapseWait);
1375     $scope.orientation = getValue($attrs.orientation, dtConfig.orientation);
1376     $scope.onSelectClose = getValue($attrs.onSelectClose, dtConfig.onSelectClose);
1377
1378     $scope.inline = $attrs.inline === 'true' ? true : dtConfig.inline;
1379
1380     function getValue(value, defaultValue) {
1381         return angular.isDefined(value) ? $scope.$parent.$eval(value) : defaultValue;
1382     }
1383
1384     function getDaysInMonth(year, month) {
1385         return new Date(year, month, 0).getDate();
1386     }
1387
1388     function getDates(startDate, n) {
1389         var dates = new Array(n);
1390         var current = startDate,
1391             i = 0;
1392         while (i < n) {
1393             dates[i++] = new Date(current);
1394             current.setDate(current.getDate() + 1);
1395         }
1396         return dates;
1397     }
1398
1399     this.updatePosition = function (b2bDatepickerPopupTemplate) {
1400         $scope.position = $position.offset($element);
1401         $scope.position.top = $scope.position.top + $element.find('input').prop('offsetHeight');
1402         if ($scope.orientation === 'right') {
1403             $scope.position.left = $scope.position.left - (((b2bDatepickerPopupTemplate && b2bDatepickerPopupTemplate.prop('offsetWidth')) || 290) - $element.find('input').prop('offsetWidth'));
1404         }
1405     };
1406
1407     function isSelected(dt) {
1408         if (dt && angular.isDate($scope.currentDate) && compare(dt, $scope.currentDate) === 0) {
1409             return true;
1410         }
1411         return false;
1412     }
1413
1414     function isFromDate(dt) {
1415         if (dt && angular.isDate($scope.fromDate) && compare(dt, $scope.fromDate) === 0) {
1416             return true;
1417         }
1418         return false;
1419     }
1420
1421     function isDateRange(dt) {
1422         if (dt && $scope.fromDate && angular.isDate($scope.currentDate) && (compare(dt, $scope.fromDate) >= 0) && (compare(dt, $scope.currentDate) <= 0)) {
1423             return true;
1424         } else if (dt && $scope.fromDate && compare(dt, $scope.fromDate) === 0) {
1425             return true;
1426         }
1427         return false;
1428     }
1429
1430     function isOld(date, currentMonthDate) {
1431         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())) {
1432             return true;
1433         } else {
1434             return false;
1435         }
1436     }
1437
1438     function isNew(date, currentMonthDate) {
1439         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())) {
1440             return true;
1441         } else {
1442             return false;
1443         }
1444     }
1445
1446     function isPastDue(dt) {
1447         if ($scope.dueDate) {
1448             return (dt > $scope.dueDate);
1449         }
1450         return false;
1451     }
1452
1453     function isDueDate(dt) {
1454         if ($scope.dueDate) {
1455             return (dt.getTime() === $scope.dueDate.getTime());
1456         }
1457         return false;
1458     }
1459
1460     var isDisabled = function (date, currentMonthDate) {
1461         if ($attrs.from && !angular.isDate($scope.fromDate)) {
1462             return true;
1463         }
1464         if (format.disableWeekend === true && (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday")) {
1465             return true;
1466         }
1467         if (format.disableSunday === true && (dateFilter(date, format.dayHeader) === "Sunday")) {
1468             return true;
1469         }
1470         if (isOld(date, currentMonthDate) || isNew(date, currentMonthDate)) {
1471             return true;
1472         }
1473         return (($scope.minDate && compare(date, $scope.minDate) < 0) || ($scope.maxDate && compare(date, $scope.maxDate) > 0) || (format.disableDates && format.disableDates({
1474             date: date
1475         })));
1476     };
1477
1478     var compare = function (date1, date2) {
1479         return (new Date(date1.getFullYear(), date1.getMonth(), date1.getDate()) - new Date(date2.getFullYear(), date2.getMonth(), date2.getDate()));
1480     };
1481
1482     function isMinDateAvailable(startDate, endDate) {
1483         if (($scope.minDate && $scope.minDate.getTime() >= startDate.getTime()) && ($scope.minDate.getTime() <= endDate.getTime())) {
1484             $scope.disablePrev = true;
1485             $scope.visibilityPrev = "hidden";
1486         } else {
1487             $scope.disablePrev = false;
1488             $scope.visibilityPrev = "visible";
1489         }
1490     }
1491
1492     function isMaxDateAvailable(startDate, endDate) {
1493         if (($scope.maxDate && $scope.maxDate.getTime() >= startDate.getTime()) && ($scope.maxDate.getTime() <= endDate.getTime())) {
1494             $scope.disableNext = true;
1495             $scope.visibilityNext = "hidden";
1496         } else {
1497             $scope.disableNext = false;
1498             $scope.visibilityNext = "visible";
1499         }
1500     }
1501
1502     function getLabel(label) {
1503         if (label) {
1504             var labelObj = {
1505                 pre: label.substr(0, 1).toUpperCase(),
1506                 post: label
1507             };
1508             return labelObj;
1509         }
1510         return;
1511     }
1512
1513     function makeDate(date, dayFormat, dayHeaderFormat, isSelected, isFromDate, isDateRange, isOld, isNew, isDisabled, dueDate, pastDue) {
1514         return {
1515             date: date,
1516             label: dateFilter(date, dayFormat),
1517             header: dateFilter(date, dayHeaderFormat),
1518             selected: !!isSelected,
1519             fromDate: !!isFromDate,
1520             dateRange: !!isDateRange,
1521             oldMonth: !!isOld,
1522             nextMonth: !!isNew,
1523             disabled: !!isDisabled,
1524             dueDate: !!dueDate,
1525             pastDue: !!pastDue,
1526             focusable: !((isDisabled && !(isSelected || isDateRange)) || (isOld || isNew))
1527         };
1528     }
1529
1530     this.modes = [
1531         {
1532             name: 'day',
1533             getVisibleDates: function (date) {
1534                 var year = date.getFullYear(),
1535                     month = date.getMonth(),
1536                     firstDayOfMonth = new Date(year, month, 1),
1537                     lastDayOfMonth = new Date(year, month + 1, 0);
1538                 var difference = startingDay - firstDayOfMonth.getDay(),
1539                     numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : -difference,
1540                     firstDate = new Date(firstDayOfMonth),
1541                     numDates = 0;
1542
1543                 if (numDisplayedFromPreviousMonth > 0) {
1544                     firstDate.setDate(-numDisplayedFromPreviousMonth + 1);
1545                     numDates += numDisplayedFromPreviousMonth; // Previous
1546                 }
1547                 numDates += getDaysInMonth(year, month + 1); // Current
1548                 numDates += (7 - numDates % 7) % 7; // Next
1549
1550                 var days = getDates(firstDate, numDates),
1551                     labels = new Array(7);
1552                 for (var i = 0; i < numDates; i++) {
1553                     var dt = new Date(days[i]);
1554                     days[i] = makeDate(dt,
1555                         format.day,
1556                         format.dayHeader,
1557                         isSelected(dt),
1558                         isFromDate(dt),
1559                         isDateRange(dt),
1560                         isOld(dt, date),
1561                         isNew(dt, date),
1562                         isDisabled(dt, date),
1563                         isDueDate(dt),
1564                         isPastDue(dt));
1565                 }
1566                 for (var j = 0; j < 7; j++) {
1567                     labels[j] = getLabel(dateFilter(days[j].date, format.dayHeader));
1568                 }
1569                 isMinDateAvailable(firstDayOfMonth, lastDayOfMonth);
1570                 isMaxDateAvailable(firstDayOfMonth, lastDayOfMonth);
1571                 return {
1572                     objects: days,
1573                     title: dateFilter(date, format.dayTitle),
1574                     labels: labels
1575                 };
1576             },
1577             split: 7,
1578             step: {
1579                 months: 1
1580             }
1581         }
1582     ];
1583 }])
1584
1585 .directive('b2bDatepickerPopup', ['$parse', '$log', '$timeout', '$document', '$documentBind', '$isElement', '$templateCache', '$compile', 'trapFocusInElement', '$position', '$window', function ($parse, $log, $timeout, $document, $documentBind, $isElement, $templateCache, $compile, trapFocusInElement, $position, $window) {
1586     return {
1587         restrict: 'EA',
1588         replace: true,
1589         transclude: true,
1590         templateUrl: function (elem, attr) {
1591             if (attr.inline === 'true') {
1592                 return 'b2bTemplate/calendar/datepicker-popup.html';
1593             } else {
1594                 return 'b2bTemplate/calendar/datepicker.html';
1595             }
1596         },
1597         scope: {},
1598         require: ['b2bDatepickerPopup', 'ngModel', '?^b2bDatepickerGroup'],
1599         controller: 'b2bDatepickerController',
1600         link: function (scope, element, attrs, ctrls) {
1601             var datepickerCtrl = ctrls[0],
1602                 ngModel = ctrls[1],
1603                 b2bDatepickerGroupCtrl = ctrls[2];
1604             var b2bDatepickerPopupTemplate;
1605
1606             if (!ngModel) {
1607                 $log.error("ng-model is required.");
1608                 return; // do nothing if no ng-model
1609             }
1610
1611             // Configuration parameters
1612             var mode = 0,
1613                 selected;
1614             scope.isOpen = false;
1615
1616             scope.headers = [];
1617             scope.footers = [];
1618
1619             if (b2bDatepickerGroupCtrl) {
1620                 b2bDatepickerGroupCtrl.registerDatepickerScope(scope);
1621             }
1622
1623             element.find('button').bind('click', function () {
1624                 element.find('input')[0].click();
1625             });
1626
1627             element.find('input').bind('click', function () {
1628                 if (!scope.ngDisabled) {
1629                     scope.isOpen = !scope.isOpen;
1630                     toggleCalendar(scope.isOpen);
1631                     scope.$apply();
1632                     datepickerCtrl.updatePosition(b2bDatepickerPopupTemplate);
1633                     $timeout(function () { 
1634                         angular.element(element[0].querySelector('.datepicker-input')).scrollTop=0;
1635                     },10);
1636                 }
1637             });
1638             var toggleCalendar = function (flag) {
1639                 if (!scope.inline) {
1640                     if (flag) {
1641                         b2bDatepickerPopupTemplate = angular.element($templateCache.get('b2bTemplate/calendar/datepicker-popup.html'));
1642                         b2bDatepickerPopupTemplate = $compile(b2bDatepickerPopupTemplate)(scope);
1643                         $document.find('body').append(b2bDatepickerPopupTemplate);
1644                         b2bDatepickerPopupTemplate.bind('keydown', keyPress);
1645                         $timeout(function () {
1646                             scope.getFocus = true;
1647                             trapFocusInElement(flag, b2bDatepickerPopupTemplate);
1648                             scope.$apply();
1649                             $timeout(function () {
1650                                 scope.getFocus = false; 
1651                                 scope.$apply();
1652                             }, 100);
1653                         });
1654                     } else {
1655                         b2bDatepickerPopupTemplate.unbind('keydown', keyPress);
1656                         b2bDatepickerPopupTemplate.remove();
1657                         element.find('button')[0].focus();
1658                         scope.getFocus = false;
1659                         trapFocusInElement(flag, b2bDatepickerPopupTemplate);
1660                     }
1661                 }
1662             };
1663
1664             var outsideClick = function (e) {
1665                 var isElement = $isElement(angular.element(e.target), element, $document);
1666                 var isb2bDatepickerPopupTemplate = $isElement(angular.element(e.target), b2bDatepickerPopupTemplate, $document);
1667                 if (!(isElement || isb2bDatepickerPopupTemplate)) {
1668                     scope.isOpen = false;
1669                     toggleCalendar(scope.isOpen);
1670                     scope.$apply();
1671                 }
1672             };
1673
1674             var keyPress = function (ev) {
1675                 if (!ev.keyCode) {
1676                     if (ev.which) {
1677                         ev.keyCode = ev.which;
1678                     } else if (ev.charCode) {
1679                         ev.keyCode = ev.charCode;
1680                     }
1681                 }
1682                 if (ev.keyCode) {
1683                     if (ev.keyCode === 27) {
1684                         scope.isOpen = false;
1685                         toggleCalendar(scope.isOpen);
1686                         ev.preventDefault();
1687                         ev.stopPropagation();
1688                     } else if (ev.keyCode === 33) {
1689                         !scope.disablePrev && scope.move(-1);
1690                         $timeout(function () {
1691                             scope.getFocus = true;
1692                             scope.$apply();
1693                             $timeout(function () {
1694                                 scope.getFocus = false;
1695                                 scope.$apply();
1696                             }, 100);
1697                         });
1698                         ev.preventDefault();
1699                         ev.stopPropagation();
1700                     } else if (ev.keyCode === 34) {
1701                         !scope.disableNext && scope.move(1);
1702                         $timeout(function () {
1703                             scope.getFocus = true;
1704                             scope.$apply();
1705                             $timeout(function () {
1706                                 scope.getFocus = false;
1707                                 scope.$apply();
1708                             }, 100);
1709                         });
1710                         ev.preventDefault();
1711                         ev.stopPropagation();
1712                     }
1713                     scope.$apply();
1714                 }
1715             };
1716
1717             $documentBind.click('isOpen', outsideClick, scope);
1718
1719             var modalContainer = angular.element(document.querySelector('.modalwrapper'));
1720             var modalBodyContainer = angular.element(document.querySelector('.modal-body'));
1721             if (modalContainer) {
1722                 modalContainer.bind('scroll', function () {
1723                     if (b2bDatepickerPopupTemplate) {
1724                         datepickerCtrl.updatePosition(b2bDatepickerPopupTemplate);
1725                         scope.$apply();
1726                     }
1727                 });
1728             }
1729             if (modalBodyContainer) {
1730                 modalBodyContainer.bind('scroll', function () {
1731                     if (b2bDatepickerPopupTemplate) {
1732                         datepickerCtrl.updatePosition(b2bDatepickerPopupTemplate);
1733                         var datepickerTextfield = $position.offset(element.find('input'));
1734                         var modalBodyPosition = $position.offset(modalBodyContainer);
1735
1736                         if (((datepickerTextfield.top + datepickerTextfield.height) < modalBodyPosition.top || datepickerTextfield.top > (modalBodyPosition.top + modalBodyPosition.height)) && scope.isOpen) {
1737                             scope.isOpen = false;
1738                             toggleCalendar(scope.isOpen);
1739                         }
1740                         scope.$apply();
1741                     }
1742                 });
1743             }
1744             var window = angular.element($window);
1745             window.bind('resize', function () {
1746                 if (b2bDatepickerPopupTemplate) {
1747                     datepickerCtrl.updatePosition(b2bDatepickerPopupTemplate);
1748                     scope.$apply();
1749                 }
1750             });
1751
1752             scope.$on('$destroy', function () {
1753                 if (scope.isOpen) {
1754                     scope.isOpen = false;
1755                     toggleCalendar(scope.isOpen);
1756                 }
1757             });
1758
1759             scope.resetTime = function (date) {
1760                 if (typeof date === 'string') {
1761                     date = date + 'T12:00:00';
1762                 }
1763                 var dt;
1764                 if (!isNaN(new Date(date))) {
1765                     dt = new Date(date);
1766                 } else {
1767                     return null;
1768                 }
1769                 return new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());
1770             };
1771
1772             if (attrs.min) {
1773                 scope.$parent.$watch($parse(attrs.min), function (value) {
1774                     scope.minDate = value ? scope.resetTime(value) : null;
1775                     refill();
1776                 });
1777             }
1778             if (attrs.max) {
1779                 scope.$parent.$watch($parse(attrs.max), function (value) {
1780                     scope.maxDate = value ? scope.resetTime(value) : null;
1781                     refill();
1782                 });
1783             }
1784             if (attrs.due) {
1785                 scope.$parent.$watch($parse(attrs.due), function (value) {
1786                     scope.dueDate = value ? scope.resetTime(value) : null;
1787                     refill();
1788                 });
1789             }
1790             if (attrs.from) {
1791                 scope.$parent.$watch($parse(attrs.from), function (value) {
1792                     scope.fromDate = value ? scope.resetTime(value) : null;
1793                     refill();
1794                 });
1795             }
1796
1797             if (attrs.legendIcon) {
1798                 scope.$parent.$watch(attrs.legendIcon, function (value) {
1799                     scope.legendIcon = value ? value : null;
1800                     refill();
1801                 });
1802             }
1803             if (attrs.legendMessage) {
1804                 scope.$parent.$watch(attrs.legendMessage, function (value) {
1805                     scope.legendMessage = value ? value : null;
1806                     refill();
1807                 });
1808             }
1809             if (attrs.ngDisabled) {
1810                 scope.$parent.$watch(attrs.ngDisabled, function (value) {
1811                     scope.ngDisabled = value ? value : null;
1812                 });
1813             }
1814
1815             // Split array into smaller arrays
1816             function split(arr, size) {
1817                 var arrays = [];
1818                 while (arr.length > 0) {
1819                     arrays.push(arr.splice(0, size));
1820                 }
1821                 return arrays;
1822             }
1823
1824             function refill(date) {
1825                 if (angular.isDate(date) && !isNaN(date)) {
1826                     selected = new Date(date);
1827                 } else {
1828                     if (!selected) {
1829                         selected = new Date();
1830                     }
1831                 }
1832
1833                 if (selected) {
1834                     var currentMode = datepickerCtrl.modes[mode],
1835                         data = currentMode.getVisibleDates(selected);
1836                     scope.rows = split(data.objects, currentMode.split);
1837                     var flag = false;
1838                     var startFlag = false;
1839                     var firstSelected = false;
1840                     for (var i = 0; i < scope.rows.length; i++) {
1841                         for (var j = 0; j < scope.rows[i].length; j++) {
1842
1843                             if (scope.rows[i][j].label === "1" && !firstSelected) {
1844                                 firstSelected = true;
1845                                 var firstDay = scope.rows[i][j];
1846                             }
1847
1848                             if (scope.rows[i][j].selected === true) {
1849                                 flag = true;
1850                                 break;
1851                             }
1852                         }
1853                         if (flag) {
1854                             break;
1855                         }
1856                     }
1857                     if (!flag) {
1858                         firstDay.firstFocus = true;
1859                     }
1860
1861                     scope.labels = data.labels || [];
1862                     scope.title = data.title;
1863
1864                     datepickerCtrl.updatePosition(b2bDatepickerPopupTemplate);
1865                 }
1866             }
1867
1868             scope.select = function (date) {
1869                 var dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());
1870                 if (!scope.onSelectClose || (scope.onSelectClose && scope.onSelectClose({
1871                         date: dt
1872                     }) !== false)) {
1873                     scope.currentDate = dt;
1874                     if (angular.isNumber(scope.collapseWait)) {
1875                         $timeout(function () {
1876                             scope.isOpen = false;
1877                             toggleCalendar(scope.isOpen);
1878                         }, scope.collapseWait);
1879                     } else {
1880                         scope.isOpen = false;
1881                         toggleCalendar(scope.isOpen);
1882                     }
1883                 }
1884             };
1885
1886             scope.move = function (direction,$event) {
1887                 var step = datepickerCtrl.modes[mode].step;
1888                 selected.setDate(1);
1889                 selected.setMonth(selected.getMonth() + direction * (step.months || 0));
1890                 selected.setFullYear(selected.getFullYear() + direction * (step.years || 0));
1891                 refill();
1892
1893                 $timeout(function () {
1894                     trapFocusInElement();
1895                 }, 100);
1896
1897                 $event.preventDefault();
1898                 $event.stopPropagation();
1899             };
1900
1901             scope.trapFocus = function () {
1902                 $timeout(function () {
1903                     trapFocusInElement();
1904                 }, 100);
1905             };
1906
1907             scope.$watch('currentDate', function (value) {
1908                 if (angular.isDefined(value) && value !== null) {
1909                     refill(value);
1910                 } else {
1911                     refill();
1912                 }
1913                 ngModel.$setViewValue(value);
1914             });
1915
1916             ngModel.$render = function () {
1917                 scope.currentDate = ngModel.$viewValue;
1918             };
1919
1920             var stringToDate = function (value) {
1921                 if (!isNaN(new Date(value))) {
1922                     value = new Date(value);
1923                 }
1924                 return value;
1925             };
1926             ngModel.$formatters.unshift(stringToDate);
1927         }
1928     };
1929 }])
1930
1931 .directive('b2bDatepicker', ['$compile', '$log', 'b2bDatepickerConfig', 'b2bDatepickerService', function ($compile, $log, b2bDatepickerConfig, b2bDatepickerService) {
1932     return {
1933         restrict: 'A',
1934         scope: {
1935             disableDates: '&',
1936             onSelectClose: '&'
1937         },
1938         require: 'ngModel',
1939         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
1940             var dateFormatString = angular.isDefined(attr.dateFormat) ? scope.$parent.$eval(attr.dateFormat) : b2bDatepickerConfig.dateFormat;
1941             var helperText = angular.isDefined(attr.helperText) ? scope.$parent.$eval(attr.helperText) : b2bDatepickerConfig.helperText;
1942             helperText = helperText.replace('$date', '{{dt | date : \'' + dateFormatString + '\'}}');
1943
1944             var inline = false;
1945             if (elem.prop('nodeName') !== 'INPUT') {
1946                 inline = true;
1947             }
1948
1949             var calendarIcon = '<i class="icon-primary-calendar" aria-hidden="true"></i>'
1950             var selectedDateMessage = '<button id="' + attr.btnId + '" type="button" class="span12 faux-input" ng-disabled="ngDisabled"><span class="hidden-spoken">' + helperText + '</span></button>';
1951
1952             elem.removeAttr('b2b-datepicker');
1953             elem.removeAttr('ng-model');
1954             elem.removeAttr('ng-disabled');
1955             elem.addClass('datepicker-input');
1956             elem.attr('ng-model', 'dt');
1957             elem.attr('aria-describedby', 'datepicker');
1958             elem.attr('aria-hidden', 'true');
1959             elem.attr('tabindex', '-1');
1960             elem.attr('readonly', 'true');
1961             elem.attr('ng-disabled', 'ngDisabled');
1962             elem.attr('b2b-format-date', dateFormatString);
1963
1964             var wrapperElement = angular.element('<div></div>');
1965             wrapperElement.attr('b2b-datepicker-popup', '');
1966             wrapperElement.attr('ng-model', 'dt');
1967             if (inline) {
1968                 wrapperElement.attr('inline', inline);
1969             }
1970
1971             b2bDatepickerService.setAttributes(attr, wrapperElement);
1972             b2bDatepickerService.bindScope(attr, scope);
1973
1974             wrapperElement.html('');
1975             wrapperElement.append(calendarIcon);
1976             wrapperElement.append(selectedDateMessage);
1977             wrapperElement.append(elem.prop('outerHTML'));
1978
1979             var elm = wrapperElement.prop('outerHTML');
1980             elm = $compile(elm)(scope);
1981             elem.replaceWith(elm);
1982         }],
1983         link: function (scope, elem, attr, ctrl) {
1984             if (!ctrl) {
1985                 $log.error("ng-model is required.");
1986                 return; // do nothing if no ng-model
1987             }
1988
1989             scope.$watch('dt', function (value) {
1990                 ctrl.$setViewValue(value);
1991             });
1992             ctrl.$render = function () {
1993                 scope.dt = ctrl.$viewValue;
1994             };
1995         }
1996     };
1997 }])
1998
1999 .directive('b2bDatepickerGroup', [function () {
2000     return {
2001         restrict: 'EA',
2002         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
2003             this.$$headers = [];
2004             this.$$footers = [];
2005             this.registerDatepickerScope = function (datepickerScope) {
2006                 datepickerScope.headers = this.$$headers;
2007                 datepickerScope.footers = this.$$footers;
2008             };
2009         }],
2010         link: function (scope, elem, attr, ctrl) {}
2011     };
2012 }])
2013
2014 .directive('b2bFormatDate', ['dateFilter', function (dateFilter) {
2015     return {
2016         restrict: 'A',
2017         require: 'ngModel',
2018         link: function (scope, elem, attr, ctrl) {
2019             var b2bFormatDate = "";
2020             attr.$observe('b2bFormatDate', function (value) {
2021                 b2bFormatDate = value;
2022             });
2023             var dateToString = function (value) {
2024                 if (!isNaN(new Date(value))) {
2025                     return dateFilter(new Date(value), b2bFormatDate);
2026                 }
2027                 return value;
2028             };
2029             ctrl.$formatters.unshift(dateToString);
2030         }
2031     };
2032 }])
2033
2034 .directive('b2bDatepickerHeader', [function () {
2035     return {
2036         restrict: 'EA',
2037         require: '^b2bDatepickerGroup',
2038         transclude: true,
2039         replace: true,
2040         template: '',
2041         compile: function (elem, attr, transclude) {
2042             return function link(scope, elem, attr, ctrl) {
2043                 if (ctrl) {
2044                     ctrl.$$headers.push(transclude(scope, function () {}));
2045                 }
2046                 elem.remove();
2047             };
2048         }
2049     };
2050 }])
2051
2052 .directive('b2bDatepickerFooter', [function () {
2053     return {
2054         restrict: 'EA',
2055         require: '^b2bDatepickerGroup',
2056         transclude: true,
2057         replace: true,
2058         template: '',
2059         compile: function (elem, attr, transclude) {
2060             return function link(scope, elem, attr, ctrl) {
2061                 if (ctrl) {
2062                     ctrl.$$footers.push(transclude(scope, function () {}));
2063                 }
2064                 elem.remove();
2065             };
2066         }
2067     };
2068 }]);
2069 /**
2070  * @ngdoc directive
2071  * @name Forms.att:checkboxes
2072  *
2073  * @description
2074  *  <file src="src/checkboxes/docs/readme.md" />
2075  * @usage
2076  * See demo section
2077  * @example
2078  <example module="b2b.att">
2079  <file src="src/checkboxes/docs/demo.html" />
2080  <file src="src/checkboxes/docs/demo.js" />
2081  </example>
2082  */
2083 angular.module('b2b.att.checkboxes', ['b2b.att.utilities'])
2084 .directive('b2bSelectGroup', [function (){
2085         return {
2086             restrict: 'A',
2087             require: 'ngModel',
2088             scope: {
2089                 checkboxes: "="
2090             },
2091             link: function (scope, elem, attr, ctrl) {
2092                 elem.bind('change', function () {
2093                     var isChecked = elem.prop('checked');
2094                     angular.forEach(scope.checkboxes, function (item) {
2095                         item.isSelected = isChecked;
2096                     });
2097                     scope.$apply();
2098                 });
2099                 scope.$watch('checkboxes', function () {
2100                     var setBoxes = 0;
2101                     if(scope.checkboxes === undefined) {
2102                         return;
2103                     }
2104                     angular.forEach(scope.checkboxes, function (item) {
2105                         if (item.isSelected) {
2106                             setBoxes++; 
2107                         } 
2108                     });
2109                     elem.prop('indeterminate', false);
2110                     if ( scope.checkboxes !==undefined && setBoxes === scope.checkboxes.length && scope.checkboxes.length > 0) { 
2111                         ctrl.$setViewValue(true); 
2112                         elem.removeClass('indeterminate');
2113                     } else if (setBoxes === 0) { 
2114                        ctrl.$setViewValue(false); 
2115                        elem.removeClass('indeterminate');
2116                     } else { 
2117                         ctrl.$setViewValue(false); 
2118                         elem.addClass('indeterminate');
2119                         elem.prop('indeterminate', true); 
2120                     }
2121                     ctrl.$render();
2122                 }, true);
2123             }
2124         };
2125     }]);
2126 /**
2127  * @ngdoc directive
2128  * @name Misc.att:coachmark
2129  *
2130  * @description
2131  * <file src="src/coachmark/docs/readme.md" />
2132  *
2133  * @usage
2134  *
2135 <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>
2136
2137  * @example
2138     <section id="code">   
2139         <b>HTML + AngularJS</b>
2140         <example module="b2b.att">
2141             <file src="src/coachmark/docs/demo.html" />
2142             <file src="src/coachmark/docs/demo.js" />
2143         </example>
2144     </section>
2145  */
2146
2147 angular.module('b2b.att.coachmark', ['b2b.att.utilities','b2b.att.position'])
2148         
2149     .directive('b2bCoachmark', ['$document', '$compile', '$position', '$timeout', function($document, $compile, $position, $timeout) {
2150         return {
2151             restrict: 'A',
2152              scope: {
2153                 coachmarks: '=',
2154                 coachmarkIndex: '=',
2155                 startCoachmarkCallback: '&',
2156                 endCoachmarkCallback: '&',
2157                 actionCoachmarkCallback: '&'
2158             },
2159             link: function (scope, element, attrs, ctrl) {
2160                 var coachmarkItems = scope.coachmarks;
2161                 var body = $document.find('body').eq(0);
2162                 var coackmarkJqContainer;
2163                 var coackmarkContainer;
2164                 var coachMarkElement;
2165                 var backdropjqLiteEl;
2166                 var coachmarkHighlight;
2167                 var initaitedCoachmark = false;
2168                 scope.coackmarkElPos ={
2169                     'top':'',
2170                     'left':''
2171                 };
2172                 
2173                 scope.currentCoachmark = {};
2174                 
2175                 
2176                 var coachmarkBackdrop = function(){
2177                     backdropjqLiteEl = angular.element('<div class="b2b-modal-backdrop fade in hidden-by-modal"></div>');
2178                     body.append(backdropjqLiteEl);
2179
2180                     backdropjqLiteEl.bind('click', function() {
2181                         scope.closeCoachmark();
2182                         scope.$apply();
2183                     });
2184                 };
2185                 
2186                 
2187                 scope.closeButtonFocus = function(){
2188                     if(document.getElementsByClassName('b2b-coachmark-header').length >0){
2189                         document.getElementsByClassName('b2b-coachmark-header')[0].scrollLeft = 0;
2190                         document.getElementsByClassName('b2b-coachmark-header')[0].scrollTop = 0;
2191                     }
2192                 }
2193
2194                 scope.actionCoachmark = function(action){
2195                     scope.actionCoachmarkCallback({
2196                         'action':action
2197                     })
2198                 };
2199                 
2200                 scope.closeCoachmark = function(){
2201                     initaitedCoachmark = false;
2202                     backdropjqLiteEl.remove();  
2203                     coackmarkContainer.remove();
2204                     coachmarkHighlight.remove();
2205                     if(coachMarkElement !== undefined && coachMarkElement !==""){
2206                         coachMarkElement.removeClass('b2b-coachmark-label')
2207                     }
2208                     if (angular.isFunction(scope.endCoachmarkCallback)){
2209                         scope.endCoachmarkCallback();   
2210                     }
2211                     element[0].focus();
2212                 }
2213                 
2214                 function showCoachmark(targetElement) {
2215                     scope.currentCoachmark = targetElement;
2216                     if(coachMarkElement !== undefined && coachMarkElement !==""){
2217                         coachMarkElement.removeClass('b2b-coachmark-label')
2218                         coackmarkContainer.remove();
2219                         coachmarkHighlight.remove();
2220                     }
2221                     coachMarkElement = angular.element(document.querySelector(targetElement.elementId));
2222                     coachMarkElement.addClass('b2b-coachmark-label');
2223                     var elementPosition = $position.offset(coachMarkElement);
2224                     
2225                     coachmarkHighlight = angular.element('<div class="b2b-coachmark-highlight"></div><div class="b2b-coachmark-highlight b2b-coachmark-highlight-mask"></div>');
2226                     coachmarkHighlight.css({
2227                         'width': (elementPosition.width + 20) +'px',
2228                         'top': (elementPosition.top -10) + 'px',
2229                         'left': (elementPosition.left - 10) + 'px',
2230                         'height': (elementPosition.height + 20) +'px'
2231                     }); 
2232                     body.append(coachmarkHighlight);
2233                     
2234                     scope.coackmarkElPos.top = (elementPosition.top + elementPosition.height + 32) + 'px';
2235                     scope.coackmarkElPos.left = (elementPosition.left - 158 + elementPosition.width / 2 ) + 'px';
2236                     coackmarkJqContainer = angular.element('<div b2b-coachmark-container b2b-trap-focus-inside-element="true"></div>');
2237                     coackmarkContainer = $compile(coackmarkJqContainer)(scope);
2238                     body.append(coackmarkContainer);
2239                     
2240                     $timeout(function () {
2241                         var currentCoachmarkContainer = document.getElementsByClassName('b2b-coachmark-container')[0];
2242                         currentCoachmarkContainer.focus();
2243                         var coachmarkHeight = window.getComputedStyle(currentCoachmarkContainer).height.split('px')[0];
2244                         var newOffsetHeight = (Math.round(elementPosition.top) - Math.round(coachmarkHeight));
2245                         
2246                         // We need a slight offset to show the lightboxed item
2247                         TweenLite.to(window, 2, {scrollTo:{x: (scope.coackmarkElPos.left.split('px')[0]-100), y: newOffsetHeight}});
2248                     }, 200);
2249                 }
2250                 
2251                 element.bind('click', function (e) {
2252                     initaitedCoachmark = true;
2253                     if(scope.coachmarkIndex === -1 || scope.coachmarkIndex >= coachmarkItems.length ){
2254                         scope.coachmarkIndex = 0;
2255                     }
2256                     scope.$watch('coachmarkIndex', function () {
2257                         if(initaitedCoachmark === true){
2258                             if(scope.coachmarkIndex === -1 || scope.coachmarkIndex >= coachmarkItems.length ){
2259                                 scope.closeCoachmark();
2260                             }else{
2261                                 showCoachmark(coachmarkItems[scope.coachmarkIndex]);
2262                             }
2263                         }
2264                     });
2265                     coachmarkBackdrop();
2266                     showCoachmark(coachmarkItems[scope.coachmarkIndex]);
2267                     if (angular.isFunction(scope.startCoachmarkCallback)){
2268                         scope.startCoachmarkCallback(); 
2269                     }
2270                     $document.bind('keydown', function (evt) {
2271                         if (evt.which === 27 && initaitedCoachmark) {
2272                             scope.closeCoachmark();
2273                             scope.$apply(); 
2274                         }
2275                     });
2276                 });
2277
2278             }
2279         };
2280     }])
2281     .directive('b2bCoachmarkContainer', ['$document', '$position', function($document, $position) {
2282         return {
2283             restrict: 'A',
2284             transclude: true,
2285             replace: true,
2286             templateUrl: 'b2bTemplate/coachmark/coachmark.html',
2287             link: function (scope, element, attrs, ctrl) {
2288                             
2289             }
2290         };  
2291     }]);
2292     
2293 /** 
2294  * @ngdoc directive 
2295  * @name Template.att:Configuration Section 
2296  * 
2297  * @description 
2298  *  <file src="src/configurationSection/docs/readme.md" /> 
2299  * 
2300  * @example 
2301  *  <section id="code"> 
2302         <b>HTML + AngularJS</b> 
2303         <example module="b2b.att"> 
2304             <file src="src/configurationSection/docs/demo.html" /> 
2305             <file src="src/configurationSection/docs/demo.js" /> 
2306        </example> 
2307     </section>    
2308  * 
2309  */
2310 angular.module('b2b.att.configurationSection', [])
2311   
2312 /** 
2313  * @ngdoc directive 
2314  * @name Template.att:Directory Listing 
2315  * 
2316  * @description 
2317  *  <file src="src/directoryListingTemplate/docs/readme.md" /> 
2318  * 
2319  * @example 
2320  *  <section id="code"> 
2321         <b>HTML + AngularJS</b> 
2322         <example module="b2b.att"> 
2323             <file src="src/directoryListingTemplate/docs/demo.html" /> 
2324             <file src="src/directoryListingTemplate/docs/demo.js" /> 
2325        </example> 
2326     </section>    
2327  * 
2328  */
2329 angular.module('b2b.att.directoryListingTemplate', [])
2330   
2331 /**
2332  * @ngdoc directive
2333  * @name Forms.att:dropdowns
2334  *
2335  * @description
2336  *  <file src="src/dropdowns/docs/readme.md" />
2337  * @usage
2338  *
2339  * @example
2340    <section id="code">
2341     <example module="b2b.att">
2342      <file src="src/dropdowns/docs/demo.html" />
2343      <file src="src/dropdowns/docs/demo.js" />
2344     </example>
2345    </section>
2346  */
2347 angular.module('b2b.att.dropdowns', ['b2b.att.utilities', 'b2b.att.position', 'ngSanitize'])
2348
2349 .constant('b2bDropdownConfig', {
2350     prev: '37,38',
2351     next: '39,40',
2352     menuKeyword: 'menu',
2353     linkMenuKeyword: 'link-menu',
2354     largeKeyword: 'large',
2355     smallKeyword: 'small'
2356 })  
2357
2358 .directive("b2bDropdown", ['$timeout', '$compile', '$templateCache', 'b2bUserAgent', 'b2bDropdownConfig', '$position', function ($timeout, $compile, $templateCache, b2bUserAgent, b2bDropdownConfig, $position) {
2359     return {
2360         restrict: 'A',
2361         scope: true,
2362         require: 'ngModel',
2363         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
2364             scope.isInputDropdown = true;
2365             scope.placeHoldertext = attr.placeholderText;
2366             if (attr.type) {
2367                 if (attr.type.indexOf(b2bDropdownConfig.menuKeyword) > -1 || attr.type.indexOf(b2bDropdownConfig.linkMenuKeyword) > -1) {
2368                     scope.isInputDropdown = false;
2369                     if (attr.type.indexOf(b2bDropdownConfig.linkMenuKeyword) > -1) {
2370                         scope.dropdownType = b2bDropdownConfig.linkMenuKeyword;
2371                     } else if (attr.type.indexOf(b2bDropdownConfig.menuKeyword) > -1) {
2372                         scope.dropdownType = b2bDropdownConfig.menuKeyword;
2373                     }
2374                 }
2375                 if (attr.type.indexOf(b2bDropdownConfig.largeKeyword) > -1) {
2376                     scope.dropdownSize = b2bDropdownConfig.largeKeyword;
2377                 } else if (attr.type.indexOf(b2bDropdownConfig.smallKeyword) > -1) {
2378                     scope.dropdownSize = b2bDropdownConfig.smallKeyword;
2379                 }
2380             }
2381
2382             scope.labelText = attr.labelText;
2383
2384             scope.setBlur = function () {
2385                 scope.setTouched();
2386             };
2387
2388             if ((scope.isInputDropdown && b2bUserAgent.notMobile()) || (!scope.isInputDropdown)) {
2389                 var formCtrl = elem.controller('form');
2390                 scope.setNgModelController = function (name, ngModelCtrl) {
2391                     if (name && formCtrl && ngModelCtrl) {
2392                         formCtrl[name] = ngModelCtrl;
2393                     }
2394                 };
2395                 scope.setOptionalCta = function (optionalCta) {
2396                     scope.optionalCta = optionalCta;
2397                 };
2398                 var innerHtml = angular.element('<div></div>').append(elem.html());
2399                 innerHtml = ($compile(innerHtml)(scope)).html();
2400                 var template = angular.element($templateCache.get('b2bTemplate/dropdowns/b2bDropdownDesktop.html'));
2401                 template.find('ul').eq(0).append(innerHtml);
2402                 template = $compile(template)(scope);
2403                 elem.replaceWith(template);
2404             } else if (scope.isInputDropdown && b2bUserAgent.isMobile()) {
2405                 elem.css({
2406                     'opacity': '0',
2407                     'filter': 'alpha(opacity=0)'
2408                 });
2409                 elem.addClass('awd-select isWrapped');
2410                 elem.wrap('<span class="selectWrap"></span>');
2411                 var cover = angular.element('<span aria-hidden="true"><i class="icon-primary-down" aria-hidden="true"></i></span>');
2412                 elem.parent().append(cover);
2413                 elem.parent().append('<i class="icon-primary-down" aria-hidden="true"></i>');
2414                 var set = function () {
2415                     var sel = elem[0] ? elem[0] : elem;
2416                     var selectedText = "";
2417                     var selIndex = sel.selectedIndex;
2418                     if (typeof selIndex !== 'undefined') {
2419                         selectedText = sel.options[selIndex].text;
2420                     }
2421                     cover.text(selectedText).append('<i class="icon-primary-down" aria-hidden="true"></i>');
2422                 };
2423                 var update = function (value) {
2424                     $timeout(set, 100);
2425                 };
2426
2427                 if (attr.ngModel) {
2428                     scope.$watch(attr.ngModel, function (newVal, oldVal) {
2429                         update();
2430                     });
2431                 }
2432                 elem.bind('keyup', function (ev) {
2433                     if (ev.keyCode === keymap.KEY.TAB || ev.keyCode === keymap.KEY.ESC) {
2434                         return;
2435                     }
2436                     set();
2437                 });
2438             }
2439         }],  
2440         link: function (scope, elem, attr, ctrl) {
2441             if ((scope.isInputDropdown && b2bUserAgent.notMobile()) || (!scope.isInputDropdown)) {
2442                 scope.updateModel = function () {
2443                     if (ctrl.$dirty) {
2444                         debugger;
2445                     }
2446                     ctrl.$setViewValue(scope.currentSelected.value);
2447                     if (scope.dropdownRequired && scope.currentSelected.value === '') {
2448                         scope.setRequired(false);
2449                     } else {
2450                         scope.setRequired(true);
2451                     }
2452
2453                     if (scope.dropdownType === b2bDropdownConfig.linkMenuKeyword) {
2454                         $timeout(function () {
2455                             scope.appendCaretPositionStyle();
2456                         }, 100);
2457                     }
2458                 };
2459                 ctrl.$render = function () {
2460 //                    if(ctrl.$dirty || ctrl.$pristine) {
2461                         $timeout(function () {
2462
2463                             if ((angular.isUndefined(ctrl.$viewValue) || ctrl.$viewValue == '') && (angular.isUndefined(scope.placeHoldertext) || scope.placeHoldertext == '')) {
2464                                 scope.dropdownLists[ctrl.$viewValue] && scope.dropdownLists[ctrl.$viewValue][0].updateDropdownValue();
2465                             } else if ((angular.isUndefined(scope.placeHoldertext) || scope.placeHoldertext == '') && ctrl.$viewValue !== '' ) {
2466                                 scope.dropdownLists[ctrl.$viewValue] && scope.dropdownLists[ctrl.$viewValue][0].updateDropdownValue();
2467                             } else if ((angular.isUndefined(ctrl.$viewValue) || ctrl.$viewValue == '') && scope.placeHoldertext !== '' )  {
2468                                 scope.currentSelected.text = scope.placeHoldertext; 
2469                             } else {
2470                                 scope.dropdownLists[ctrl.$viewValue] && scope.dropdownLists[ctrl.$viewValue][0].updateDropdownValue();
2471                             }
2472
2473                         }, 100);
2474                     };
2475 //                }
2476                 scope.disabled = false;
2477                 scope.dropdownName = attr.name;
2478                 scope.dropdownId = attr.id;
2479                 scope.labelId = attr.ariaLabelledby;
2480                 scope.dropdownDescribedBy = attr.ariaDescribedby;
2481                 if (attr.required) {
2482                     scope.dropdownRequired = true;
2483                 } else {
2484                     scope.dropdownRequired = false;
2485                 }
2486                 elem.removeAttr('name');
2487                 elem.removeAttr('id');
2488                 scope.$parent.$watch(attr.ngDisabled, function (val) {
2489                     scope.disabled = val;
2490                 });
2491             }
2492         }
2493     };
2494 }])
2495
2496 .directive("b2bDropdownToggle", ['$document', '$documentBind', '$isElement', 'b2bDropdownConfig', 'keymap', 'b2bUtilitiesConfig', '$timeout', '$position', function ($document, $documentBind, $isElement, b2bDropdownConfig, keymap, b2bUtilitiesConfig, $timeout, $position) {
2497     return {
2498         restrict: 'A',
2499         require: '?^b2bKey',
2500         link: function (scope, elem, attr, ctrl) {
2501             scope.appendCaretPositionStyle = function () {
2502                 while (document.querySelector('style.b2bDropdownCaret')) {
2503                     document.querySelector('style.b2bDropdownCaret').remove();
2504                 };
2505                 var caretPosition = $position.position(elem).width - 26;
2506                 if (scope.dropdownType === b2bDropdownConfig.linkMenuKeyword) {
2507                     var template = angular.element('<style class="b2bDropdownCaret" type="text/css">.linkSelectorModule .active+.moduleWrapper:before {left: ' + caretPosition + 'px;}</style>');
2508                     $document.find('head').append(template);
2509                 }
2510             };
2511
2512             if (scope.isInputDropdown && (scope.labelText !== undefined)) {
2513                 elem.attr('aria-label', scope.labelText);
2514             }
2515
2516             scope.toggleFlag = false;
2517             scope.dropdownLists = {};
2518             scope.dropdownListValues = [];
2519             scope.dropdown = {
2520                 totalIndex: -1
2521             };
2522             scope.currentSelected = {
2523                 value: '',
2524                 text: '',
2525                 label: '',
2526                 index: -1
2527             };
2528             var searchString = '';
2529             var searchElement = function (searchExp) {
2530                 var regex = new RegExp("\\b" + searchExp, "gi");
2531                 var position = scope.dropdownListValues.regexIndexOf(regex, scope.currentSelected.index + 1, true);
2532                 if (position > -1) {
2533                     return position;
2534                 }
2535                 return undefined;
2536             };
2537             var startTimer = function (time) {
2538                 if (searchString === '') {
2539                     $timeout(function () {
2540                         searchString = '';
2541                     }, time);
2542                 }
2543             };
2544             scope.toggleDropdown = function (toggleFlag) {
2545                 if (!scope.disabled) {
2546                     if (angular.isDefined(toggleFlag)) {
2547                         scope.toggleFlag = toggleFlag;
2548                     } else {
2549                         scope.toggleFlag = !scope.toggleFlag;
2550                     }
2551                     if (!scope.toggleFlag) {
2552                         if (scope.isInputDropdown) {
2553                             elem.parent().find('input')[0].focus();
2554                         } else {
2555                             elem.parent().find('button')[0].focus();
2556                         }
2557                     } else {
2558                         scope.dropdown.highlightedValue = scope.currentSelected.value;
2559                         if (ctrl && ctrl.enableSearch) {
2560                             if (angular.isDefined(scope.dropdownLists[scope.currentSelected.value])) {
2561                                 ctrl.resetCounter(scope.dropdownLists[scope.currentSelected.value][2]);
2562                             }
2563                         }
2564                         if (scope.dropdownType === b2bDropdownConfig.linkMenuKeyword) {
2565                             scope.appendCaretPositionStyle();
2566                         }
2567                     }
2568                 }
2569             };
2570
2571             elem.bind('keydown', function (ev) {
2572                 if (!ev.keyCode) {
2573                     if (ev.which) {
2574                         ev.keyCode = ev.which;
2575                     } else if (ev.charCode) {
2576                         ev.keyCode = ev.charCode;
2577                     }
2578                 }
2579                 if (!scope.toggleFlag) {
2580                     if (ev.keyCode) {
2581                         var currentIndex = scope.currentSelected.index;
2582                         if (ev.altKey === true && ev.keyCode === keymap.KEY.DOWN) {
2583                             scope.toggleDropdown(true);
2584                             ev.preventDefault();
2585                             ev.stopPropagation();
2586                         } else if (b2bDropdownConfig.prev.split(',').indexOf(ev.keyCode.toString()) > -1) {
2587                             angular.isDefined(scope.dropdownListValues[currentIndex - 1]) ? scope.dropdownLists[scope.dropdownListValues[currentIndex - 1]][0].updateDropdownValue() : angular.noop();
2588                             ev.preventDefault();
2589                             ev.stopPropagation();
2590                         } else if (b2bDropdownConfig.next.split(',').indexOf(ev.keyCode.toString()) > -1) {
2591                             angular.isDefined(scope.dropdownListValues[currentIndex + 1]) ? scope.dropdownLists[scope.dropdownListValues[currentIndex + 1]][0].updateDropdownValue() : angular.noop();
2592                             ev.preventDefault();
2593                             ev.stopPropagation();
2594                         } else if (ev.keyCode >= 48 && ev.keyCode <= 105) {
2595                             startTimer(b2bUtilitiesConfig.searchTimer);
2596                             searchString = searchString + (keymap.MAP[ev.keyCode] || '');
2597                             var position = searchElement(searchString);
2598                             angular.isDefined(scope.dropdownListValues[position]) ? scope.dropdownLists[scope.dropdownListValues[position]][0].updateDropdownValue() : angular.noop();
2599                             ev.preventDefault();
2600                             ev.stopPropagation();
2601                         }
2602                     }
2603                 } else {
2604                     if (ev.altKey === true && ev.keyCode === keymap.KEY.UP) {
2605                         scope.toggleDropdown(false);
2606                         ev.preventDefault();
2607                         ev.stopPropagation();
2608                     } else if (ev.keyCode === keymap.KEY.TAB || ev.keyCode === keymap.KEY.ESC) {
2609                         scope.toggleDropdown(false);
2610                         ev.preventDefault();
2611                         ev.stopPropagation();
2612                     }
2613                 }
2614                 scope.$apply(); // TODO: Move this into each block to avoid expensive digest cycles
2615             });
2616             var outsideClick = function (e) {
2617                 var isElement = $isElement(angular.element(e.target), elem.parent(), $document);
2618                 if (!isElement) {
2619                     scope.toggleDropdown(false);
2620                     scope.$apply();
2621                 }
2622             };
2623             $documentBind.click('toggleFlag', outsideClick, scope);
2624         }
2625     };
2626 }])
2627
2628 .directive("b2bDropdownGroup", ['$compile', '$templateCache', 'b2bUserAgent', function ($compile, $templateCache, b2bUserAgent) {
2629     return {
2630         restrict: 'A',
2631         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
2632             if ((scope.isInputDropdown && b2bUserAgent.notMobile()) || (!scope.isInputDropdown)) {
2633                 var innerHtml = angular.element('<div></div>').append(elem.html());
2634                 innerHtml = ($compile(innerHtml)(scope)).html();
2635                 var template = angular.element($templateCache.get('b2bTemplate/dropdowns/b2bDropdownGroupDesktop.html'));
2636                 template.attr('ng-repeat', attr.optGroupRepeat);
2637                 template.attr('label', elem.attr('label'));
2638                 template.find('ul').append(innerHtml);
2639                 elem.replaceWith(template);
2640             } else if (scope.isInputDropdown && b2bUserAgent.isMobile()) {
2641                 var template = angular.element(elem.prop('outerHTML'));
2642                 template.attr('ng-repeat', attr.optGroupRepeat);
2643                 template.removeAttr('b2b-dropdown-group');
2644                 template.removeAttr('opt-group-repeat');
2645                 template = $compile(template)(scope);
2646                 elem.replaceWith(template);
2647             }
2648         }]
2649     };
2650 }])
2651
2652 .directive("b2bDropdownGroupDesktop", [function () {
2653     return {
2654         restrict: 'A',
2655         scope: true,
2656         link: function (scope, elem, attr, ctrl) {
2657             scope.groupHeader = attr.label;
2658         }
2659     };
2660 }])
2661
2662 .directive("b2bDropdownList", ['$compile', '$templateCache', 'b2bUserAgent', function ($compile, $templateCache, b2bUserAgent) {
2663     return {
2664         restrict: 'A',
2665         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
2666             if ((scope.isInputDropdown && b2bUserAgent.notMobile()) || (!scope.isInputDropdown)) {
2667                 var innerHtml = angular.element('<div></div>').append(elem.html());
2668                 innerHtml = ($compile(innerHtml)(scope)).html();
2669                 var template = angular.element($templateCache.get('b2bTemplate/dropdowns/b2bDropdownListDesktop.html'));
2670                 template.attr('ng-repeat', attr.optionRepeat);
2671                 template.attr('value', elem.attr('value'));
2672                 template.attr('search-key', elem.attr('value'));
2673                 if (elem.attr('aria-describedby')){
2674                     template.attr('aria-describedby', attr.ariaDescribedby);
2675                 }
2676                 if (elem.attr('imgsrc')) {
2677                     if (elem.attr('imgalt')) {
2678                         template.append('<img role="presentation" ng-src="' + elem.attr('imgsrc') + '" alt="' + elem.attr('imgalt') + '"/>');
2679                     } else {
2680                         template.append('<img role="presentation" ng-src="' + elem.attr('imgsrc') + '" alt=""/>');
2681                     }
2682                 }
2683                 template.append(innerHtml);
2684                 elem.replaceWith(template);
2685             } else if (scope.isInputDropdown && b2bUserAgent.isMobile()) {
2686                 var template = angular.element(elem.prop('outerHTML'));
2687                 template.attr('ng-repeat', attr.optionRepeat);
2688                 if (elem.attr('aria-describedby')){
2689                     template.attr('aria-describedby', attr.ariaDescribedby);
2690                 }
2691                 template.removeAttr('b2b-dropdown-list');
2692                 template.removeAttr('option-repeat');
2693                 template = $compile(template)(scope);
2694                 elem.replaceWith(template);
2695             }
2696         }]
2697     };
2698 }])
2699
2700 .directive("b2bDropdownListDesktop", ['$sce', 'keymap', 'b2bDropdownConfig', function ($sce, keymap, b2bDropdownConfig) {
2701     return {
2702         restrict: 'A',
2703         scope: true,
2704         link: function (scope, elem, attr, ctrl) {
2705             var dropdownListValue = scope.dropdownListValue = attr.value;
2706             scope.dropdown.totalIndex++;
2707             var dropdownListIndex = scope.dropdown.totalIndex;
2708             scope.dropdownListValues.push(dropdownListValue);
2709             scope.dropdownLists[dropdownListValue] = [];
2710             scope.dropdownLists[dropdownListValue][0] = scope;
2711             scope.dropdownLists[dropdownListValue][1] = elem;
2712             scope.dropdownLists[dropdownListValue][2] = dropdownListIndex;
2713             scope.updateDropdownValue = function () {
2714                 scope.currentSelected.value = dropdownListValue;
2715                 if (scope.isInputDropdown) {
2716                     scope.currentSelected.text = elem.text();
2717                 } else if ((scope.dropdownType === b2bDropdownConfig.linkMenuKeyword) || (scope.dropdownType === b2bDropdownConfig.menuKeyword && scope.dropdownSize === b2bDropdownConfig.smallKeyword)) {
2718                     scope.currentSelected.text = dropdownListValue;
2719                 } else if (scope.dropdownType === b2bDropdownConfig.menuKeyword) {
2720                     scope.currentSelected.text = $sce.trustAsHtml(elem.html());
2721                 }
2722                 if (scope.isInputDropdown) {
2723                     scope.currentSelected.label = elem.text();
2724                 } else if (scope.dropdownType === b2bDropdownConfig.linkMenuKeyword) {
2725                     scope.currentSelected.label = dropdownListValue;
2726                 } else if (scope.dropdownType === b2bDropdownConfig.menuKeyword) {
2727                     scope.currentSelected.label = elem.text();
2728                 }
2729                 scope.currentSelected.index = dropdownListIndex;
2730                 scope.updateModel();
2731             };
2732             scope.selectDropdownItem = function () {
2733                 scope.setDirty();
2734                 scope.updateDropdownValue();
2735                 scope.toggleDropdown(false);
2736             };
2737             scope.highlightDropdown = function () {
2738                 scope.dropdown.highlightedValue = dropdownListValue;
2739             };
2740             elem.bind('mouseover', function (ev) {
2741                 elem[0].focus();
2742             });
2743             elem.bind('keydown', function (ev) {
2744                 if (!ev.keyCode) {
2745                     if (ev.which) {
2746                         ev.keyCode = ev.which;
2747                     } else if (ev.charCode) {
2748                         ev.keyCode = ev.charCode;
2749                     }
2750                 }
2751                 if (ev.altKey === true && ev.keyCode === keymap.KEY.UP) {
2752                     scope.toggleDropdown(false);
2753                     ev.preventDefault();
2754                     ev.stopPropagation();
2755                 } else if (ev.keyCode === keymap.KEY.TAB || ev.keyCode === keymap.KEY.ESC) {
2756                     scope.toggleDropdown(false);
2757                     ev.preventDefault();
2758                     ev.stopPropagation();
2759                 }
2760                 scope.$apply();
2761             });
2762         }
2763     };
2764 }])
2765
2766 .directive("b2bDropdownRepeat", ['$compile', 'b2bUserAgent', function ($compile, b2bUserAgent) {
2767     return {
2768         restrict: 'A',
2769         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
2770             if ((scope.isInputDropdown && b2bUserAgent.notMobile()) || (!scope.isInputDropdown)) {
2771                 var innerHtml = angular.element('<div></div>').append(elem.html());
2772                 innerHtml = ($compile(innerHtml)(scope)).html();
2773                 var template = angular.element('<div></div>');
2774                 template.attr('ng-repeat', attr.b2bDropdownRepeat);
2775                 template.append(innerHtml);
2776                 elem.replaceWith(template);
2777             } else if (scope.isInputDropdown && b2bUserAgent.isMobile()) {
2778                 angular.noop();
2779             }
2780         }]
2781     };
2782 }])
2783
2784 .directive("b2bDropdownValidation", ['$timeout', function ($timeout) {
2785     return {
2786         restrict: 'A',
2787         require: 'ngModel',
2788         link: function (scope, elem, attr, ctrl) {
2789             $timeout(function () {
2790                 scope.setNgModelController(attr.name, ctrl);
2791             }, 100);
2792             scope.setDirty = function () {
2793                 if (ctrl.$dirty === false) {
2794                     ctrl.$dirty = true;
2795                     ctrl.$pristine = false;
2796                 }
2797             };
2798             scope.setTouched = function () {
2799                 if (ctrl.$touched === false) {
2800                     ctrl.$touched = true;
2801                     ctrl.$pristine = false;
2802                 }
2803             };
2804             scope.setRequired = function (flag) {
2805                 ctrl.$setValidity('required', flag);
2806             };
2807         }
2808     };
2809 }])
2810
2811 .directive('b2bDropdownOptionalCta', [function () {
2812     return {
2813         restrict: 'EA',
2814         transclude: true,
2815         replace: true,
2816         template: '',
2817         compile: function (elem, attr, transclude) {
2818             return function link(scope, elem, attr, ctrl) {
2819                 if (scope.setOptionalCta) {
2820                     scope.setOptionalCta(transclude(scope, function () {}));
2821                 }
2822                 elem.remove();
2823             };
2824         }
2825     };
2826 }]);
2827 /**
2828  * @ngdoc directive
2829  * @name Forms.att:File Upload
2830  *
2831  * @description
2832  *  <file src="src/fileUpload/docs/readme.md" />
2833  *
2834  * @usage
2835  * 
2836 <form id="dragDropFile">        
2837     <div b2b-file-drop file-model="fileModel" on-drop="triggerFileUpload()"  align="center">
2838         <p>
2839             <br>To upload a file, drag & drop it here or 
2840             <span b2b-file-link file-model="fileModel" on-file-select="triggerFileUpload()" >
2841                 click here to select from your computer.
2842             </span><br>
2843         </p>
2844     </div>
2845 </form>
2846  *
2847  * @example
2848  *  <section id="code">
2849         <example module="b2b.att">
2850             <file src="src/fileUpload/docs/demo.html" />
2851             <file src="src/fileUpload/docs/demo.js" />
2852        </example>
2853     </section>
2854  *
2855  */
2856 angular.module('b2b.att.fileUpload', ['b2b.att.utilities'])
2857     .directive('b2bFileDrop', [function() {
2858             return {
2859                 restrict: 'EA',
2860                 scope: {
2861                     fileModel: '=',
2862                     onDrop: '&'
2863                 },
2864                 controller: ['$scope', '$attrs', function($scope, $attrs) {
2865                     this.onDrop = $scope.onDrop;
2866                 }],
2867                 link: function(scope, element) {
2868                     element.addClass('b2b-dragdrop');
2869                     element.bind(
2870                         'dragover',
2871                         function(e) {
2872                             if (e.originalEvent) {
2873                                 e.dataTransfer = e.originalEvent.dataTransfer;
2874                             }
2875                             e.dataTransfer.dropEffect = 'move';
2876                             // allows us to drop
2877                             if (e.preventDefault) {
2878                                 e.preventDefault();
2879                             }
2880                             element.addClass('b2b-dragdrop-over');
2881                             return false;
2882                         }
2883                     );
2884                     element.bind(
2885                         'dragenter',
2886                         function(e) {
2887                             // allows us to drop
2888                             if (e.preventDefault) {
2889                                 e.preventDefault();
2890                             }
2891                             element.addClass('b2b-dragdrop-over');
2892                             return false;
2893                         }
2894                     );
2895                     element.bind(
2896                         'dragleave',
2897                         function() {
2898                             element.removeClass('b2b-dragdrop-over');
2899                             return false;
2900                         }
2901                     );
2902                     element.bind(
2903                         'drop',
2904                         function(e) {
2905                             // Stops some browsers from redirecting.
2906                             if (e.preventDefault) {
2907                                 e.preventDefault();
2908                             }
2909                             if (e.stopPropagation) {
2910                                 e.stopPropagation();
2911                             }
2912                             if (e.originalEvent) {
2913                                 e.dataTransfer = e.originalEvent.dataTransfer;
2914                             }
2915                             element.removeClass('b2b-dragdrop-over');
2916                             if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
2917                                 scope.fileModel = e.dataTransfer.files[0];
2918                                 scope.$apply();
2919                                 if (angular.isFunction(scope.onDrop)) {
2920                                     scope.onDrop();
2921                                 }
2922                             }
2923                             return false;
2924                         }
2925                     );
2926                 }
2927             };
2928         }])
2929         .directive('b2bFileLink', [function() {
2930             return {
2931                 restrict: 'EA',
2932                 require: '^?b2bFileDrop',
2933                 replace: true,
2934                 transclude: true,
2935                 templateUrl: 'b2bTemplate/fileUpload/fileUpload.html',
2936                 scope: {
2937                     fileModel: '=?',
2938                     onFileSelect: '&'
2939                 },
2940                 controller: ['$scope', function($scope) {
2941                     this.setFileModel = function(fileModel) {
2942                         if ($scope.takeFileModelFromParent) {
2943                             $scope.$parent.fileModel = fileModel;
2944                             $scope.$parent.$apply();
2945                         } else {
2946                             $scope.fileModel = fileModel;
2947                             $scope.$apply();
2948                         }
2949                     };
2950                     this.callbackFunction = function() {
2951                         if (angular.isFunction($scope.onFileSelect)) {
2952                             $scope.onFileSelect();
2953                         }
2954                     };
2955         
2956                 }],
2957                 link: function(scope, element, attr, b2bFileDropCtrl) {
2958                     scope.takeFileModelFromParent = false;
2959                     if (!(attr.fileModel) && b2bFileDropCtrl) {
2960                         scope.takeFileModelFromParent = true;
2961                     }
2962                     if (!(attr.onFileSelect) && b2bFileDropCtrl) {
2963                         scope.onFileSelect = b2bFileDropCtrl.onDrop;
2964                     }
2965                 }
2966             };
2967         }])
2968         .directive('b2bFileChange', ['$log', '$rootScope', function($log, $rootScope) {
2969             return {
2970                 restrict: 'A',
2971                 require: '^b2bFileLink',
2972                 link: function(scope, element, attr, b2bFileLinkCtrl) {
2973                     element.bind('change', changeFileModel);
2974
2975                     function changeFileModel(e) {
2976                         if (e.target.files && e.target.files.length > 0) {
2977                             b2bFileLinkCtrl.setFileModel(e.target.files[0]);
2978                             b2bFileLinkCtrl.callbackFunction();
2979                         } else {
2980                             var strFileName = e.target.value;
2981                             try {
2982                                 var objFSO = new ActiveXObject("Scripting.FileSystemObject");
2983                                 b2bFileLinkCtrl.setFileModel(objFSO.getFile(strFileName));
2984                                 b2bFileLinkCtrl.callbackFunction();
2985                             } catch (e) {
2986                                 var errMsg = "There was an issue uploading " + strFileName + ". Please try again.";
2987                                 $log.error(errMsg);
2988                                 $rootScope.$broadcast('b2b-file-link-failure', errMsg);
2989                             }
2990                         }
2991                     }
2992                 }
2993             };
2994         }]);
2995 /**
2996  * @ngdoc directive
2997  * @name Navigation.att:filters
2998  *
2999  * @description
3000  *  <file src="src/filters/docs/readme.md" />
3001  *
3002  * @usage
3003  *  <div b2b-filters></div>
3004  *
3005  * @example
3006  *  <section id="code">
3007        <b>HTML + AngularJS</b>
3008         <example module="b2b.att">
3009             <file src="src/filters/docs/demo.html" />
3010             <file src="src/filters/docs/demo.js" />
3011        </example>
3012     </section>
3013  * 
3014  */
3015 angular.module('b2b.att.filters', ['b2b.att.utilities', 'b2b.att.multipurposeExpander'])
3016     .filter('filtersSelectedItemsFilter', [function () {
3017         return function (listOfItemsArray) {
3018
3019             if (!listOfItemsArray) {
3020                 listOfItemsArray = [];
3021             }
3022
3023             var returnArray = [];
3024
3025             for (var i = 0; i < listOfItemsArray.length; i++) {
3026                 for (var j = 0; j < listOfItemsArray[i].filterTypeItems.length; j++) {
3027                     if (listOfItemsArray[i].filterTypeItems[j].selected && !listOfItemsArray[i].filterTypeItems[j].inProgress) {
3028                         returnArray.push(listOfItemsArray[i].filterTypeItems[j]);
3029                     }
3030                 }
3031             }
3032
3033             return returnArray;
3034         };
3035     }]);
3036 /**
3037  * @ngdoc directive
3038  * @name Messages, modals & alerts.att:flyout
3039  *
3040  * @description
3041  *  <file src="src/flyout/docs/readme.md" />
3042  * @example
3043  *  <section id="code">
3044         <example module="b2b.att">
3045             <file src="src/flyout/docs/demo.html" />
3046             <file src="src/flyout/docs/demo.js" />
3047        </example>
3048     </section>
3049  *
3050  */
3051 angular.module('b2b.att.flyout', ['b2b.att.utilities', 'b2b.att.position'])
3052     .directive('b2bFlyout', ['$timeout', 'b2bDOMHelper', 'keymap', 'events', function ($timeout, b2bDOMHelper, keymap, events) {
3053         return {
3054             restrict: 'EA',
3055             transclude: true,
3056             templateUrl: 'b2bTemplate/flyout/flyout.html',
3057             controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
3058                 scope.flyoutOpened = false;
3059                 var contentScope = '';
3060                 var togglerScope = '';
3061                 this.registerContentScope = function (scp) {
3062                     contentScope = scp;
3063                 };
3064                 this.registerTogglerScope = function (scp) {
3065                     togglerScope = scp;
3066                 };
3067
3068                 this.toggleFlyoutState = function () {
3069                     if (contentScope) {
3070                         contentScope.toggleFlyout();
3071                     }
3072                 };
3073                 this.getTogglerDimensions = function () {
3074                     return togglerScope.getTogglerDimensions();
3075                 }
3076                 this.setTogglerFocus = function () {
3077                     return togglerScope.setTogglerFocus();
3078                 }
3079
3080                 this.closeFlyout = function (e) {
3081                     contentScope.closeFromChild(e);
3082                 };
3083                 this.gotFocus = function () {
3084                     contentScope.gotFocus();
3085                 };
3086
3087                 this.updateAriaModel = function (val) {
3088                     scope.flyoutOpened = val;
3089                 };
3090
3091                 var firstTabableElement = undefined,
3092                     lastTabableElement = undefined;
3093
3094                 var firstTabableElementKeyhandler = function (e) {
3095                     if (!e.keyCode) {
3096                         e.keyCode = e.which;
3097                     }
3098                     if (e.keyCode === keymap.KEY.TAB && e.shiftKey && scope.flyoutOpened) { 
3099                         contentScope.gotFocus();
3100                         events.preventDefault(e);
3101                         events.stopPropagation(e);
3102                     }
3103                 };
3104
3105                 var lastTabableElementKeyhandler = function (e) {
3106                     if (!e.keyCode) {
3107                         e.keyCode = e.which;
3108                     }
3109                     if (e.keyCode === keymap.KEY.TAB && !e.shiftKey) {
3110                         contentScope.gotFocus();    
3111                         events.preventDefault(e);
3112                         events.stopPropagation(e);
3113                     }
3114                 };
3115                 this.associateTabEvent = function(){
3116                     $timeout(function () {
3117                         var element = elem[0].getElementsByClassName('b2b-flyout-container')[0];
3118                         firstTabableElement = b2bDOMHelper.firstTabableElement(element);
3119                         lastTabableElement = b2bDOMHelper.lastTabableElement(element);
3120                         if(angular.isUndefined(firstTabableElement)){
3121                             angular.element(element).css('display','block');
3122                             firstTabableElement = b2bDOMHelper.firstTabableElement(element);
3123                             lastTabableElement = b2bDOMHelper.lastTabableElement(element);
3124                             angular.element(element).css('display','none');
3125                         }
3126                         angular.element(firstTabableElement).bind('keydown', firstTabableElementKeyhandler);
3127                         angular.element(lastTabableElement).bind('keydown', lastTabableElementKeyhandler);
3128                     });
3129                 }
3130                 this.updateTabbableElements = function(){
3131                     $timeout(function () {
3132                         var element = elem[0].getElementsByClassName('b2b-flyout-container')[0];
3133                         angular.element(element).css('display','block');
3134                         firstTabableElement = b2bDOMHelper.firstTabableElement(element);
3135                         lastTabableElement = b2bDOMHelper.lastTabableElement(element);
3136                         angular.element(firstTabableElement).bind('keydown', firstTabableElementKeyhandler);
3137                         angular.element(lastTabableElement).bind('keydown', lastTabableElementKeyhandler);
3138                         angular.element(element).css('display','none');
3139                     });
3140                 }
3141                 this.unbindTabbaleEvents = function(){
3142                     if(angular.isDefined(firstTabableElement)){
3143                         angular.element(firstTabableElement).unbind('keydown', firstTabableElementKeyhandler);
3144                     }
3145
3146                     if(angular.isDefined(lastTabableElement)){
3147                         angular.element(lastTabableElement).unbind('keydown', lastTabableElementKeyhandler);
3148                     }
3149                 }
3150             }],
3151             link: function (scope, element, attrs, ctrl) {
3152
3153             }
3154         };
3155     }])
3156     .directive('b2bFlyoutToggler', [function () {
3157         return {
3158             restrict: 'A',
3159             require: '^b2bFlyout',
3160             link: function (scope, element, attrs, ctrl) {
3161                 element.bind('click', function (e) {
3162                     ctrl.toggleFlyoutState();
3163                 });
3164
3165                 scope.getTogglerDimensions = function () {
3166                     return element[0].getBoundingClientRect();
3167                 }
3168
3169                 scope.setTogglerFocus = function () {
3170                     element[0].focus();
3171                 }
3172
3173                 ctrl.registerTogglerScope(scope);
3174             }
3175         };
3176     }])
3177     .directive('b2bFlyoutContent', ['$position', '$timeout', '$documentBind', '$isElement', '$document', function ($position, $timeout, $documentBind, $isElement, $document) {
3178         return {
3179             restrict: 'EA',
3180             transclude: true,
3181             replace: true,
3182             require: '^b2bFlyout',
3183             scope: {
3184                 horizontalPlacement: '@',
3185                 verticalPlacement: '@',
3186                 flyoutStyle: '@',
3187                 flyoutTitle: '@',
3188                 contentUpdated: "=?"
3189             },
3190             templateUrl: 'b2bTemplate/flyout/flyoutContent.html',
3191             link: function (scope, element, attrs, ctrl) {
3192                 var flyoutStyleArray, eachCssProperty, cssPropertyKey, cssPropertyVal, temp;
3193                 scope.openFlyout = false;
3194                 if (!scope.horizontalPlacement) {
3195                     scope.horizontalPlacement = 'center';
3196                 }
3197                 if (!scope.verticalPlacement) {
3198                     scope.verticalPlacement = 'below';
3199                 }
3200
3201                 scope.toggleFlyout = function () {
3202
3203                     scope.openFlyout = !scope.openFlyout;
3204
3205                     if (scope.openFlyout) {
3206
3207                         if (angular.isDefined(scope.flyoutStyle) && scope.flyoutStyle != "") {
3208                             flyoutStyleArray = scope.flyoutStyle.split(";");
3209                             for (i = 0; i < flyoutStyleArray.length; i++) {
3210                                 eachCssProperty = flyoutStyleArray[i].split(":");
3211                                 if (eachCssProperty.length == 2) {
3212                                     cssPropertyKey = eachCssProperty[0].trim();
3213                                     cssPropertyVal = eachCssProperty[1].trim();
3214                                     angular.element(element[0])[0].style[cssPropertyKey] = cssPropertyVal;
3215                                 }
3216                             }
3217                         }
3218
3219                         angular.element(element[0]).css({
3220                             'opacity': 0,
3221                             'display': 'block'
3222                         });
3223
3224                         var flyoutIcons = angular.element(document.querySelectorAll(".b2b-flyout-icon"));
3225                         angular.forEach(flyoutIcons, function (elm) {
3226                             angular.element(elm)[0].blur();
3227                         });
3228
3229                         $timeout(function () {
3230                             ctrl.setTogglerFocus();
3231
3232                             var togglerDimensions = ctrl.getTogglerDimensions();
3233                             var flyoutDimensions = element[0].getBoundingClientRect();
3234
3235                             switch (scope.horizontalPlacement) {
3236                             case "left":
3237                                 angular.element(element[0]).css({
3238                                     'left': ((togglerDimensions.width / 2) - 26) + 'px'
3239                                 });
3240                                 break;
3241                             case "right":
3242                                 angular.element(element[0]).css({
3243                                     'right': ((togglerDimensions.width / 2) - 23) + 'px'
3244                                 });
3245                                 break;  
3246
3247                             case "centerLeft":
3248                                 var marginLeft =  10-(flyoutDimensions.width)-20;
3249                                 angular.element(element[0]).css({
3250                                     'margin-left': marginLeft + 'px'
3251                                 });
3252                                 break;
3253                             case "centerRight":
3254                                 angular.element(element[0]).css({
3255                                     'left': ((togglerDimensions.width + 9 )) + 'px'
3256                                 });
3257                                 break;    
3258
3259                             default:
3260                                 var marginLeft = (togglerDimensions.width / 2) - (flyoutDimensions.width / 2) - 8;
3261                                 angular.element(element[0]).css({
3262                                     'margin-left': marginLeft + 'px'
3263                                 });
3264                             }
3265
3266                             switch (scope.verticalPlacement) {
3267                             case "above":
3268                                 angular.element(element[0]).css({
3269                                     'top': -(flyoutDimensions.height + 13) + 'px'
3270                                 });
3271                                 break;
3272                             case "centerLeft":
3273                                 angular.element(element[0]).css({
3274                                     'top': -((togglerDimensions.height-13))+ 'px'
3275                                 });
3276                                 break;
3277                             case "centerRight":
3278                                 angular.element(element[0]).css({
3279                                     'top': -(flyoutDimensions.height - 23)+ 'px'
3280                                 });
3281                                 break;                                    
3282                             default:
3283                                 angular.element(element[0]).css({
3284                                     'top': (togglerDimensions.height + 13) + 'px'
3285                                 });
3286                             }
3287
3288                             angular.element(element[0]).css({
3289                                 'opacity': 1
3290                             });
3291                         }, 100);
3292                     } else {
3293                         scope.hideFlyout();
3294                     }
3295                 };
3296
3297                 scope.gotFocus = function () {
3298                     scope.openFlyout = false;
3299                     scope.hideFlyout();
3300                     ctrl.setTogglerFocus();
3301                     scope.$apply();
3302                 };
3303
3304                 scope.closeFromChild = function (e) {
3305                     scope.openFlyout = false;
3306                     scope.hideFlyout();
3307                     ctrl.setTogglerFocus();
3308                     scope.$apply();
3309                 };
3310
3311                 scope.hideFlyout = function () {
3312                     angular.element(element[0]).css({
3313                         'opacity': 0,
3314                         'display': 'none'
3315                     });
3316                 };
3317
3318                 scope.closeFlyout = function (e) {
3319                     var isElement = $isElement(angular.element(e.target), element, $document);
3320                     if ((e.type === "keydown" && e.which === 27) || ((e.type === "click" || e.type==="touchend") && !isElement)) {
3321                         scope.openFlyout = false;
3322                         scope.hideFlyout();
3323                         ctrl.setTogglerFocus();
3324                         scope.$apply();
3325                     }
3326                 };
3327
3328                 scope.$watch('openFlyout', function () {
3329                     ctrl.updateAriaModel(scope.openFlyout);
3330                 });
3331
3332                 $documentBind.click('openFlyout', scope.closeFlyout, scope);
3333                 $documentBind.event('keydown', 'openFlyout', scope.closeFlyout, scope);
3334                 $documentBind.event('touchend', 'openFlyout', scope.closeFlyout, scope);
3335                 ctrl.registerContentScope(scope);
3336
3337                 if (angular.isDefined(scope.contentUpdated) && scope.contentUpdated !== null) {
3338                     scope.$watch('contentUpdated', function (newVal, oldVal) {
3339                         if(newVal){
3340                             if (newVal !== oldVal) {
3341                                 ctrl.unbindTabbaleEvents();
3342                                 ctrl.associateTabEvent();
3343                             }
3344                             scope.contentUpdated = false;
3345                         } 
3346                     });
3347                 }  
3348
3349             }
3350         };
3351     }])
3352     .directive('b2bCloseFlyout', [function () {
3353         return {
3354             restrict: 'A',
3355             require: '^b2bFlyout',
3356             scope: {
3357                 closeFlyout: '&'
3358             },
3359             link: function (scope, element, attrs, ctrl) {
3360                 element.bind('click', function (e) {
3361                     scope.closeFlyout(e);
3362                     ctrl.closeFlyout(e);
3363                 });
3364             }
3365         };
3366     }])
3367     .directive('b2bFlyoutTrapFocusInside', [function () {
3368         return {
3369             restrict: 'A',
3370             transclude: false,
3371             require: '^b2bFlyout',
3372             link: function (scope, elem, attr, ctrl) {
3373                 /* Before opening modal, find the focused element */
3374                 ctrl.updateTabbableElements();
3375             }
3376         };
3377     }]);
3378 /**
3379  * @ngdoc directive
3380  * @name Layouts.att:footer
3381  *
3382  * @description
3383  *  <file src="src/footer/docs/readme.md" />
3384  *
3385  * @usage
3386  * 
3387  <footer class="b2b-footer-wrapper" role="contentinfo" aria-label="footer">
3388         <div class="b2b-footer-container" b2b-column-switch-footer footer-link-items='footerItems'>
3389             <hr>
3390             <div class="divider-bottom-footer">
3391                 <div class="span2 dispalyInline">&nbsp;</div>
3392                 <div class="span6 dispalyInline">
3393                     <ul class="footer-nav-content">
3394                         <li><a href="Terms_of_use.html" title="Terms of use" id="foot0">Terms of use</a>|</li>
3395                         <li><a href="Privacy_policy.html" title="Privacy policy" id="foot1" class="active">Privacy policy</a>|</li>
3396                         <li><a href="Tollfree_directory_assistance.html" title="Tollfree directory assistance" id="foot2">Tollfree directory assistance</a>|</li>
3397                         <li><a href="compliance.html" title="Accessibility" id="foot3">Accessibility</a></li>
3398
3399                     </ul>
3400                     <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.
3401
3402                     </p>
3403                 </div>
3404                 <div class="span3 footerLogo dispalyInline">
3405                     <a href="index.html" class="footer-logo">
3406                         <i class="icon-primary-att-globe"><span class="hidden-spoken">A T &amp; T</span></i>
3407                         <h2 class="logo-title">AT&amp;T</h2>
3408                     </a>
3409                 </div>
3410             </div>
3411
3412         </div>  
3413     </footer>
3414
3415  * @example
3416  *  <section id="code">   
3417  <example module="b2b.att">
3418  <file src="src/footer/docs/demo.html" />
3419  <file src="src/footer/docs/demo.js" />
3420  </example>
3421  </section>
3422  *
3423  */
3424 angular.module('b2b.att.footer', ['b2b.att.utilities']).
3425         directive('b2bColumnSwitchFooter', [function() {
3426                 return {
3427                     restrict: 'A',
3428                     transclude: true,
3429                     scope: {
3430                         footerLinkItems: "="
3431                     },
3432                     templateUrl: 'b2bTemplate/footer/footer_column_switch_tpl.html',
3433                     link: function(scope) {
3434                         var tempFooterColumns = scope.footerLinkItems.length;
3435                         scope.footerColumns = 3;
3436                         if ( (tempFooterColumns === 5) || (tempFooterColumns === 4) ) {
3437                             scope.footerColumns = tempFooterColumns;
3438                         }
3439                     }
3440
3441                 };
3442
3443             }]);
3444      
3445
3446 /**
3447  * @ngdoc directive
3448  * @name Layouts.att:header
3449  *
3450  * @description
3451  *  <file src="src/header/docs/readme.md" />
3452  *
3453  * @usage
3454  *  <li b2b-header-menu class="header__item b2b-headermenu" ng-repeat="item in tabItems" role="presentation">
3455         <a href="#" class="menu__item" role="menuitem">{{item.title}}</a>
3456         <div class="header-secondary-wrapper">
3457             <ul class="header-secondary" role="menu">
3458                 <li class="header-subitem" b2b-header-submenu ng-repeat="i in item.subitems" role="presentation">
3459                     <a href="#" class="menu__item" aria-haspopup="true" role="menuitem">{{i.value}}</a>
3460                     <div class="header-tertiary-wrapper" ng-if="i.links">
3461                         <ul class="header-tertiary" role="menu">
3462                             <li b2b-header-tertiarymenu ng-repeat="link in i.links" role="presentation">
3463                                 <label>{{link.title}}</label>
3464                                 <div b2b-tertiary-link ng-repeat="title in link.value">
3465                                     <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>
3466                                     <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>
3467                                     <ul class="header-quarternary" role="menu"  ng-if="title.subitems">
3468                                         <li b2b-header-quarternarymenu role="presentation">
3469                                             <a href="{{nav.href}}" ng-repeat="nav in title.subitems" role="menuitem" aria-haspopup="true">{{nav.title}}</a>
3470                                         </li>
3471                                     </ul>
3472                                 </div>
3473                             </li>
3474                         </ul>
3475                     </div>
3476                 </li>
3477             </ul>
3478         </div>
3479     </li> 
3480  *
3481  * @example
3482  *  <section id="code">
3483  <example module="b2b.att.header">
3484  <file src="src/header/docs/demo.html" />
3485  <file src="src/header/docs/demo.js" />
3486  </example>
3487  </section>
3488  *
3489  */
3490 angular.module('b2b.att.header', ['b2b.att.dropdowns','b2b.att.utilities'])
3491     .directive('b2bHeaderMenu', ['keymap', '$documentBind', '$timeout', '$isElement', '$document', function (keymap, $documentBind, $timeout, $isElement, $document) {
3492         return {
3493             restrict: 'A',
3494             controller:['$scope',function($scope){
3495                 this.nextSiblingFocus = function (elObj,flag) {
3496                         if (elObj.nextElementSibling) {
3497                             if(flag){
3498                                 var nextmenuItem = this.getFirstElement(elObj.nextElementSibling,'a');
3499                                 nextmenuItem.focus();
3500                             }else{
3501                                 elObj.nextElementSibling.focus();
3502                             }
3503                         }
3504                 };
3505                 
3506                 this.previousSiblingFocus = function (elObj,flag) {
3507                         if (elObj.previousElementSibling) {
3508                             if(flag){
3509                                 var prevmenuItem = this.getFirstElement(elObj.previousElementSibling,'a');
3510                                 prevmenuItem.focus();
3511                             }else{
3512                                 elObj.previousElementSibling.focus();
3513                             }
3514                         }
3515                 };
3516                     
3517                 this.getFirstElement = function(elmObj,selector){
3518                         return elmObj.querySelector(selector);                        
3519                     };
3520             }],
3521             link: function (scope, elem,attr,ctrl) {
3522                 scope.showMenu = false;
3523                 var activeElm, subMenu, tertiaryMenu, el= angular.element(elem)[0], 
3524                         menuItem = angular.element(elem[0].children[0]);
3525                 menuItem.bind('click', function () {
3526                     elem.parent().children().removeClass('active');
3527                     elem.addClass('active');
3528                     var elems= this.parentElement.parentElement.querySelectorAll('li[b2b-header-menu]>a');
3529                     for (var i=0; i<elems.length; i++) {
3530                         elems[i].setAttribute("aria-expanded",false);
3531                     }
3532                     scope.showMenu = true;
3533                     var elmTofocus = ctrl.getFirstElement(this.parentElement,'li[b2b-header-submenu]');
3534                     elmTofocus.firstElementChild.focus();
3535                     this.setAttribute('aria-expanded',true);
3536                     scope.$apply();
3537                 });
3538                
3539                 elem.bind('keydown', function (evt) {
3540                     activeElm = document.activeElement;
3541                     subMenu = ctrl.getFirstElement(activeElm.parentElement,'li[b2b-header-submenu]');
3542                     tertiaryMenu = ctrl.getFirstElement(activeElm.parentElement,'li[b2b-header-tertiarymenu]');
3543                     switch (evt.keyCode) {
3544                         case keymap.KEY.ENTER:
3545                         case keymap.KEY.SPACE:
3546                             elem[0].click();
3547                             break;
3548                         case keymap.KEY.UP:
3549                             evt.stopPropagation();
3550                             evt.preventDefault();
3551                             if (activeElm.parentElement.hasAttribute('b2b-header-submenu')) {
3552                                 menuItem[0].focus();
3553                             }
3554                             break;
3555                         case keymap.KEY.DOWN:
3556                             evt.stopPropagation();
3557                             evt.preventDefault();
3558                             if (subMenu) {
3559                                 subMenu.firstElementChild.focus();
3560                             } else if (tertiaryMenu) {
3561                                 var firstSubitem = ctrl.getFirstElement(tertiaryMenu,'a.header-tertiaryitem');
3562                                 firstSubitem.focus();
3563                             }
3564                             break;
3565                         case keymap.KEY.RIGHT:
3566                             evt.stopPropagation();
3567                             evt.preventDefault();
3568                             if (activeElm.parentElement.hasAttribute('b2b-header-submenu')) {
3569                                 var elm = angular.element(activeElm.parentElement)[0];
3570                                 ctrl.nextSiblingFocus(elm,true);
3571                             } else if (activeElm.parentElement.parentElement.hasAttribute('b2b-header-tertiarymenu')) {
3572                                 var tertiaryLI = angular.element(activeElm.parentElement.parentElement)[0];
3573                                 if (tertiaryLI.nextElementSibling) {
3574                                     var nextElm = ctrl.getFirstElement(tertiaryLI.nextElementSibling,"a.header-tertiaryitem");
3575                                     nextElm.focus();
3576                                 }
3577                             }
3578                             else if(activeElm.parentElement.hasAttribute('b2b-header-menu')){
3579                                 ctrl.nextSiblingFocus(el,true);
3580                             }
3581                             break;
3582                         case keymap.KEY.LEFT:
3583                             evt.stopPropagation();
3584                             evt.preventDefault();
3585                             if (activeElm.parentElement.hasAttribute('b2b-header-submenu')) {
3586                                 var previousElm = angular.element(activeElm.parentElement)[0];
3587                                 ctrl.previousSiblingFocus(previousElm,true);
3588                             } else if (activeElm.parentElement.parentElement.hasAttribute('b2b-header-tertiarymenu')) {
3589                                 var tertiaryLI = angular.element(activeElm.parentElement.parentElement)[0];
3590                                 if (tertiaryLI.previousElementSibling) {
3591                                     var prevElm = ctrl.getFirstElement(tertiaryLI.previousElementSibling,"a.header-tertiaryitem");
3592                                     prevElm.focus();
3593                                 }
3594                             }
3595                             else if(activeElm.parentElement.hasAttribute('b2b-header-menu')) {
3596                                 ctrl.previousSiblingFocus(el,true);
3597                             }
3598                             break;
3599                         case keymap.KEY.ESC:
3600                             evt.stopPropagation();
3601                             evt.preventDefault();
3602                             scope.showMenu = false;
3603                             elem.removeClass('active');
3604                             menuItem.attr('aria-expanded',false);
3605                             $timeout(function(){
3606                                 menuItem[0].focus();
3607                             },100);
3608                             scope.$apply();
3609                             break;
3610                         default:
3611                             break;
3612                     }
3613                 });
3614                 var outsideClick = function (e) {
3615                     var isElement = $isElement(angular.element(e.target), elem, $document);
3616                     if (!isElement) {
3617                         scope.showMenu = false;
3618                         elem.removeClass('active');
3619                         scope.$apply();
3620                     }
3621                 };
3622                 $documentBind.click('showMenu', outsideClick, scope);
3623             }
3624         };
3625     }]).directive('b2bHeaderSubmenu', ['$timeout',function ($timeout) {
3626         return{
3627             restrict: 'A',
3628             link: function (scope, elem) {
3629                 var caretSign = angular.element("<i class='menuCaret'></i>");
3630                 $timeout(function(){
3631                     var menuItem = angular.element(elem[0].children[0]);
3632                     menuItem.bind('focus mouseenter', function () {
3633                         elem.parent().children().removeClass('active');
3634                         elem.addClass('active');
3635                         if(elem[0].childElementCount > 1){ // > 1 has third level menu
3636                             menuItem.attr('aria-expanded',true);
3637                             menuItem.attr('aria-haspopup',true);
3638                         }
3639                         var caretLeft = (elem[0].offsetLeft +  elem[0].offsetWidth/2) - 10;
3640                         caretSign.css({left: caretLeft + 'px'});
3641                         angular.element(caretSign);
3642                         var tertiaryItems = elem[0].querySelectorAll('[b2b-header-tertiarymenu]');
3643                         if(tertiaryItems.length >=1){
3644                             elem.append(caretSign);
3645                         }
3646                     });
3647                     menuItem.bind('blur', function () {
3648                         $timeout(function () {
3649                             var parentElm = document.activeElement.parentElement.parentElement;
3650                             if(parentElm){
3651                                 if (!(parentElm.hasAttribute('b2b-header-tertiarymenu'))) {
3652                                     elem.removeClass('active');
3653                                     if(elem[0].childElementCount > 1){ // > 1 has third level menu
3654                                         menuItem.attr('aria-expanded',false);
3655                                     }
3656                                     var caret = elem[0].querySelector('.menuCaret');
3657                                     if(caret){
3658                                         caret.remove();
3659                                     }   
3660                                 }
3661                             }
3662                         });
3663                     });
3664                 });
3665             }
3666         };
3667     }]).directive('b2bHeaderTertiarymenu', ['$timeout','keymap', function ($timeout,keymap){
3668         return{
3669             restrict: 'A',
3670             require:'^b2bHeaderMenu',
3671             link: function (scope, elem,attr,ctrl) {
3672                 
3673                 elem.bind('keydown', function (evt) {
3674                     var activeElm = document.activeElement;
3675                     var activeParentElm = activeElm.parentElement;
3676                     var activeParentObj  = angular.element(activeParentElm)[0];
3677                     
3678                     if(activeParentElm.hasAttribute('b2b-tertiary-link')){
3679                         var quarterNav = angular.element(activeParentElm)[0].querySelector('li[b2b-header-quarternarymenu]');
3680                         if(quarterNav){
3681                             var links = ctrl.getFirstElement(angular.element(quarterNav)[0],'a');
3682                         }
3683                     }
3684                     var tertiaryMenu = activeElm.parentElement.parentElement.parentElement;
3685                     var tertiaryMenuFlag = tertiaryMenu.hasAttribute('b2b-tertiary-link');
3686                     
3687                     switch (evt.keyCode) {
3688                         case keymap.KEY.DOWN:
3689                             evt.stopPropagation();
3690                             evt.preventDefault();
3691                             if (activeParentElm.hasAttribute('b2b-tertiary-link')) {
3692                                 if(angular.element(quarterNav).hasClass('active')){
3693                                     links.focus();
3694                                 }else if(activeParentObj.nextElementSibling){
3695                                     ctrl.nextSiblingFocus(activeParentObj,true);
3696                                 }
3697                             }
3698                             else if(angular.element(activeParentElm).hasClass('active')){
3699                                 ctrl.nextSiblingFocus(activeElm);
3700                             }
3701                             break;                        
3702                         case keymap.KEY.UP:
3703                             evt.stopPropagation();
3704                             evt.preventDefault();
3705                             if(activeParentElm.hasAttribute('b2b-tertiary-link')){
3706                                 if(activeParentObj.previousElementSibling.hasAttribute('b2b-tertiary-link')){
3707                                     ctrl.previousSiblingFocus(activeParentObj,true);
3708                                 }else{
3709                                     var elm = angular.element(activeElm.parentElement.parentElement.parentElement.parentElement.parentElement)[0];
3710                                     ctrl.getFirstElement(elm,"a").focus();
3711                                 }
3712                             }else if(angular.element(activeParentElm).hasClass('active')){
3713                                     if (activeElm.previousElementSibling) {
3714                                         ctrl.previousSiblingFocus(activeElm);
3715                                     }else if (tertiaryMenuFlag) {
3716                                         var elm = angular.element(tertiaryMenu)[0];
3717                                         ctrl.getFirstElement(elm,"a.header-tertiaryitem").focus();
3718                                     }
3719                                 }
3720                             break;
3721                         default:
3722                             break;
3723                     }
3724                 });
3725             }            
3726         };          
3727     }]).directive('b2bHeaderTogglemenu', ['$timeout', 'keymap', function ($timeout, keymap) {
3728         return{
3729             restrict: 'A',
3730             require: '^b2bHeaderMenu',
3731             link: function (scope, elem, attrs, ctrl) {
3732                 var quarterNav;
3733                 $timeout(function () {
3734                     quarterNav = angular.element(elem.parent())[0].querySelector('li[b2b-header-quarternarymenu]');
3735                     elem.bind('click', function () {
3736                         angular.element(quarterNav).toggleClass('active');
3737                     });
3738                 });
3739             }
3740         };
3741     }]).directive('b2bHeaderResponsive', ['$timeout',function ($timeout) {
3742         return{
3743             restrict: 'A',
3744             controller: function($scope){
3745                 this.applyMediaQueries = function(value){
3746                     document.querySelector('style').textContent += 
3747                         "@media screen and (max-width:950px) { \
3748                             .header__item.profile { right: " + value + "px; } \
3749                         }";
3750                 };
3751                 this.arrangeResponsiveHeader = function(children){
3752                     /* 
3753                      * clientWidth of 1090 === max-width of 1100px
3754                      * clientWidth of 920 === max-width of 950px
3755                      * see b2b-angular.css for rest of responsive header CSS
3756                      */
3757                   if (document.documentElement.clientWidth <= 920) { 
3758                         switch(children){
3759                             case 1:
3760                                 this.applyMediaQueries(200);                    
3761                                 break;
3762                             case 2:
3763                                 this.applyMediaQueries(200);                            
3764                                 break;
3765                             default: // anthing above 3, however, should not have more than 3 to date
3766                                 this.applyMediaQueries(200);                                                                            
3767                         }
3768                     }
3769                 }
3770             },
3771             link: function (scope, elem, attrs, ctrl) {
3772                 var children;
3773                 var profile;
3774                 
3775                 // onload of page
3776                 $timeout(function(){ 
3777                     profile = document.querySelector('li.header__item.profile');
3778                     children = angular.element(profile).children().length;
3779                     
3780                     ctrl.arrangeResponsiveHeader(children); // shift right-side icon flyovers
3781                 });
3782
3783                 // on screen resize
3784                 window.addEventListener('resize', function(event){ // caret adjustmet
3785                     var activeSubmenu = elem[0].querySelector('[b2b-header-menu] [b2b-header-submenu].active');
3786                     var activeSubmenuEl = angular.element(activeSubmenu);
3787                     if(activeSubmenu){
3788                         var caretSign = activeSubmenu.querySelector('i.menuCaret');
3789                         if(caretSign){
3790                             var caretSignEl = angular.element(caretSign);
3791                             var caretLeft = (activeSubmenu.offsetLeft +  activeSubmenu.offsetWidth/2) - 10;
3792                             caretSignEl.css({left: caretLeft + 'px'});
3793                         }
3794                     }
3795
3796                     ctrl.arrangeResponsiveHeader(children); // shift right-side icon flyovers
3797                 });
3798             }
3799         };
3800     }]);
3801
3802 /**
3803  * @ngdoc directive
3804  * @name Layouts.att:headings
3805  *
3806  * @description
3807  *  <file src="src/headings/docs/readme.md" />
3808  *
3809  * @usage
3810     <h1 class="heading-page">38px page heading</h1>
3811     <h2 class="heading-major-section">30px major section heading</h2>
3812     <h3 class="heading-sub-section">24px sub-section heading</h3>
3813     <h2 class="heading-medium">20px medium heading</h2>
3814     <h2 class="heading-medium-emphasis">20px medium emphasis heading</h2>
3815     <h3 class="heading-small">18px small heading</h3>
3816     <h3 class="heading-small-emphasis">18px small emphasis heading</h3>
3817     <h3 class="heading-micro">13px micro heading</h3>
3818
3819     <h2 class="heading-group">Lead</h2>
3820     <h1 class="heading-page">This is 38px heading</h1>
3821     <h2 class="lead">This is lead text...The next big thing since the last big thing we announced.</h2>
3822     <h2 class="heading-group">Eyebrow</h2>
3823     <h3 class="eyebrow">EYEBROW TEXT</h3>
3824     <h2 class="heading-major-section">This is a 30px heading</h2>
3825     <h3 class="eyebrow">EYEBROW TEXT</h3>
3826     <h3 class="heading-sub-section">24px sub-section heading</h3>
3827     <h2 class="heading-group">Subheading</h2>
3828     <h2 class="heading-major-section">This is a 30px heading</h2>
3829     <h3 class="subheading">A subheading here to support what was said above</h3>
3830  * @example
3831  <section id="code">
3832     <b>HTML + AngularJS</b>
3833     <example module="b2b.att">
3834     <file src="src/headings/docs/demo.html" />
3835 </example>
3836 </section>
3837  */
3838
3839 var b2bLegalCopy = angular.module('b2b.att.headings', []);
3840 /**
3841  * @ngdoc directive
3842  * @name Tabs, tables & accordions.att:horizontalTable
3843  *
3844  * @description
3845  *  <file src="src/horizontalTable/docs/readme.md" />
3846  *
3847  * @usage
3848  * @param {int} sticky - Number of sticky columns to have. Maximum of 3.
3849  * @param {boolean} refresh - A boolean that when set to true will force a re-render of table. Only use when using 'bulk mode'
3850  * @example
3851  *  <section id="code">
3852         <example module="b2b.att">
3853             <file src="src/horizontalTable/docs/demo.html" />
3854             <file src="src/horizontalTable/docs/demo.js" />
3855        </example>
3856     </section>
3857  *
3858  */
3859 angular.module('b2b.att.horizontalTable', [])
3860     .constant('b2bHorizontalTableConfig', {
3861         'maxStickyColumns': 3
3862     })
3863     .directive('b2bHorizontalTable', ['$timeout', 'b2bHorizontalTableConfig', 'b2bDOMHelper', function ($timeout, b2bHorizontalTableConfig, b2bDOMHelper) {
3864         return {
3865             restrict: 'EA',
3866             scope: true,
3867             transclude: true,
3868             scope: {
3869                 numOfStickyCols: '=?sticky',
3870                 refresh: '=?'
3871
3872             },
3873             templateUrl: 'b2bTemplate/horizontalTable/horizontalTable.html',
3874             link: function (scope, element, attrs, ctrl) {
3875                 scope.numOfStickyCols = scope.numOfStickyCols || 1;
3876                 scope.viewportIndex = scope.numOfStickyCols;
3877
3878                 // JM520E: This is a temporary hack until I solve the ngRepeat issue
3879                 function hack() {
3880                     if (element.find('th').length < scope.numOfStickyCols) {
3881                         // DOM ngRepeat is not ready, let's check back in 10 ms
3882                         console.info('THs are not ready, trying again in 10ms');
3883                         $timeout(hack, 10, false);
3884                     } else {
3885                         init();
3886                     }
3887                 }
3888                 hack();
3889
3890                 if (attrs.refresh !== undefined && attrs.refresh !== '') {
3891                     scope.$watch('refresh', function(oldVal, newVal) {
3892                         if (scope.refresh) {
3893                             // From testing it takes about 30 ms before ngRepeat executes, so let's set initial timeout
3894                             // NOTE: May need to expose timeout to developers. Application is known to have digest cycle of 3-5k watches.
3895                             $timeout(init, 100, false);
3896                             scope.refresh = false;
3897                         }
3898                     });
3899                 }
3900
3901                 var tableElement = element.find('table');
3902                 var thElements = element.find('th');
3903                 var innerContainer = angular.element(element[0].querySelector('.b2b-horizontal-table-inner-container'));
3904                 var outerContainer = angular.element(element[0].querySelector('.b2b-horizontal-table'));
3905
3906                 var tableColumns = [];
3907                 var tableRows = element.find('tr');
3908
3909                 var maxWidth = 0,
3910                     maxHeight = 0;
3911                 var totalWidth = element.children()[0].offsetWidth;
3912                 var lastVisibleColumn = 0;
3913                 var collectiveColumnWidth = [];
3914                 var collectiveRowHeight = [];
3915                 var columnSets = [];
3916                 var setIndex = 0; 
3917                 var stickyPixels = 0;
3918
3919                 var displayNoneCSS = {'display': 'none'};
3920                 var displayBlockCSS = {'display': 'table-cell'};
3921
3922                 function calculateVisibleColumns(startingPoint) {
3923                     var usedWidth = 0, 
3924                         visibleColumns = startingPoint || scope.numOfStickyCols;
3925
3926                     while(usedWidth < stickyPixels && visibleColumns < collectiveColumnWidth.length) {
3927                         if (usedWidth+collectiveColumnWidth[visibleColumns] > stickyPixels) {
3928                             if (startingPoint === visibleColumns) {
3929                                 return visibleColumns; // The next cell is too large to fit, it should be only thing to fit
3930                             }
3931                             visibleColumns--;
3932                             return visibleColumns;
3933                         }
3934                         usedWidth += collectiveColumnWidth[visibleColumns];
3935                         visibleColumns++;
3936                     }
3937
3938                     if (usedWidth > stickyPixels) {
3939                         return --visibleColumns;
3940                     }
3941                     return visibleColumns;
3942                 }
3943
3944                 function updateCellDisplay(set) {
3945                     for (var i = scope.numOfStickyCols; i < tableColumns.length; i++) {
3946                         angular.element(tableColumns[i]).css(displayNoneCSS);
3947                     }
3948
3949                     for (var i = set[0]; i <= set[1]; i++) {
3950                         angular.element(tableColumns[i]).css(displayBlockCSS);
3951                     }
3952                 }
3953
3954                 function forceDigest() {
3955                     if (!scope.$$phase) {
3956                         scope.$digest();
3957                     }
3958                 }
3959
3960                 function findMax(arr, prop) {
3961                     var max = 0;
3962                     var localVal = 0;
3963                     var prevDisplay;
3964                     var item;
3965                     for (var i = 0; i < arr.length; i++) {
3966                         item = arr[i];
3967                         prevDisplay = angular.element(item).css('display');
3968                         if (scope.$$phase) {
3969                             scope.$digest();
3970                         }
3971                         if (prop === 'width') {
3972                             localVal = Math.ceil(parseInt(window.getComputedStyle(item).width.split('px')[0], 10)) + 30; // 30 px is padding
3973                         } else if (prop === 'offsetWidth') {
3974                             localVal = item.offsetWidth;
3975                         } else if (prop === 'height') {
3976                             localVal = item.offsetHeight;
3977                         }
3978
3979                         if (localVal >= max) {
3980                             max = localVal;
3981                         }
3982                     }
3983                     
3984                     return max;
3985                 }
3986
3987                 function init() {
3988                     // Reset this from a previous execution
3989                     tableColumns = [];
3990                     collectiveColumnWidth = [];
3991                     collectiveRowHeight = [];
3992                     maxWidth = 0;
3993                     maxHeight = 0;
3994                     lastVisibleColumn = 0;
3995                     columnSets = [];
3996                     setIndex = 0; 
3997                     visibleColumns = [];
3998                     stickyPixels = 0;
3999
4000                     tableElement = element.find('table');
4001                     thElements = element.find('th');
4002                     innerContainer = angular.element(element[0].querySelector('.b2b-horizontal-table-inner-container'));
4003                     outerContainer = angular.element(element[0].querySelector('.b2b-horizontal-table'));
4004                     totalWidth = element.children()[0].offsetWidth;
4005
4006
4007                     tableRows = element.find('tr');
4008                     totalWidth = element.children()[0].offsetWidth;
4009
4010                     scope.disableLeft = true;
4011                     scope.disableRight = false;
4012
4013                     if (scope.numOfStickyCols > b2bHorizontalTableConfig.maxStickyColumns) {
4014                         throw new Error("Table can only support 3 sticky columns.");
4015                     }                  
4016
4017                     angular.forEach(tableRows, function(row, rowIndex) {
4018                         collectiveRowHeight.push(findMax(row.children, 'height'));
4019                         for(var j = 0; j < row.children.length; j++) {
4020                             if (tableColumns[j] === undefined) {
4021                                 tableColumns[j] = [];
4022                             }
4023                             tableColumns[j].push(row.children[j]);
4024                         }
4025                     });
4026
4027                     // We need to reset all the displayNones from previous runs, if applicable
4028                     if (attrs.refresh !== undefined && attrs.refresh !== '')  {
4029                         for (var i = scope.numOfStickyCols+1; i < tableColumns.length; i++) {
4030                             angular.element(tableColumns[i]).css(displayBlockCSS);
4031                         }
4032                     }
4033
4034                     for (var i = 0; i < tableColumns.length; i++) {
4035                         collectiveColumnWidth.push(findMax(tableColumns[i], 'width')); //offsetWidth doesn't take into account custom css inside
4036                     }
4037                     for(var i = 0; i < scope.numOfStickyCols; i++) {
4038                         maxWidth += collectiveColumnWidth[i];
4039                     }
4040       
4041                     stickyPixels = totalWidth-maxWidth;
4042
4043
4044                     // At this point, for each tr, I need to set the properties (height) and each numOfStickyCols children
4045                     // should be set with sticky properties (margin-left and width)
4046                     var width = maxWidth;
4047                     for(var i = 0; i < scope.numOfStickyCols; i++) {
4048                         for (var j = 0; j < tableRows.length; j++) {
4049                             trObject = angular.element(tableRows[j].children[i]);
4050                             
4051                             angular.element(trObject).css({
4052                                 'margin-left': -(width + 2) + 'px', 
4053                                 'width': (collectiveColumnWidth[i] + 3) + 'px', // instead of taking the max width, grab max width for that column
4054                                 'height': collectiveRowHeight[j] + 'px',
4055                                 'position': 'absolute',
4056                                 'background-color': 'lightgrey'
4057                             });
4058                         }
4059                         
4060
4061                         width -= collectiveColumnWidth[i];
4062                     }
4063
4064                     innerContainer.css({
4065                         'padding-left': (maxWidth + 2) + 'px'
4066                     });
4067
4068
4069                     // Let's precompute all the (set) combinations beforehand
4070                     columnSets = []; 
4071                     for (var i = scope.numOfStickyCols; i < tableColumns.length;) {
4072                         visibleColumns = calculateVisibleColumns(i);
4073                         columnSets.push([i, visibleColumns]);
4074                         i = visibleColumns + 1;
4075                     }
4076                     
4077                     updateCellDisplay(columnSets[setIndex]);
4078                     checkScrollArrows();
4079
4080                     scope.numOfCols = tableColumns.length;
4081
4082                     console.log('Bulk Mode is ' + (attrs.bulkMode ? 'enabled': 'disabled'));
4083                     console.log('tableColumns', tableColumns);
4084                     console.log('collectiveColumnWidth: ', collectiveColumnWidth);
4085                     console.log('maxWidth: ', maxWidth);
4086                 }
4087
4088                 function checkScrollArrows() {
4089                     scope.disableLeft = (setIndex === 0);
4090                     scope.disableRight = !(setIndex < columnSets.length-1);
4091                 }
4092
4093
4094                 scope.moveViewportLeft = function () {
4095                     setIndex--;
4096                     updateCellDisplay(columnSets[setIndex]);
4097                     checkScrollArrows();
4098
4099                     if (scope.disableLeft) {
4100                         element.find('span')[0].focus();
4101                     }
4102                 };
4103                 
4104                 scope.moveViewportRight = function () {
4105                     setIndex++;
4106                     updateCellDisplay(columnSets[setIndex]);
4107                     checkScrollArrows();
4108                     
4109                     if (scope.disableRight) {
4110                         element.find('span')[0].focus();
4111                     }
4112                 };
4113
4114                 scope.getColumnSet = function () {
4115                     return columnSets[setIndex];
4116                 };
4117
4118                 innerContainer.bind('scroll', function () {
4119                     $timeout(function () {
4120                         checkScrollArrows();
4121                     }, 1);
4122                 });
4123
4124             }
4125         };
4126     }]);
4127 /**
4128  * @ngdoc directive
4129  * @name Forms.att:hourPicker
4130  *
4131  * @description
4132  *  <file src="src/hourPicker/docs/readme.md" />
4133  *
4134  * @usage
4135  * <div b2b-hourpicker ng-model="hourpickerValue.value"></div>
4136     
4137  * @example
4138  *  <section id="code">
4139         <example module="b2b.att">
4140             <file src="src/hourPicker/docs/demo.html" />
4141             <file src="src/hourPicker/docs/demo.js" />
4142         </example>
4143     </section>
4144  *
4145  */
4146 angular.module('b2b.att.hourPicker', ['b2b.att.utilities'])
4147
4148 .constant('b2bHourpickerConfig', {
4149     dayOptions: [{
4150         title: 'sunday',
4151         caption: 'Sun',
4152         label: 'S',
4153         disabled: false
4154     }, {
4155         title: 'monday',
4156         caption: 'Mon',
4157         label: 'M',
4158         disabled: false
4159     }, {
4160         title: 'tuesday',
4161         caption: 'Tues',
4162         label: 'T',
4163         disabled: false
4164     }, {
4165         title: 'wednesday',
4166         caption: 'Wed',
4167         label: 'W',
4168         disabled: false
4169     }, {
4170         title: 'thursday',
4171         caption: 'Thu',
4172         label: 'T',
4173         disabled: false
4174     }, {
4175         title: 'friday',
4176         caption: 'Fri',
4177         label: 'F',
4178         disabled: false
4179     }, {
4180         title: 'saturday',
4181         caption: 'Sat',
4182         label: 'S',
4183         disabled: false
4184     }],
4185     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'],
4186     startTimeDefaultOptionIndex: -1,
4187     startTimeDefaultMeridiem: "am",
4188     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'],
4189     endTimeDefaultOptionIndex: -1,
4190     endTimeDefaultMeridiem: "pm",
4191     sameDayOption: true
4192 })
4193
4194 .factory('b2bNormalizeHourpickerValues', [function () {
4195     var _normalize = function (hourpickerValues) {
4196         if (angular.isDefined(hourpickerValues) && hourpickerValues != null) {
4197             var finalHourpickerValues = [];
4198             var hourpickerValue = {};
4199             var days = {};
4200             for (var i = 0; i < hourpickerValues.length; i++) {
4201                 days = hourpickerValues[i].days ? hourpickerValues[i].days : {};
4202                 hourpickerValue.startTime = hourpickerValues[i].startTime ? hourpickerValues[i].startTime : '';
4203                 hourpickerValue.startMeridiem = hourpickerValues[i].startMeridiem ? hourpickerValues[i].startMeridiem : '';
4204                 hourpickerValue.endTime = hourpickerValues[i].endTime ? hourpickerValues[i].endTime : '';
4205                 hourpickerValue.endMeridiem = hourpickerValues[i].endMeridiem ? hourpickerValues[i].endMeridiem : '';
4206                 hourpickerValue.days = [];
4207
4208                 var retrieveDaysText = function (daysDetails) {
4209                     var daysTexts = [];
4210                     var first = -1;
4211                     var last = -1;
4212                     var index = -1;
4213                     for (var i in days) {
4214                         if (days[i].value) {
4215                             daysTexts.push(i);
4216                         }
4217                     }
4218
4219                     first = daysTexts[0];
4220                     last = daysTexts[0];
4221                     index = 0;
4222                     hourpickerValue.days[index] = days[first].caption;
4223                     if (daysTexts.length > 1) {
4224                         for (var i = 1; i < daysTexts.length; i++) {
4225                             if (daysTexts[i] - last === 1) {
4226                                 last = daysTexts[i];
4227                                 hourpickerValue.days[index] = days[first].caption + ' - ' + days[last].caption;
4228                             } else {
4229                                 index++;
4230                                 first = last = daysTexts[i];
4231                                 hourpickerValue.days[index] = days[first].caption;
4232                             }
4233                         }
4234                     }
4235                 };
4236                 retrieveDaysText();
4237
4238                 finalHourpickerValues.push(angular.copy(hourpickerValue));
4239             }
4240
4241             return angular.copy(finalHourpickerValues);
4242         }
4243     };
4244
4245     return {
4246         normalize: _normalize
4247     };
4248 }])
4249
4250 .directive('b2bHourpicker', ['b2bHourpickerConfig', 'b2bNormalizeHourpickerValues', function (b2bHourpickerConfig, b2bNormalizeHourpickerValues) {
4251     return {
4252         restrict: 'EA',
4253         replace: false,
4254         scope: true,
4255         require: 'ngModel',
4256         templateUrl: 'b2bTemplate/hourPicker/b2bHourpicker.html',
4257         controller: ['$scope', function (scope) {
4258
4259         }],
4260         link: function (scope, elem, attr, ctrl) {
4261             scope.hourpicker = {};
4262             scope.hourpicker.dayOptions = attr.dayOptions ? scope.$parent.$eval(attr.dayOptions) : b2bHourpickerConfig.dayOptions;
4263             scope.hourpicker.startTimeOptions = attr.startTimeOptions ? scope.$parent.$eval(attr.startTimeOptions) : b2bHourpickerConfig.startTimeOptions;
4264             scope.hourpicker.endTimeOptions = attr.endTimeOptions ? scope.$parent.$eval(attr.endTimeOptions) : b2bHourpickerConfig.endTimeOptions;
4265             scope.hourpicker.startTimeDefaultOptionIndex = attr.startTimeDefaultOptionIndex ? scope.$parent.$eval(attr.startTimeDefaultOptionIndex) : b2bHourpickerConfig.startTimeDefaultOptionIndex;
4266             scope.hourpicker.endTimeDefaultOptionIndex = attr.endTimeDefaultOptionIndex ? scope.$parent.$eval(attr.endTimeDefaultOptionIndex) : b2bHourpickerConfig.endTimeDefaultOptionIndex;
4267             scope.hourpicker.startTimeDefaultMeridiem = attr.startTimeDefaultMeridiem ? scope.$parent.$eval(attr.startTimeDefaultMeridiem) : b2bHourpickerConfig.startTimeDefaultMeridiem;
4268             scope.hourpicker.endTimeDefaultMeridiem = attr.endTimeDefaultMeridiem ? scope.$parent.$eval(attr.endTimeDefaultMeridiem) : b2bHourpickerConfig.endTimeDefaultMeridiem;
4269             scope.hourpicker.sameDayOption = attr.sameDayOption ? scope.$parent.$eval(attr.sameDayOption) : b2bHourpickerConfig.sameDayOption;
4270             scope.hourpicker.editMode = -1;
4271
4272             scope.hourpickerValues = [];
4273             scope.finalHourpickerValues = [];
4274             scope.addHourpickerValue = function (hourpickerPanelValue) {
4275                 if (hourpickerPanelValue) {
4276                     if (scope.hourpicker.editMode > -1) {
4277                         scope.hourpickerValues[scope.hourpicker.editMode] = hourpickerPanelValue;
4278                         scope.hourpicker.editMode = -1;
4279                     } else {
4280                         scope.hourpickerValues.push(hourpickerPanelValue);
4281                     }
4282                 }
4283                 scope.finalHourpickerValues = b2bNormalizeHourpickerValues.normalize(angular.copy(scope.hourpickerValues));
4284                 ctrl.$setViewValue(angular.copy(scope.hourpickerValues));
4285             };
4286             ctrl.$render = function () {
4287                 if (angular.isDefined(ctrl.$modelValue)) {
4288                     scope.hourpickerValues = angular.copy(ctrl.$modelValue);
4289                     scope.finalHourpickerValues = b2bNormalizeHourpickerValues.normalize(angular.copy(scope.hourpickerValues));
4290                 }
4291             };
4292             scope.editHourpickerValue = function (index) {
4293                 scope.hourpickerPanelValue = angular.copy(scope.hourpickerValues[index]);
4294                 scope.hourpicker.editMode = index;
4295             };
4296             scope.deleteHourpickerValue = function (index) {
4297                 scope.hourpickerValues.splice(index, 1);
4298                 scope.resetHourpickerPanelValue();
4299                 scope.addHourpickerValue();
4300             };
4301
4302             scope.setValidity = function (errorType, errorValue) {
4303                 ctrl.$setValidity(errorType, errorValue);
4304             }
4305         }
4306     }
4307 }])
4308
4309 .directive('b2bHourpickerPanel', [function () {
4310     return {
4311         restrict: 'EA',
4312         replace: false,
4313         templateUrl: 'b2bTemplate/hourPicker/b2bHourpickerPanel.html',
4314         controller: ['$scope', function (scope) {
4315
4316         }],
4317         link: function (scope, elem, attr, ctrl) {
4318             var hourpickerPanelValueTemplate = {
4319                 days: {},
4320                 startTime: '',
4321                 startMeridiem: 'am',
4322                 endTime: '',
4323                 endMeridiem: 'pm'
4324             };
4325             for (var i = 0; i < scope.hourpicker.dayOptions.length; i++) {
4326                 hourpickerPanelValueTemplate.days[i] = {
4327                     value: false,
4328                     title: scope.hourpicker.dayOptions[i].title,
4329                     caption: scope.hourpicker.dayOptions[i].caption
4330                 };
4331             }
4332             scope.hourpickerPanelValue = {};
4333             scope.disableAddBtn = true;
4334
4335             scope.$watch('hourpickerPanelValue.days', function(){
4336                 for(var i in scope.hourpickerPanelValue.days)
4337                 {
4338                     if(scope.hourpickerPanelValue.days[i].value)
4339                     {
4340                         scope.disableAddBtn = false;
4341                         break;
4342                     }
4343                     scope.disableAddBtn = true;
4344                 }
4345             }, true);
4346
4347             scope.resetHourpickerPanelValue = function () {
4348                 scope.hourpickerPanelValue = angular.copy(hourpickerPanelValueTemplate);
4349                 if (scope.hourpicker.startTimeDefaultOptionIndex > -1) {
4350                     scope.hourpickerPanelValue.startTime = scope.hourpicker.startTimeOptions[scope.hourpicker.startTimeDefaultOptionIndex];
4351                 }
4352                 if (scope.hourpicker.endTimeDefaultOptionIndex > -1) {
4353                     scope.hourpickerPanelValue.endTime = scope.hourpicker.endTimeOptions[scope.hourpicker.endTimeDefaultOptionIndex];
4354                 }
4355                 scope.hourpickerPanelValue.startMeridiem = scope.hourpicker.startTimeDefaultMeridiem;
4356                 scope.hourpickerPanelValue.endMeridiem = scope.hourpicker.endTimeDefaultMeridiem;
4357                 scope.hourpicker.editMode = -1;
4358                 scope.setValidity('invalidHourpickerData', true);
4359                 scope.setValidity('invalidHourpickerTimeRange', true);
4360             };
4361             scope.resetHourpickerPanelValue();
4362             scope.updateHourpickerValue = function () {
4363                 if (scope.isFormValid() && !scope.isTimeOverlap()) {
4364                     scope.addHourpickerValue(angular.copy(scope.hourpickerPanelValue));
4365                     scope.resetHourpickerPanelValue();
4366                 }
4367             };
4368
4369             scope.isFormValid = function () {
4370                 var isStartTimeAvailable = scope.hourpickerPanelValue.startTime ? true : false;
4371                 var isStartMeridiemAvailable = scope.hourpickerPanelValue.startMeridiem ? true : false;
4372                 var isEndTimeAvailable = scope.hourpickerPanelValue.endTime ? true : false;
4373                 var isEndMeridiemAvailable = scope.hourpickerPanelValue.endMeridiem ? true : false;
4374                 var currentStartTime = getTime(scope.hourpickerPanelValue.startTime, scope.hourpickerPanelValue.startMeridiem);
4375                 var currentEndTime = getTime(scope.hourpickerPanelValue.endTime, scope.hourpickerPanelValue.endMeridiem);
4376                 var isTimeInProperSequence = currentEndTime > currentStartTime;
4377                 var isDayChecked = false;
4378                 for (var i in scope.hourpickerPanelValue.days) {
4379                     if (scope.hourpickerPanelValue.days[i].value) {
4380                         isDayChecked = true;
4381                         break;
4382                     }
4383                 }
4384
4385                 if (isStartTimeAvailable && isStartMeridiemAvailable && isEndTimeAvailable && isEndMeridiemAvailable && isTimeInProperSequence && isDayChecked) {
4386                     scope.setValidity('invalidHourpickerData', true);
4387                     return true;
4388                 } else {
4389                     scope.setValidity('invalidHourpickerData', false);
4390                     return false;
4391                 }
4392             };
4393             scope.isTimeOverlap = function () {
4394                 var selectedDays = [];
4395                 for (var i in scope.hourpickerPanelValue.days) {
4396                     if (scope.hourpickerPanelValue.days[i].value) {
4397                         selectedDays.push(i);
4398                     }
4399                 }
4400
4401                 var currentStartTime, currentEndTime, existingStartTime, existingEndTime;
4402                 currentStartTime = getTime(scope.hourpickerPanelValue.startTime, scope.hourpickerPanelValue.startMeridiem);
4403                 currentEndTime = getTime(scope.hourpickerPanelValue.endTime, scope.hourpickerPanelValue.endMeridiem);
4404                 for (var i = 0; i < scope.hourpickerValues.length; i++) {
4405                     
4406                     if (i === scope.hourpicker.editMode) {
4407                         continue;
4408                     }
4409
4410                     for (var j = 0; j < selectedDays.length; j++) {
4411                         existingStartTime = getTime(scope.hourpickerValues[i].startTime, scope.hourpickerValues[i].startMeridiem);
4412                         existingEndTime = getTime(scope.hourpickerValues[i].endTime, scope.hourpickerValues[i].endMeridiem);
4413                         if (scope.hourpickerValues[i].days[selectedDays[j]].value) {
4414                             if(!scope.hourpicker.sameDayOption){
4415                                 scope.setValidity('dayAlreadySelected', false);
4416                                 return true;
4417                             } else if ((currentStartTime > existingStartTime && currentStartTime < existingEndTime) || (currentEndTime > existingStartTime && currentEndTime < existingEndTime)) {
4418                                 scope.setValidity('invalidHourpickerTimeRange', false);
4419                                 return true;
4420                             } else if ((existingStartTime > currentStartTime && existingStartTime < currentEndTime) || (existingEndTime > currentStartTime && existingEndTime < currentEndTime)) {
4421                                 scope.setValidity('invalidHourpickerTimeRange', false);
4422                                 return true;
4423                             } else if ((currentStartTime === existingStartTime) && (currentEndTime === existingEndTime)) {
4424                                 scope.setValidity('invalidHourpickerTimeRange', false);
4425                                 return true;
4426                             }
4427                         }
4428                     }
4429                 }
4430
4431                 scope.setValidity('dayAlreadySelected', true);
4432                 scope.setValidity('invalidHourpickerTimeRange', true);
4433                 return false;
4434             };
4435             var getTime = function (timeString, meridiem) {
4436                 var tempDate = new Date();
4437                 if (timeString && meridiem) {
4438                     var timeSplit = timeString.split(':');
4439                     var hour = ((meridiem === 'PM' || meridiem === 'pm') && timeSplit[0] !== '12') ? parseInt(timeSplit[0], 10) + 12 : parseInt(timeSplit[0], 10);
4440                     tempDate.setHours(hour, parseInt(timeSplit[1], 10), 0, 0);
4441                 }
4442
4443                 return tempDate.getTime();
4444             };
4445         }
4446     }
4447 }])
4448
4449 .directive('b2bHourpickerValue', [function () {
4450     return {
4451         restrict: 'EA',
4452         replace: false,
4453         templateUrl: 'b2bTemplate/hourPicker/b2bHourpickerValue.html',
4454         controller: ['$scope', function (scope) {
4455
4456         }],
4457         link: function (scope, elem, attr, ctrl) {
4458             scope.hourpickerValue = {};
4459             scope.hourpickerValue.startTime = attr.startTime ? scope.$eval(attr.startTime) : '';
4460             scope.hourpickerValue.startMeridiem = attr.startMeridiem ? scope.$eval(attr.startMeridiem) : '';
4461             scope.hourpickerValue.endTime = attr.endTime ? scope.$eval(attr.endTime) : '';
4462             scope.hourpickerValue.endMeridiem = attr.endMeridiem ? scope.$eval(attr.endMeridiem) : '';
4463             scope.hourpickerValue.days = attr.days ? scope.$eval(attr.days).join(', ') : '';
4464             scope.hourpickerValue.index = attr.b2bHourpickerValue ? scope.$eval(attr.b2bHourpickerValue) : -1;
4465         }
4466     }
4467 }]);
4468 /**
4469  * @ngdoc directive
4470  * @name Template.att:inputTemplate
4471  *
4472  * @description
4473  *  <file src="src/inputTemplate/docs/readme.md" />
4474  *
4475  * @usage
4476  *  <input type="text" id="fieldId" placeholder="placholder text here" class="span12 input-enhanced" name="fieldName">
4477  *
4478  * @example
4479  <section id="code">
4480     <b>HTML + AngularJS</b>
4481     <example module="b2b.att">
4482         <file src="src/inputTemplate/docs/demo.html" />
4483         <file src="src/inputTemplate/docs/demo.js" />
4484     </example>
4485  </section>
4486  */
4487 angular.module('b2b.att.inputTemplate', []);
4488
4489 /**
4490  * @ngdoc directive
4491  * @name Navigation.att:leftNavigation
4492  *
4493  * @description
4494  *  <file src="src/leftNavigation/docs/readme.md" />
4495  *
4496  * @usage
4497  *   <b2b-left-navigation data-menu="menuData"></b2b-left-navigation> 
4498  *
4499  * @example
4500  *  <section id="code">
4501         <example module="b2b.att">
4502             <file src="src/leftNavigation/docs/demo.html" />
4503             <file src="src/leftNavigation/docs/demo.js" />
4504        </example>
4505     </section>
4506  *
4507  */
4508 angular.module('b2b.att.leftNavigation', [])
4509     .directive('b2bLeftNavigation', [function () {
4510         return {
4511             restrict: 'EA',
4512             templateUrl: 'b2bTemplate/leftNavigation/leftNavigation.html',
4513             scope: {
4514                 menuData: '='
4515             },
4516             link: function (scope, element, attrs, ctrl) {
4517                 scope.idx = -1;
4518                 scope.itemIdx = -1;
4519                 scope.navIdx = -1;
4520                 scope.toggleNav = function (val,link) {
4521                         /**Added for ECOMP: make parent menu a link if no child menus.**/
4522                         if(link!=null && link!=''){
4523                                 location.href = link;
4524                                 return;
4525                         }
4526                         /**Ended**/
4527                         if (val === scope.idx) {
4528                         scope.idx = -1;
4529                         return;
4530                     }
4531                     scope.idx = val;
4532                 };
4533                 /*New function for ECOMP*/
4534                 scope.toggleDrawer = function(showmenu){
4535                         scope.idx=-1; /*hide the sunmenus*/
4536                         if(showmenu){
4537                                 //scope.openList.length=0;
4538                                 document.getElementById('page-content').style.marginLeft = "50px";
4539                         }
4540                         else
4541                                 document.getElementById('page-content').style.marginLeft = "250px";             
4542                 };
4543                 scope.liveLink = function (evt, val1, val2) {
4544                     scope.itemIdx = val1;
4545                     scope.navIdx = val2;
4546                     evt.stopPropagation();
4547                 };
4548             }
4549         };
4550     }]);
4551 /**
4552  * @ngdoc directive
4553  * @name Buttons, links & UI controls.att:links
4554  *
4555  * @description
4556  *  <file src="src/links/docs/readme.md" />
4557  * @usage
4558  *      <!-- See below examples for link implementation -->
4559  *      
4560  * @example
4561        <section id="code">              
4562            <b>HTML + AngularJS</b>
4563            <example module="b2b.att">
4564            <file src="src/links/docs/demo.html" />
4565             <file src="src/links/docs/demo.js" />            
4566           </example>          
4567         </section>
4568  */
4569 angular.module('b2b.att.links', []);
4570 /**
4571  * @ngdoc directive
4572  * @name Misc.att:listbox
4573  *
4574  * @description
4575  *  <file src="src/listbox/docs/readme.md" />
4576  *
4577  * @param {int} currentIndex - Current index of selected listbox item. Is not supported on multiselect listbox
4578  * @param {Array} listboxData - Data of listbox items. Should include full data regardless if HTML will be filtered.
4579
4580  * @example
4581  *  <section id="code">   
4582      <example module="b2b.att">
4583      <file src="src/listbox/docs/demo.html" />
4584      <file src="src/listbox/docs/demo.js" />
4585      </example>
4586     </section>
4587  *
4588  */
4589 angular.module('b2b.att.listbox', ['b2b.att.utilities'])
4590 .directive('b2bListBox', ['keymap', 'b2bDOMHelper', '$rootScope', function(keymap, b2bDOMHelper, $rootScope) {
4591                 return {
4592                     restrict: 'AE',
4593                     transclude: true,
4594                     replace: true,
4595                     scope: {
4596                         currentIndex: '=', 
4597                         listboxData: '='
4598                     },
4599                     templateUrl: 'b2bTemplate/listbox/listbox.html',
4600                     link: function(scope, elem, attr) {
4601
4602                         if (attr.ariaMultiselectable !== undefined || attr.ariaMultiselectable === 'true') {
4603                             scope.multiselectable = true;
4604                         } else {
4605                             scope.multiselectable = false;
4606                         }
4607
4608                         var shiftKey = false;
4609                         var elements = [];
4610                         var prevDirection = undefined; // previous direction is used for an edge case when shifting
4611                         var shiftKeyPressed = false; // Used to handle shift clicking
4612                         var ctrlKeyPressed = false;
4613
4614                         var currentIndexSet = {
4615                             'elementIndex': 0,
4616                             'listboxDataIndex': 0
4617                         };
4618
4619                         /*scope.$watch('currentIndex', function(oldVal, newVal) {
4620                             if (angular.equals(oldVal, newVal)) return;
4621                             if (!scope.multiselectable) {
4622                                 // This doesn't garuntee anything. index will update on focus based on rules
4623                                 currentIndexSet.listboxDataIndex = scope.currentIndex;
4624                                 // Should this occur? 
4625                                 //scope.listboxData[currentIndexSet.listboxDataIndex].selected = true;
4626
4627                                 // Update elementIndex
4628                                 elements = elem.children();
4629                                 var indecies = Array.prototype.map.call(elements, function(item) {
4630                                     return parseInt(angular.element(item).attr('data-index'), 10);
4631                                 }).filter(function(item) {
4632                                     return item === scope.currentIndex;
4633                                 });
4634                                 currentIndex.elementIndex = indecies[0];
4635                                 //focusOnElement(currentIndexSet.elementIndex); // This isn't shifting focus
4636                                 if (!scope.$$phase) {
4637                                     scope.$apply();
4638                                 }
4639                             }
4640                         });*/
4641
4642                         function isTrue(item) {
4643                             if (item.selected === true) {
4644                                 return true;
4645                             }
4646                         }
4647
4648                         function incrementIndex(elem) {
4649                             $rootScope.$apply();
4650
4651                             var nextElem = elem.next();
4652                             if (!angular.isDefined(nextElem) || nextElem.length === 0) {
4653                                 return;
4654                             }
4655
4656                             currentIndexSet.elementIndex += 1;
4657                             currentIndexSet.listboxDataIndex = parseInt(nextElem.attr('data-index'), 10);
4658                             scope.currentIndex = currentIndexSet.listboxDataIndex;
4659
4660                             if (currentIndexSet.elementIndex >= elements.length - 1) {
4661                                 currentIndexSet.elementIndex = elements.length-1;
4662                             }
4663                         }
4664
4665                         function decrementIndex(elem) {
4666                             $rootScope.$apply();
4667                             var prevElem = angular.element(b2bDOMHelper.previousElement(elem));
4668                             if (!angular.isDefined(prevElem) || prevElem.length === 0) {
4669                                 return;
4670                             }
4671
4672                             currentIndexSet.elementIndex -= 1;
4673                             currentIndexSet.listboxDataIndex = parseInt(prevElem.attr('data-index'), 10);
4674                             scope.currentIndex = currentIndexSet.listboxDataIndex;
4675
4676                             if (currentIndexSet.elementIndex <= 0) {
4677                                 currentIndexSet.elementIndex = 0;
4678                             }
4679                         }
4680
4681                         var focusOnElement = function(index) {
4682                             try {
4683                                 elements[index].focus();
4684                             } catch (e) {};
4685                         }
4686
4687                         function selectItems(startIndex, endIndex, forceValue) {
4688                             for (var i = startIndex; i < endIndex; i++) {
4689                                 if (forceValue === undefined) {
4690                                     // We will flip the value
4691                                     scope.listboxData[i].selected = !scope.listboxData[i].selected;
4692                                 } else {
4693                                     scope.listboxData[i].selected = forceValue;
4694                                 }
4695                             }
4696
4697                             if (!scope.$$phase) {
4698                                 scope.$apply();
4699                             }
4700                         }
4701
4702                         elem.bind('focus', function(evt) { 
4703                             // If multiselectable or not and nothing is selected, put focus on first element 
4704                             // If multiselectable and a range is set, put focus on first element of range 
4705                             // If not multiselectable and something selected, put focus on element 
4706                             elements = elem.children(); 
4707                              var selectedItems = scope.listboxData.filter(isTrue); 
4708                              var elementsIndies = Array.prototype.map.call(elements, function(item) {
4709                                 return parseInt(angular.element(item).attr('data-index'), 10);
4710                             });
4711  
4712                             if (selectedItems.length == 0) { 
4713                                 focusOnElement(0); 
4714                                 currentIndexSet.listboxDataIndex = 0;
4715                             } else if (attr.ariaMultiselectable) { 
4716                                 var index = scope.listboxData.indexOf(selectedItems[0]); 
4717                                 var indies = elementsIndies.filter(function(item) {
4718                                     return (item === index);
4719                                 });
4720
4721                                 if (indies.length === 0 || indies[0] != index) {
4722                                     // Set focused on 0
4723                                     currentIndexSet.elementIndex = elementsIndies[0]; 
4724                                     currentIndexSet.listboxDataIndex = 0;
4725                                     focusOnElement(currentIndexSet.elementIndex);
4726                                 } else {
4727                                     focusOnElement(indies[0]); 
4728                                     currentIndexSet.elementIndex = indies[0];
4729                                     currentIndexSet.listboxDataIndex = index;
4730                                 }
4731                             } else { 
4732                                 focusOnElement(currentIndexSet.elementIndex);  
4733                             }
4734                             scope.currentIndex = currentIndexSet.listboxDataIndex;
4735
4736                             if (!scope.$$phase) {
4737                                 scope.$apply();
4738                             }
4739                         });
4740                         elem.bind('keyup', function(evt) {
4741                             if (evt.keyCode === keymap.KEY.SHIFT) {
4742                                 shiftKeyPressed = false;
4743                             } else if (evt.keyCode === keymap.KEY.CTRL) {
4744                                 ctrlKeyPressed = false;
4745                             }
4746                         });
4747         
4748                         elem.bind('keydown', function(evt) {
4749                             var keyCode = evt.keyCode;
4750                             elements = elem.children();
4751                             if (keyCode === keymap.KEY.SHIFT) {
4752                                 shiftKeyPressed = true;
4753                             } else if (evt.keyCode === keymap.KEY.CTRL) {
4754                                 ctrlKeyPressed = true;
4755                             }
4756
4757                             switch(keyCode) {
4758                                 case 65: // A key
4759                                 {
4760                                     if (scope.multiselectable && evt.ctrlKey) {
4761                                         var arr = scope.listboxData.filter(isTrue);
4762                                         var elementsIndies = Array.prototype.map.call(elements, function(item) {
4763                                             return parseInt(angular.element(item).attr('data-index'), 10);
4764                                         });
4765                                         var val = !(arr.length === scope.listboxData.length);
4766                                         for (var i = 0; i < elementsIndies.length; i++) {
4767                                             scope.listboxData[elementsIndies[i]].selected = val;
4768                                         }
4769
4770                                         if (!scope.$$phase) {
4771                                             scope.$apply();
4772                                         }
4773                                         
4774                                         evt.preventDefault();
4775                                         evt.stopPropagation();
4776                                     }
4777                                     break;
4778                                 }
4779                                 case keymap.KEY.END:
4780                                 {
4781                                     if (scope.multiselectable && evt.ctrlKey && evt.shiftKey) {
4782                                         var elementsIndies = Array.prototype.map.call(elements, function(item) {
4783                                             return parseInt(angular.element(item).attr('data-index'), 10);
4784                                         }).filter(function(item) {
4785                                             return (item >= currentIndexSet.listboxDataIndex);
4786                                         });
4787                                         for (var i = 0; i < elementsIndies.length; i++) {
4788                                             scope.listboxData[elementsIndies[i]].selected = true;
4789                                         }
4790                                         evt.preventDefault();
4791                                         evt.stopPropagation();
4792
4793                                         if (!scope.$$phase) {
4794                                             scope.$apply();
4795                                         }
4796                                     }
4797                                     break;
4798                                 }
4799                                 case keymap.KEY.HOME: 
4800                                 {
4801                                     if (scope.multiselectable && evt.ctrlKey && evt.shiftKey) {
4802                                         selectItems(0, currentIndexSet.listboxDataIndex+1, true); // currentIndex+1 is what is being focused on
4803                                         evt.preventDefault();
4804                                         evt.stopPropagation();
4805                                     }
4806                                     break;
4807                                 }
4808                                 case keymap.KEY.LEFT:
4809                                 case keymap.KEY.UP:
4810                                 {
4811                                     if (currentIndexSet.listboxDataIndex === 0) {
4812                                         evt.preventDefault();
4813                                         evt.stopPropagation();
4814                                         return;
4815                                     }
4816
4817                                     decrementIndex(elements.eq(currentIndexSet.elementIndex));
4818                                     if (scope.multiselectable && (evt.shiftKey || evt.ctrlKey)) {
4819                                         if (evt.shiftKey) {
4820                                             if (prevDirection === 'DOWN') {
4821                                                 scope.listboxData[currentIndexSet.listboxDataIndex+1].selected = !scope.listboxData[currentIndexSet.listboxDataIndex+1].selected;
4822                                             }
4823                                             scope.listboxData[currentIndexSet.listboxDataIndex].selected = !scope.listboxData[currentIndexSet.listboxDataIndex].selected;
4824                                         }
4825                                         prevDirection = 'UP';
4826                                     } else {
4827                                         // If no modifier keys are selected, all other items need to be unselected.
4828                                         prevDirection = undefined;
4829                                         selectItems(0, scope.listboxData.length, false);
4830                                         scope.listboxData[currentIndexSet.listboxDataIndex].selected = true;
4831                                     }
4832                                     focusOnElement(currentIndexSet.elementIndex);
4833                                     if(!scope.$$phase) {
4834                                         scope.$apply();
4835                                     }
4836                                     evt.preventDefault();
4837                                     evt.stopPropagation();
4838                                     break;
4839                                 }
4840                                 case keymap.KEY.RIGHT:
4841                                 case keymap.KEY.DOWN:
4842                                 {
4843                                     if (currentIndexSet.listboxDataIndex === scope.listboxData.length-1) {
4844                                         evt.preventDefault();
4845                                         evt.stopPropagation();
4846                                         return;
4847                                     }
4848
4849                                     incrementIndex(elements.eq(currentIndexSet.elementIndex));
4850                                     
4851                                     if (scope.multiselectable && (evt.shiftKey || evt.ctrlKey)) {
4852                                         if (evt.shiftKey) {
4853                                             if (prevDirection === 'UP') {
4854                                                 scope.listboxData[currentIndexSet.listboxDataIndex-1].selected = !scope.listboxData[currentIndexSet.listboxDataIndex-1].selected;
4855                                             }
4856                                             
4857                                             scope.listboxData[currentIndexSet.listboxDataIndex].selected = !scope.listboxData[currentIndexSet.listboxDataIndex].selected;    
4858                                         }
4859                                         prevDirection = 'DOWN';
4860                                     } else {
4861                                         // If no modifier keys are selected, all other items need to be unselected.
4862                                         prevDirection = undefined;
4863                                         selectItems(0, scope.listboxData.length, false);
4864                                         scope.listboxData[currentIndexSet.listboxDataIndex].selected = true;
4865                                     }
4866
4867                                     focusOnElement(currentIndexSet.elementIndex);
4868                                     if(!scope.$$phase) {
4869                                         scope.$apply();
4870                                     }
4871                                     evt.preventDefault();
4872                                     evt.stopPropagation();
4873                                     break;
4874                                 }
4875                                 case keymap.KEY.TAB:
4876                                     if(evt.shiftKey) {
4877                                         var previousElement = b2bDOMHelper.previousElement(elem.parent().parent(), true);
4878                                         evt.preventDefault();
4879                                         previousElement.focus();
4880                                     }
4881                                     break;
4882                                 default:
4883                                     break;
4884                             }
4885                         });
4886
4887                         elem.bind('click', function(evt) {
4888                             var index = parseInt(evt.target.dataset.index, 10);
4889                             if (index === undefined || isNaN(index)) {
4890                                 return;
4891                             }
4892                             if (scope.multiselectable && currentIndexSet.listboxDataIndex !== undefined) {
4893                                 if (shiftKeyPressed) {
4894                                     var min = Math.min(index, currentIndexSet.listboxDataIndex);
4895                                     var max = Math.max(index, currentIndexSet.listboxDataIndex);
4896
4897                                     if (index === min) { // clicking up
4898                                         var firstIndex = scope.listboxData.findIndex(function(item) { return item.selected === true;});
4899                                         // Given the firstIndex, let's find the matching element to get proper element match
4900                                         elements = elem.children();
4901                                         elements.eq(firstIndex)
4902                                         var elementsThatMatch = Array.prototype.filter.call(elements, function(item) {
4903                                             if (parseInt(angular.element(item).attr('data-index'), 10) === firstIndex) {
4904                                                 return true;
4905                                             }
4906                                         });
4907                                         firstIndex = parseInt(angular.element(elementsThatMatch).attr('data-index'), 10);
4908                                         
4909                                         if (index <= firstIndex && scope.listboxData.filter(isTrue).length > 1) {
4910                                             // Break the selection into 2
4911                                             selectItems(firstIndex + 1, max + 1, undefined); // + 1 needed because selectItems only selects up to MAX
4912                                             selectItems(min, firstIndex, undefined); 
4913                                         } else if (scope.listboxData.filter(isTrue).length == 1){
4914                                             selectItems(min, max, undefined); 
4915                                         } else {
4916                                             selectItems(min + 1, max + 1, undefined);
4917                                         }
4918                                     } else { // clicking down
4919                                         selectItems(min + 1, max + 1, scope.listboxData[min].selected);
4920                                     }
4921                                 } else if (ctrlKeyPressed) {
4922                                     scope.listboxData[index].selected = !scope.listboxData[index].selected;
4923                                 } else {
4924                                     selectItems(0, scope.listboxData.length, false);
4925                                     scope.listboxData[index].selected = !scope.listboxData[index].selected;
4926                                 }
4927                             } else {
4928                                 selectItems(0, scope.listboxData.length, false);
4929                                 scope.listboxData[index].selected = !scope.listboxData[index].selected;
4930                             }
4931                             currentIndexSet.elementIndex = index;
4932                             currentIndexSet.listboxDataIndex = index;
4933                             scope.currentIndex = currentIndexSet.listboxDataIndex;
4934                             if (!scope.$$phase) {
4935                                 scope.$apply();
4936                             }
4937                             focusOnElement(index);
4938                         });
4939                     }
4940                 };
4941             }]);
4942 /**
4943  * @ngdoc directive
4944  * @name Videos, audio & animation.att:loaderAnimation
4945  *
4946  * @description
4947  *  <file src="src/loaderAnimation/docs/readme.md" />
4948  *
4949  * @usage
4950  *   <!-- Below demo js shows-->
4951  *   Angular library uses Global.css's icon-primary-spinner.
4952  *
4953  * @example
4954  *  <section id="code">
4955         <example module="b2b.att">
4956             <file src="src/loaderAnimation/docs/demo.html" />
4957             <file src="src/loaderAnimation/docs/demo.js" />
4958        </example>
4959     </section>
4960  *
4961  */
4962 angular.module('b2b.att.loaderAnimation', [])
4963     .constant('b2bSpinnerConfig', {
4964         loadingText: 'Loading...',
4965         startEvent: 'startButtonSpinner',
4966         stopEvent: 'stopButtonSpinner'
4967     })
4968     .constant("progressTrackerConfig", {
4969         loadingText: 'Loading...',
4970         minDuration: "",
4971         activationDelay: "",
4972         minDurationPromise: "",
4973         activationDelayPromise: ""
4974     })
4975
4976 .provider('progressTracker', function () {
4977     this.$get = ['$q', '$timeout', function ($q, $timeout) {
4978         function cancelTimeout(promise) {
4979             if (promise) {
4980                 $timeout.cancel(promise);
4981             }
4982         }
4983         return function ProgressTracker(options) {
4984             //do new if user doesn't
4985             if (!(this instanceof ProgressTracker)) {
4986                 return new ProgressTracker(options);
4987             }
4988
4989             options = options || {};
4990             //Array of promises being tracked
4991             var tracked = [];
4992             var self = this;
4993             //Allow an optional "minimum duration" that the tracker has to stay active for.
4994             var minDuration = options.minDuration;
4995             //Allow a delay that will stop the tracker from activating until that time is reached
4996             var activationDelay = options.activationDelay;
4997             var minDurationPromise;
4998             var activationDelayPromise;
4999             self.active = function () {
5000                 //Even if we have a promise in our tracker, we aren't active until delay is elapsed
5001                 if (activationDelayPromise) {
5002                     return false;
5003                 }
5004                 return tracked.length > 0;
5005             };
5006             self.tracking = function () {
5007                 //Even if we aren't active, we could still have a promise in our tracker
5008                 return tracked.length > 0;
5009             };
5010             self.destroy = self.cancel = function () {
5011                 minDurationPromise = cancelTimeout(minDurationPromise);
5012                 activationDelayPromise = cancelTimeout(activationDelayPromise);
5013                 for (var i = tracked.length - 1; i >= 0; i--) {
5014                     tracked[i].resolve();
5015                 }
5016                 tracked.length = 0;
5017             };
5018             //Create a promise that will make our tracker active until it is resolved.
5019             // @return deferred - our deferred object that is being tracked
5020             self.createPromise = function () {
5021                 var deferred = $q.defer();
5022                 tracked.push(deferred);
5023                 //If the tracker was just inactive and this the first in the list of promises, we reset our delay and minDuration again.
5024                 if (tracked.length === 1) {
5025                     if (activationDelay) {
5026                         activationDelayPromise = $timeout(function () {
5027                             activationDelayPromise = cancelTimeout(activationDelayPromise);
5028                             startMinDuration();
5029                         }, activationDelay);
5030                     } else {
5031                         startMinDuration();
5032                     }
5033                 }
5034                 deferred.promise.then(onDone(false), onDone(true));
5035                 return deferred;
5036
5037                 function startMinDuration() {
5038                     if (minDuration) {
5039                         minDurationPromise = $timeout(angular.noop, minDuration);
5040                     }
5041                 }
5042                 //Create a callback for when this promise is done. It will remove our tracked promise from the array if once minDuration is complete
5043                 function onDone() {
5044                     return function () {
5045                         (minDurationPromise || $q.when()).then(function () {
5046                             var index = tracked.indexOf(deferred);
5047                             tracked.splice(index, 1);
5048                             //If this is the last promise, cleanup the timeouts for activationDelay
5049                             if (tracked.length === 0) {
5050                                 activationDelayPromise = cancelTimeout(activationDelayPromise);
5051                             }
5052                         });
5053                     };
5054                 }
5055             };
5056             self.addPromise = function (promise) {
5057                 
5058 //                we cannot assign then function in other var and then add the resolve and reject 
5059                 var thenFxn = promise && (promise.then || promise.$then || (promise.$promise && promise.$promise.then));                
5060                 if (!thenFxn) {
5061                     throw new Error("progressTracker expects a promise object :: Not found");
5062                 }
5063                 var deferred = self.createPromise();
5064                 //When given promise is done, resolve our created promise
5065                 //Allow $then for angular-resource objects
5066
5067                 promise.then(function (value) {
5068                         deferred.resolve(value);
5069                         return value;
5070                     }, function (value) {
5071                         deferred.reject(value);
5072                         return $q.reject(value);
5073                     }
5074                 );
5075                 return deferred;
5076             };
5077         };
5078     }];
5079 })
5080
5081 .config(['$httpProvider', function ($httpProvider) {
5082     $httpProvider.interceptors.push(['$q', 'progressTracker', function ($q) {
5083         return {
5084             request: function (config) {
5085                 if (config.tracker) {
5086                     if (!angular.isArray(config.tracker)) {
5087                         config.tracker = [config.tracker];
5088                     }
5089                     config.$promiseTrackerDeferred = config.$promiseTrackerDeferred || [];
5090
5091                     angular.forEach(config.tracker, function (tracker) {
5092                         var deferred = tracker.createPromise();
5093                         config.$promiseTrackerDeferred.push(deferred);
5094                     });
5095                 }
5096                 return $q.when(config);
5097             },
5098             response: function (response) {
5099                 if (response.config && response.config.$promiseTrackerDeferred) {
5100                     angular.forEach(response.config.$promiseTrackerDeferred, function (deferred) {
5101                         deferred.resolve(response);
5102                     });
5103                 }
5104                 return $q.when(response);
5105             },
5106             responseError: function (response) {
5107                 if (response.config && response.config.$promiseTrackerDeferred) {
5108                     angular.forEach(response.config.$promiseTrackerDeferred, function (deferred) {
5109                         deferred.reject(response);
5110                     });
5111                 }
5112                 return $q.reject(response);
5113             }
5114         };
5115     }]);
5116 }])
5117
5118 .directive('b2bClickSpin', ['$timeout', '$parse', '$rootScope', 'progressTracker', function ($timeout, $parse, $rootScope, progressTracker) {
5119     return {
5120         restrict: 'A',
5121         link: function (scope, elm, attrs) {
5122             var fn = $parse(attrs.b2bClickSpin);
5123             elm.on('click', function (event) {
5124                 var promise = $timeout(function () {console.log("inside Promise")}, 5000);
5125                 scope.$apply(function () {
5126                     fn(scope, {
5127                         $event: event
5128                     });
5129                 });
5130                 //comment this line if not running unit test
5131                 $rootScope.loadingTracker = progressTracker({
5132                     minDuration: 750
5133                 });
5134                 $rootScope.loadingTracker.addPromise(promise);
5135                 angular.forEach("$routeChangeSuccess $viewContentLoaded $locationChangeSuccess".split(" "), function (event) {
5136                     $rootScope.$on(event, function () {
5137
5138                         $timeout.cancel(promise);
5139                     });
5140                 });
5141             });
5142         }
5143     };
5144 }])
5145
5146 .directive('b2bProgressTracker', ['progressTrackerConfig', function (ptc) {
5147     return {
5148         restrict: 'EA',
5149         replace: true,
5150         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>'
5151     };
5152 }])
5153
5154 .directive('b2bLoadButton', ['b2bSpinnerConfig', '$timeout', function (spinnerConfig, $timeout) {
5155     var spinButton = function (state, element, data) {
5156         
5157         var attr = element.html() ? 'html' : 'val';
5158         state = state + 'Text';
5159         if (state === 'loadingText') {
5160             element[attr](data[state]);
5161             element.attr("disabled",'disabled');
5162             element.addClass('disabled');
5163         } else if (state === 'resetText') {
5164             element[attr](data[state]);
5165             element.removeAttr("disabled");
5166             element.removeClass('disabled');
5167         }
5168     };
5169
5170     return {
5171         restrict: 'A',
5172         replace: false,
5173         scope: {
5174             promise: '=promise',
5175             startEvent: '@startEvent',
5176             stopEvent: '@stopEvent'
5177         },
5178         link: function (scope, element, attr) {
5179             var validAttr = element.html() ? 'html' : 'val';
5180             var data = {
5181                 loadingText: '',
5182                 resetText: ''
5183             };
5184
5185             var updateLoadingText = function (val) {
5186                 var loadingText = val;
5187                 if (!angular.isDefined(loadingText) || loadingText === "") {
5188                     loadingText = spinnerConfig.loadingText;
5189                 }
5190                 data.loadingText = validAttr === 'html' ? "<i class=\"icon-primary-spinner small\"></i>" + loadingText : loadingText;
5191             };
5192             var updateResetText = function (val) {
5193                 data.resetText = val;
5194             };
5195
5196             attr.$observe('b2bLoadButton', function (val) {
5197                 updateLoadingText(val);
5198             });
5199             $timeout(function () {
5200                 updateResetText(element[validAttr]());
5201             }, 500);
5202
5203             if (!angular.isDefined(scope.startEvent) || scope.startEvent === "") {
5204                 scope.startEvent = spinnerConfig.startEvent;
5205             }
5206
5207             if (!angular.isDefined(scope.stopEvent) || scope.stopEvent === "") {
5208                 scope.stopEvent = spinnerConfig.stopEvent;
5209             }
5210
5211             scope.$watch('promise', function () {
5212                 if (angular.isDefined(scope.promise) && angular.isFunction(scope.promise.then)) {
5213                     spinButton('loading', element, data);
5214                     scope.promise.then(function () {
5215                         spinButton('reset', element, data);
5216                     }, function () {
5217                         spinButton('reset', element, data);
5218                     });
5219                 }
5220             });
5221
5222             scope.$on(scope.startEvent, function () {
5223                 spinButton('loading', element, data);
5224                 scope.$on(scope.stopEvent, function () {
5225                     spinButton('reset', element, data);
5226                 });
5227             });
5228         }
5229     };
5230 }])
5231
5232
5233 ;
5234  /**
5235  * @ngdoc directive
5236  * @name Misc.att:messageWrapper
5237  * @scope
5238  * @param {boolean} trigger - A boolean that triggers directive to switch focus
5239  * @param {integer} delay  - Extra delay added to trigger code to allow for DOM to be ready. Default is 10ms.
5240  * @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)
5241  * @param {string} trapFocus - Attribute-based API to trap focus within the message. This should be enabled by default on all toast messages.
5242  * @description
5243  *  <file src="src/messageWrapper/docs/readme.md" />
5244  * @usage
5245  * <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>
5246  *
5247  * @example
5248  *  <section id="code">   
5249  <b>HTML + AngularJS</b>
5250  <example module="b2b.att">
5251  <file src="src/messageWrapper/docs/demo.html" />
5252  <file src="src/messageWrapper/docs/demo.js" />
5253  </example>
5254  </section>
5255  *
5256  */
5257 angular.module('b2b.att.messageWrapper', ['b2b.att.utilities'])
5258 .directive('b2bMessageWrapper', ['b2bDOMHelper', '$compile', '$timeout', '$log', function(b2bDOMHelper, $compile, $timeout, $log) {
5259   return {
5260     restrict: 'AE',
5261     scope: {
5262       trigger: '=',
5263       delay: '=?'
5264     },
5265     transclude: true,
5266     replace: true,
5267     template: '<div ng-transclude></div>',
5268     link: function(scope, elem, attrs) {
5269       scope.delay = scope.delay || 10;
5270
5271       if (attrs.trapFocus != undefined && !elem.children().eq(0).attr('b2b-trap-focus-inside-element')) {
5272         // Append b2bTrapFocusInsideElement onto first child and recompile
5273         elem.children().eq(0).attr('b2b-trap-focus-inside-element', 'false');
5274         elem.children().eq(0).attr('trigger', scope.trigger);
5275         $compile(elem.contents())(scope);
5276       }
5277
5278       var firstElement = undefined,
5279           launchingElement = undefined;
5280       
5281       scope.$watch('trigger', function(oldVal, newVal) {
5282         if (oldVal === newVal) return;
5283         if (!angular.isDefined(launchingElement)) {
5284           launchingElement = document.activeElement;
5285         }
5286         $timeout(function() {
5287           if (scope.trigger) {
5288
5289             if (attrs.noFocus === true || attrs.noFocus === "") {
5290               elem.children()[0].focus();
5291             } else {
5292               firstElement = b2bDOMHelper.firstTabableElement(elem);
5293
5294               if (angular.isDefined(firstElement)) {
5295                 firstElement.focus();
5296               }
5297             }
5298             
5299           } else {
5300             if (angular.isDefined(launchingElement) && launchingElement.nodeName !== 'BODY') {
5301               if (launchingElement === document.activeElement) {
5302                 return;
5303               }
5304
5305               if (b2bDOMHelper.isInDOM(launchingElement) && b2bDOMHelper.isTabable(launchingElement)) {
5306                   // At this point, launchingElement is still a valid element, but focus will fail and 
5307                   // activeElement will become body, hence we want to apply custom logic and find previousElement
5308                   var prevLaunchingElement = launchingElement;
5309                   launchingElement.focus();
5310
5311                   if (document.activeElement !== launchingElement || document.activeElement.nodeName === 'BODY') {
5312                     launchingElement = b2bDOMHelper.previousElement(angular.element(prevLaunchingElement), true);
5313                     launchingElement.focus();
5314                   }
5315               } else {
5316                 launchingElement = b2bDOMHelper.previousElement(launchingElement, true);
5317                 launchingElement.focus();
5318               }
5319             }
5320           }
5321         }, scope.delay); 
5322       });
5323     }
5324   };
5325 }]);
5326 /**
5327  * @ngdoc directive
5328  * @name Messages, modals & alerts.att:modalsAndAlerts
5329  *
5330  * @description
5331  *  <file src="src/modalsAndAlerts/docs/readme.md" />
5332  *
5333  * @usage
5334  *  <button class="btn" b2b-modal="b2bTemplate/modalsAndAlerts/demo_modal.html" modal-ok="ok()" modal-cancel="cancel()">Launch demo modal</button>
5335  *
5336  * @example
5337  *  <section id="code">
5338      <example module="b2b.att">
5339       <file src="src/modalsAndAlerts/docs/demo.html" />
5340       <file src="src/modalsAndAlerts/docs/demo.js" />
5341      </example>
5342     </section>
5343  *
5344  */
5345 angular.module('b2b.att.modalsAndAlerts', ['b2b.att.position', 'b2b.att.transition', 'b2b.att.utilities'])
5346
5347 /**
5348  * A helper, internal data structure that acts as a map but also allows getting / removing
5349  * elements in the LIFO order
5350  */
5351 .factory('$$stackedMap', function () {
5352     return {
5353         createNew: function () {
5354             var stack = [];
5355
5356             return {
5357                 add: function (key, value) {
5358                     stack.push({
5359                         key: key,
5360                         value: value
5361                     });
5362                 },
5363                 get: function (key) {
5364                     for (var i = 0; i < stack.length; i++) {
5365                         if (key === stack[i].key) {
5366                             return stack[i];
5367                         }
5368                     }
5369                 },
5370                 keys: function () {
5371                     var keys = [];
5372                     for (var i = 0; i < stack.length; i++) {
5373                         keys.push(stack[i].key);
5374                     }
5375                     return keys;
5376                 },
5377                 top: function () {
5378                     return stack[stack.length - 1];
5379                 },
5380                 remove: function (key) {
5381                     var idx = -1;
5382                     for (var i = 0; i < stack.length; i++) {
5383                         if (key === stack[i].key) {
5384                             idx = i;
5385                             break;
5386                         }
5387                     }
5388                     return stack.splice(idx, 1)[0];
5389                 },
5390                 removeTop: function () {
5391                     return stack.splice(stack.length - 1, 1)[0];
5392                 },
5393                 length: function () {
5394                     return stack.length;
5395                 }
5396             };
5397         }
5398     };
5399 }).factory('trapFocusInElement', ['$document', '$isElement', 'DOMHelper', 'keymap', function ($document, $isElement, DOMHelper, keymap) {
5400     var elementStack = [];
5401     var stackHead = undefined;
5402     var firstTabableElement, lastTabableElement;
5403
5404     var trapKeyboardFocusInFirstElement = function (e) {
5405         if (!e.keyCode) {
5406             e.keyCode = e.which;
5407         }
5408
5409         if (e.shiftKey === true && e.keyCode === keymap.KEY.TAB) {
5410             lastTabableElement[0].focus();
5411             e.preventDefault(e);
5412             e.stopPropagation(e);
5413         }
5414
5415     };
5416
5417     var trapKeyboardFocusInLastElement = function (e) {
5418         if (!e.keyCode) {
5419             e.keyCode = e.which;
5420         }
5421
5422         if (e.shiftKey === false && e.keyCode === keymap.KEY.TAB) {
5423             firstTabableElement[0].focus();
5424             e.preventDefault(e);
5425             e.stopPropagation(e);
5426         }
5427     };
5428     
5429     var trapFocusInElement = function (flag, firstTabableElementParam, lastTabableElementParam) {
5430         var bodyElements = $document.find('body').children();
5431
5432         firstTabableElement = firstTabableElementParam ? firstTabableElementParam : angular.element(DOMHelper.firstTabableElement(stackHead));
5433         lastTabableElement = lastTabableElementParam ? lastTabableElementParam : angular.element(DOMHelper.lastTabableElement(stackHead));
5434
5435         if (flag) {
5436             for (var i = 0; i < bodyElements.length; i++) {
5437                 if (bodyElements[i] !== stackHead[0]) {
5438                     bodyElements.eq(i).attr('aria-hidden', true);
5439                 }
5440             }
5441             firstTabableElement.bind('keydown', trapKeyboardFocusInFirstElement);
5442             lastTabableElement.bind('keydown', trapKeyboardFocusInLastElement);
5443         } else {
5444             for (var j = 0; j < bodyElements.length; j++) {
5445                 if (bodyElements[j] !== stackHead[0]) {
5446                     bodyElements.eq(j).removeAttr('aria-hidden');
5447                 }
5448             }
5449             firstTabableElement.unbind('keydown', trapKeyboardFocusInFirstElement);
5450             lastTabableElement.unbind('keydown', trapKeyboardFocusInLastElement);
5451         }
5452     };
5453     var toggleTrapFocusInElement = function (flag, element) {
5454         if (angular.isDefined(flag) && angular.isDefined(element)) {
5455             if (angular.isUndefined(stackHead)) {
5456                 stackHead = element;
5457                 trapFocusInElement(flag);
5458             } else {
5459                 if (flag) {
5460                     trapFocusInElement(false);
5461                     elementStack.push(stackHead);
5462                     stackHead = element;
5463                     trapFocusInElement(true);
5464                 } else {
5465                     if (stackHead.prop('$$hashKey') === element.prop('$$hashKey')) {
5466                         trapFocusInElement(false);
5467                         stackHead = elementStack.pop();
5468                         if (angular.isDefined(stackHead)) {
5469                             trapFocusInElement(true);
5470                         }
5471                     }
5472                 }
5473             }
5474         }else {
5475             if (angular.isDefined(stackHead)) {
5476                 trapFocusInElement(false, firstTabableElement, lastTabableElement);
5477                 trapFocusInElement(true);
5478             }
5479         }
5480     };
5481
5482     return toggleTrapFocusInElement;
5483 }])
5484
5485 /**
5486  * A helper directive for the $modal service. It creates a backdrop element.
5487  */
5488 .directive('b2bModalBackdrop', ['$modalStack', '$timeout', function ($modalStack, $timeout) {
5489     return {
5490         restrict: 'EA',
5491         replace: true,
5492         templateUrl: 'b2bTemplate/modalsAndAlerts/b2b-backdrop.html',
5493         link: function (scope, element, attrs) {
5494             scope.close = function (evt) {
5495                 var modal = $modalStack.getTop();
5496                 if (modal && modal.value.backdrop && modal.value.backdrop !== 'static') {
5497                     evt.preventDefault();
5498                     evt.stopPropagation();
5499                     $modalStack.dismiss(modal.key, 'backdrop click');
5500                 }
5501             };
5502         }
5503     };
5504 }])
5505
5506 .directive('b2bModalWindow', ['$timeout', 'windowOrientation', '$window', function ($timeout, windowOrientation, $window) {
5507     return {
5508         restrict: 'EA',
5509         scope: {
5510             index: '@'
5511         },
5512         replace: true,
5513         transclude: true,
5514         templateUrl: 'b2bTemplate/modalsAndAlerts/b2b-window.html',
5515         controller: ['$scope', '$element', '$attrs', function (scope, element, attrs) {
5516             scope.windowClass = attrs.windowClass || '';
5517             scope.sizeClass = attrs.sizeClass || '';
5518             scope.isNotifDialog = false;
5519
5520             this.setTitle = function (title) {
5521                 scope.title = title;
5522             };
5523             this.setContent = function (content) {
5524                 scope.content = content;
5525                 scope.isNotifDialog = true;
5526             };
5527             this.isDockedModal = scope.windowClass.indexOf('modal-docked') > -1;
5528         }],
5529         link: function (scope, element, attrs, ctrl) {
5530             if (ctrl.isDockedModal) {
5531                 scope.isModalLandscape = false;
5532
5533                 var window = angular.element($window);
5534                 scope.updateCss = function () {
5535                     if (windowOrientation.isPotrait()) { // Potrait Mode
5536                         scope.isModalLandscape = false;
5537                     } else if (windowOrientation.isLandscape()) { // Landscape Mode
5538                         scope.isModalLandscape = true;
5539                     }
5540                 };
5541
5542                 $timeout(function () {
5543                     scope.updateCss();
5544                     scope.$apply();
5545                 }, 100);
5546                 window.bind('orientationchange', function () {
5547                     scope.updateCss();
5548                     scope.$apply();
5549                 });
5550                 window.bind('resize', function () {
5551                     scope.updateCss();
5552                     scope.$apply();
5553                 });
5554             }else {
5555                 angular.element(element[0].querySelectorAll(".awd-select-list")).css({
5556                     "max-height": "200px"
5557                 });
5558             }
5559
5560             var isIE = /msie|trident/i.test(navigator.userAgent);
5561             if (isIE) {
5562                 if(angular.element(element[0].querySelector('.corner-button button.close')).length > 0){
5563                     angular.element(element[0].querySelector('.corner-button button.close')).bind('focus', function () {
5564                        angular.element(element[0].querySelector('.b2b-modal-header'))[0].scrollLeft = 0;
5565                        angular.element(element[0].querySelector('.b2b-modal-header'))[0].scrollTop = 0;
5566                     });
5567                 }
5568             }
5569             
5570         }
5571     };
5572 }])
5573
5574 .directive('b2bModalTitle', [function () {
5575     return {
5576         restrict: 'A',
5577         require: '^b2bModalWindow',
5578         link: function (scope, elem, attr, ctrl) {
5579             ctrl.setTitle(attr.id);
5580         }
5581     };
5582 }])
5583
5584 .directive('b2bModalContent', [function () {
5585     return {
5586         restrict: 'A',
5587         require: '^b2bModalWindow',
5588         link: function (scope, elem, attr, ctrl) {
5589             ctrl.setContent(attr.id);
5590         }
5591     };
5592 }])
5593
5594
5595 .directive('b2bModalBody', ['$timeout', '$position', '$document', '$window', 'windowOrientation', 'b2bAwdBreakpoints', function ($timeout, $position, $document, $window, windowOrientation, b2bAwdBreakpoints) {
5596     return {
5597         restrict: 'AC',
5598         scope: {
5599             index: '@'
5600         },
5601         require: '^b2bModalWindow',
5602         link: function (scope, element, attrs, ctrl) {
5603             var window = angular.element($window);
5604             var body = $document.find('body').eq(0);
5605             scope.setModalHeight = function () {
5606                 var modalHeaderHeight, modalFooterHeight, modalBodyHeight, windowHeight, windowWidth, modalHeight;
5607                 modalHeaderHeight = 0;
5608                 modalFooterHeight = 0;
5609                 windowHeight = $window.innerHeight;
5610                 windowWidth = $window.innerWidth;
5611                 body.css({
5612                     'height': windowHeight + 'px'
5613                 });
5614
5615                 if (ctrl.isDockedModal) {
5616                     var modalElements = element.parent().children();
5617                     for (var i = 0; i < modalElements.length; i++) {
5618                         if (modalElements.eq(i).hasClass('b2b-modal-header')) {
5619                             modalHeaderHeight = $position.position(modalElements.eq(i)).height;
5620                         } else if (modalElements.eq(i).hasClass('b2b-modal-footer')) {
5621                             modalFooterHeight = $position.position(modalElements.eq(i)).height;
5622                         }
5623                     }
5624
5625                     modalHeight = $position.position(element.parent()).height;
5626
5627                     modalBodyHeight = modalHeight - (modalHeaderHeight + modalFooterHeight) + 'px';
5628
5629                     if (windowOrientation.isPotrait()) { // Potrait Mode
5630                         element.removeAttr('style').css({
5631                             height: modalBodyHeight
5632                         });
5633                     } else if (windowOrientation.isLandscape() && windowWidth < b2bAwdBreakpoints.breakpoints.mobile.max) { // Landscape Mode Mobile
5634                         element.removeAttr('style');
5635                     } else if (windowOrientation.isLandscape() && windowWidth >= b2bAwdBreakpoints.breakpoints.mobile.max) { // Landscape Mode Non-Mobile
5636                         element.removeAttr('style').css({
5637                             height: modalBodyHeight
5638                         });
5639                     }
5640                 }
5641             };
5642
5643             $timeout(function () {
5644                 scope.setModalHeight();
5645                 scope.$apply();
5646             }, 100);
5647             window.bind('orientationchange', function () {
5648                 scope.setModalHeight();
5649                 scope.$apply();
5650             });
5651             window.bind('resize', function () {
5652                 scope.setModalHeight();
5653                 scope.$apply();
5654             });
5655         }
5656     };
5657 }])
5658
5659 .directive('b2bModalFooter', ['windowOrientation', '$window', function (windowOrientation, $window) {
5660     return {
5661         restrict: 'AC',
5662         scope: {
5663             index: '@'
5664         },
5665         link: function (scope, element, attrs) {
5666
5667         }
5668     };
5669 }])
5670
5671 .factory('$modalStack', ['$document', '$compile', '$rootScope', '$$stackedMap', '$log', '$timeout', 'trapFocusInElement', function ($document, $compile, $rootScope, $$stackedMap, $log, $timeout, trapFocusInElement) {
5672     var backdropjqLiteEl, backdropDomEl;
5673     var backdropScope = $rootScope.$new(true);
5674     var body = $document.find('body').eq(0);
5675     var html = $document.find('html').eq(0);
5676     var openedWindows = $$stackedMap.createNew();
5677     var $modalStack = {};
5678
5679     function backdropIndex() {
5680         var topBackdropIndex = -1;
5681         var opened = openedWindows.keys();
5682         for (var i = 0; i < opened.length; i++) {
5683             if (openedWindows.get(opened[i]).value.backdrop) {
5684                 topBackdropIndex = i;
5685             }
5686         }
5687         return topBackdropIndex;
5688     }
5689
5690     $rootScope.$watch(backdropIndex, function (newBackdropIndex) {
5691         backdropScope.index = newBackdropIndex;
5692     });
5693
5694     function removeModalWindow(modalInstance) {
5695         //background scroll fix
5696         html.removeAttr('style');
5697         body.removeAttr('style');
5698         body.removeClass('styled-by-modal');
5699
5700         var modalWindow = openedWindows.get(modalInstance).value;
5701         trapFocusInElement(false, modalWindow.modalDomEl);
5702
5703         //clean up the stack
5704         openedWindows.remove(modalInstance);
5705
5706         //remove window DOM element
5707         modalWindow.modalDomEl.remove();
5708
5709         //remove backdrop if no longer needed
5710         if (backdropDomEl && backdropIndex() === -1) {
5711             backdropDomEl.remove();
5712             backdropDomEl = undefined;
5713         }
5714
5715         //destroy scope
5716         modalWindow.modalScope.$destroy();
5717     }
5718
5719     $document.bind('keydown', function (evt) {
5720         var modal;
5721
5722         if (evt.which === 27) {
5723             modal = openedWindows.top();
5724             if (modal && modal.value.keyboard) {
5725                 $rootScope.$apply(function () {
5726                     $modalStack.dismiss(modal.key);
5727                 });
5728             }
5729         }
5730     });
5731
5732     $modalStack.open = function (modalInstance, modal) {
5733
5734         openedWindows.add(modalInstance, {
5735             deferred: modal.deferred,
5736             modalScope: modal.scope,
5737             backdrop: modal.backdrop,
5738             keyboard: modal.keyboard
5739         });
5740
5741         var angularDomEl = angular.element('<div b2b-modal-window></div>');
5742         angularDomEl.attr('window-class', modal.windowClass);
5743         angularDomEl.attr('size-class', modal.sizeClass);
5744         angularDomEl.attr('index', openedWindows.length() - 1);
5745         angularDomEl.html(modal.content);
5746
5747         var modalDomEl = $compile(angularDomEl)(modal.scope);
5748         openedWindows.top().value.modalDomEl = modalDomEl;
5749         //background page scroll fix
5750         html.css({
5751             'overflow-y': 'hidden'
5752         });
5753         body.css({
5754             'overflow-y': 'hidden',
5755             'width': '100%',
5756             'height': window.innerHeight + 'px'
5757         });
5758         body.addClass('styled-by-modal');
5759         body.append(modalDomEl);
5760
5761         if (backdropIndex() >= 0 && !backdropDomEl) {
5762             backdropjqLiteEl = angular.element('<div b2b-modal-backdrop></div>');
5763             backdropDomEl = $compile(backdropjqLiteEl)(backdropScope);
5764             body.append(backdropDomEl);
5765         }
5766
5767         $timeout(function () {
5768
5769             if (modal.scope.$$childHead.isNotifDialog) {
5770                 angular.element(modalDomEl).find('button')[0].focus();
5771             } else {
5772                 angular.element(modalDomEl)[0].focus();
5773             }
5774             trapFocusInElement(true, angular.element(modalDomEl).eq(0));
5775         }, 200);
5776     };
5777
5778     $modalStack.close = function (modalInstance, result) {
5779         var modal = openedWindows.get(modalInstance);
5780         if (modal) {
5781             modal.value.deferred.resolve(result);
5782             removeModalWindow(modalInstance);
5783         }
5784     };
5785
5786     $modalStack.dismiss = function (modalInstance, reason) {
5787         var modalWindow = openedWindows.get(modalInstance).value;
5788         if (modalWindow) {
5789             modalWindow.deferred.reject(reason);
5790             removeModalWindow(modalInstance);
5791         }
5792     };
5793
5794     $modalStack.getTop = function () {
5795         return openedWindows.top();
5796     };
5797
5798     return $modalStack;
5799 }])
5800
5801 .provider('$modal', function () {
5802     var $modalProvider = {
5803         options: {
5804             backdrop: true, //can be also false or 'static'
5805             keyboard: true
5806         },
5807         $get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack', function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) {
5808             var $modal = {};
5809
5810             function getTemplatePromise(options) {
5811                 return options.template ? $q.when(options.template) :
5812                     $http.get(options.templateUrl, {
5813                         cache: $templateCache
5814                     }).then(function (result) {
5815                         return result.data;
5816                     });
5817             }
5818
5819             function getResolvePromises(resolves) {
5820                 var promisesArr = [];
5821                 angular.forEach(resolves, function (value, key) {
5822                     if (angular.isFunction(value) || angular.isArray(value)) {
5823                         promisesArr.push($q.when($injector.invoke(value)));
5824                     }
5825                 });
5826                 return promisesArr;
5827             }
5828
5829             $modal.open = function (modalOptions) {
5830
5831                 var modalResultDeferred = $q.defer();
5832                 var modalOpenedDeferred = $q.defer();
5833                 //prepare an instance of a modal to be injected into controllers and returned to a caller
5834                 var modalInstance = {
5835                     result: modalResultDeferred.promise,
5836                     opened: modalOpenedDeferred.promise,
5837                     close: function (result) {
5838                         $modalStack.close(modalInstance, result);
5839                     },
5840                     dismiss: function (reason) {
5841                         $modalStack.dismiss(modalInstance, reason);
5842                     }
5843                 };
5844
5845                 //merge and clean up options
5846                 modalOptions = angular.extend({}, $modalProvider.options, modalOptions);
5847                 modalOptions.resolve = modalOptions.resolve || {};
5848
5849                 //verify options
5850                 if (!modalOptions.template && !modalOptions.templateUrl) {
5851                     throw new Error('One of template or templateUrl options is required.');
5852                 }
5853
5854                 var templateAndResolvePromise =
5855                     $q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve)));
5856
5857
5858                 templateAndResolvePromise.then(function resolveSuccess(tplAndVars) {
5859
5860                     var modalScope = (modalOptions.scope || $rootScope).$new();
5861                     modalScope.$close = modalInstance.close;
5862                     modalScope.$dismiss = modalInstance.dismiss;
5863
5864                     var ctrlInstance, ctrlLocals = {};
5865                     var resolveIter = 1;
5866
5867                     //controllers
5868                     if (modalOptions.controller) {
5869                         ctrlLocals.$scope = modalScope;
5870                         ctrlLocals.$modalInstance = modalInstance;
5871                         angular.forEach(modalOptions.resolve, function (value, key) {
5872                             ctrlLocals[key] = tplAndVars[resolveIter++];
5873                         });
5874
5875                         ctrlInstance = $controller(modalOptions.controller, ctrlLocals);
5876                     }
5877
5878                     $modalStack.open(modalInstance, {
5879                         scope: modalScope,
5880                         deferred: modalResultDeferred,
5881                         content: tplAndVars[0],
5882                         backdrop: modalOptions.backdrop,
5883                         keyboard: modalOptions.keyboard,
5884                         windowClass: modalOptions.windowClass,
5885                         sizeClass: modalOptions.sizeClass
5886                     });
5887
5888                 }, function resolveError(reason) {
5889                     modalResultDeferred.reject(reason);
5890                 });
5891
5892                 templateAndResolvePromise.then(function () {
5893                     modalOpenedDeferred.resolve(true);
5894                 }, function () {
5895                     modalOpenedDeferred.reject(false);
5896                 });
5897
5898                 return modalInstance;
5899             };
5900
5901             return $modal;
5902         }]
5903     };
5904
5905     return $modalProvider;
5906 })
5907
5908 .directive("b2bModal", ["$modal", "$log", '$scrollTo', function ($modal, $log, $scrollTo) {
5909     return {
5910         restrict: 'A',
5911         scope: {
5912             b2bModal: '@',
5913             modalController: '@',
5914             modalOk: '&',
5915             modalCancel: '&',
5916             windowClass: '@',
5917             sizeClass: '@'
5918         },
5919         link: function (scope, elm, attr) {
5920             elm.bind('click', function (ev) {
5921                 var currentPosition = ev.pageY - ev.clientY;
5922                 ev.preventDefault();
5923                 if (angular.isDefined(elm.attr("href")) && elm.attr("href") !== "") {
5924                     scope.b2bModal = elm.attr("href");
5925                 }
5926                 $modal.open({
5927                     templateUrl: scope.b2bModal,
5928                     controller: scope.modalController,
5929                     windowClass: scope.windowClass,
5930                     sizeClass: scope.sizeClass
5931                 }).result.then(function (value) {
5932                     scope.modalOk({
5933                         value: value
5934                     });
5935                     elm[0].focus();
5936                 }, function (value) {
5937                     scope.modalCancel({
5938                         value: value
5939                     });
5940                     elm[0].focus();
5941                 });
5942             });
5943         }
5944     };
5945 }])
5946
5947 .directive("utilityFilter", ["$modal", "$log", '$scrollTo', function ($modal, $log, $scrollTo) {
5948     return {
5949         restrict: 'EA',
5950         scope: {
5951             utilityFilter: '@'
5952         },
5953         require: 'ngModel',
5954         templateUrl: 'b2bTemplate/modal/u-filter.html',
5955         link: function (scope, element, attribute, ctrl) {
5956             //controller to be passed to $modal service
5957             scope.options = angular.copy(scope.$parent.$eval(attribute.ngModel));
5958             scope.$parent.$watch(attribute.ngModel, function (newVal, oldVal) {
5959                 if (newVal !== oldVal) {
5960                     scope.options = newVal;
5961                 }
5962             });
5963             var modalCtrl = function ($scope, options) {
5964                 $scope.options = angular.copy(options);
5965             };
5966
5967             if (angular.isDefined(scope.utilityFilter)) {
5968                 scope.templateUrl = scope.utilityFilter;
5969             } else {
5970                 scope.templateUrl = 'b2bTemplate/modal/u-filter-window.html';
5971             }
5972             element.bind('click', function (ev) {
5973                 var currentPosition = ev.pageY - ev.clientY;
5974                 $modal.open({
5975                     templateUrl: scope.templateUrl,
5976                     controller: modalCtrl,
5977                     resolve: {
5978                         options: function () {
5979                             return scope.options;
5980                         }
5981                     }
5982                 }).result.then(function (value) {
5983                     ctrl.$setViewValue(value);
5984                     element[0].focus();
5985                     $scrollTo(0, currentPosition, 0);
5986                 }, function () {
5987                     element[0].focus();
5988                     $scrollTo(0, currentPosition, 0);
5989                 });
5990             });
5991         }
5992     };
5993 }]);
5994 /**
5995  * @ngdoc directive
5996  * @name Forms.att:monthSelector
5997  *
5998  * @description
5999  *  <file src="src/monthSelector/docs/readme.md" />
6000  *
6001  * @usage
6002  * <div b2b-monthpicker ng-model="dt" min="minDate" max="maxDate" mode="monthpicker"></div>
6003     
6004  * @example
6005  *  <section id="code">
6006         <example module="b2b.att">
6007             <file src="src/monthSelector/docs/demo.html" />
6008             <file src="src/monthSelector/docs/demo.js" />
6009         </example>
6010     </section>
6011  *
6012  */
6013 angular.module('b2b.att.monthSelector', ['b2b.att.position', 'b2b.att.utilities'])
6014
6015 .constant('b2bMonthpickerConfig', {
6016     dateFormat: 'MM/dd/yyyy',
6017     dayFormat: 'd',
6018     monthFormat: 'MMMM',
6019     yearFormat: 'yyyy',
6020     dayHeaderFormat: 'EEEE',
6021     dayTitleFormat: 'MMMM yyyy',
6022     disableWeekend: false,
6023     disableSunday: false,
6024     disableDates: null,
6025     onSelectClose: null,
6026     startingDay: 0,
6027     minDate: null,
6028     maxDate: null,
6029     dueDate: null,
6030     fromDate: null,
6031     legendIcon: null,
6032     legendMessage: null,
6033     calendarDisabled: false,
6034     collapseWait: 0,
6035     orientation: 'left',
6036     inline: false,
6037     mode:0,
6038     helperText: 'The date you selected is $date. Double tap to open calendar. Select a date to close the calendar.',
6039     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.',
6040     MonthpickerEvalAttributes: ['dateFormat', 'dayFormat', 'monthFormat', 'yearFormat', 'dayHeaderFormat', 'dayTitleFormat', 'disableWeekend', 'disableSunday', 'startingDay', 'collapseWait', 'orientation','mode','id'],
6041     MonthpickerWatchAttributes: ['min', 'max', 'due', 'from', 'legendIcon', 'legendMessage', 'ngDisabled'],
6042     MonthpickerFunctionAttributes: ['disableDates', 'onSelectClose']
6043 })
6044
6045 .factory('b2bMonthpickerService', ['b2bMonthpickerConfig', 'dateFilter', function (b2bMonthpickerConfig, dateFilter) {
6046     var setAttributes = function (attr, elem) {
6047         if (angular.isDefined(attr) && attr !== null && angular.isDefined(elem) && elem !== null) {
6048             var attributes = b2bMonthpickerConfig.MonthpickerEvalAttributes.concat(b2bMonthpickerConfig.MonthpickerWatchAttributes, b2bMonthpickerConfig.MonthpickerFunctionAttributes);
6049             for (var key in attr) {
6050                 var val = attr[key];
6051                 if (attributes.indexOf(key) !== -1 && angular.isDefined(val)) {
6052                     elem.attr(key.toSnakeCase(), key);
6053                 }
6054             }
6055         }
6056     };
6057
6058     var bindScope = function (attr, scope) {
6059         if (angular.isDefined(attr) && attr !== null && angular.isDefined(scope) && scope !== null) {
6060             var evalFunction = function (key, val) {
6061                 scope[key] = scope.$parent.$eval(val);
6062             };
6063
6064             var watchFunction = function (key, val) {
6065                 scope.$parent.$watch(val, function (value) {
6066                     scope[key] = value;
6067                 });
6068                 scope.$watch(key, function (value) {
6069                     scope.$parent[val] = value;
6070                 });
6071             };
6072
6073             var evalAttributes = b2bMonthpickerConfig.MonthpickerEvalAttributes;
6074             var watchAttributes = b2bMonthpickerConfig.MonthpickerWatchAttributes;
6075             for (var key in attr) {
6076                 var val = attr[key];
6077                 if (evalAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {
6078                     evalFunction(key, val);
6079                 } else if (watchAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {
6080                     watchFunction(key, val);
6081                 }
6082             }
6083         }
6084     };
6085
6086     return {
6087         setAttributes: setAttributes,
6088         bindScope: bindScope
6089     };
6090 }])
6091
6092 .controller('b2bMonthpickerController', ['$scope', '$attrs', 'dateFilter', '$element', '$position', 'b2bMonthpickerConfig', function ($scope, $attrs, dateFilter, $element, $position, dtConfig) {
6093     var format = {
6094             date: getValue($attrs.dateFormat, dtConfig.dateFormat),
6095             day: getValue($attrs.dayFormat, dtConfig.dayFormat),
6096             month: getValue($attrs.monthFormat, dtConfig.monthFormat),
6097             year: getValue($attrs.yearFormat, dtConfig.yearFormat),
6098             dayHeader: getValue($attrs.dayHeaderFormat, dtConfig.dayHeaderFormat),
6099             dayTitle: getValue($attrs.dayTitleFormat, dtConfig.dayTitleFormat),
6100             disableWeekend: getValue($attrs.disableWeekend, dtConfig.disableWeekend),
6101             disableSunday: getValue($attrs.disableSunday, dtConfig.disableSunday),
6102             disableDates: getValue($attrs.disableDates, dtConfig.disableDates)
6103         },
6104         startingDay = getValue($attrs.startingDay, dtConfig.startingDay);
6105
6106     $scope.minDate = dtConfig.minDate ? $scope.resetTime(dtConfig.minDate) : null;
6107     $scope.maxDate = dtConfig.maxDate ? $scope.resetTime(dtConfig.maxDate) : null;
6108     $scope.dueDate = dtConfig.dueDate ? $scope.resetTime(dtConfig.dueDate) : null;
6109     $scope.fromDate = dtConfig.fromDate ? $scope.resetTime(dtConfig.fromDate) : null;
6110     $scope.legendIcon = dtConfig.legendIcon ? dtConfig.legendIcon : null;
6111     $scope.legendMessage = dtConfig.legendMessage ? dtConfig.legendMessage : null;
6112     $scope.ngDisabled = dtConfig.calendarDisabled ? dtConfig.calendarDisabled : null;
6113     $scope.collapseWait = getValue($attrs.collapseWait, dtConfig.collapseWait);
6114     $scope.orientation = getValue($attrs.orientation, dtConfig.orientation);
6115     $scope.onSelectClose = getValue($attrs.onSelectClose, dtConfig.onSelectClose);
6116     $scope.mode = getValue($attrs.mode, dtConfig.mode);
6117     
6118     $scope.inline = $attrs.inline === 'true' ? true : dtConfig.inline;
6119
6120     function getValue(value, defaultValue) {
6121         return angular.isDefined(value) ? $scope.$parent.$eval(value) : defaultValue;
6122     }
6123
6124     function getDaysInMonth(year, month) {
6125         return new Date(year, month, 0).getDate();
6126     }
6127
6128     function getDates(startDate, n) {
6129         var dates = new Array(n);
6130         var current = startDate,
6131             i = 0;
6132         while (i < n) {
6133             dates[i++] = new Date(current);
6134             current.setDate(current.getDate() + 1);
6135         }
6136         return dates;
6137     }
6138
6139     this.updatePosition = function (b2bMonthpickerPopupTemplate) {
6140         $scope.position = $position.offset($element);
6141         if($element.find('input').length > 0 ){
6142             $scope.position.top += $element.find('input').prop('offsetHeight');
6143         }else{
6144             $scope.position.top += $element.find('a').prop('offsetHeight');
6145         }
6146         
6147         if ($scope.orientation === 'right') {
6148             $scope.position.left -= (((b2bMonthpickerPopupTemplate && b2bMonthpickerPopupTemplate.prop('offsetWidth')) || 290) - $element.find('input').prop('offsetWidth'));
6149         }
6150     };
6151
6152     function isSelected(dt) { 
6153         if (dt && angular.isDate($scope.currentDate) && compare(dt, $scope.currentDate) === 0) {
6154             return true;
6155         }
6156         return false;
6157     }
6158
6159     function isFromDate(dt) {
6160         if (dt && angular.isDate($scope.fromDate) && compare(dt, $scope.fromDate) === 0) {
6161             return true;
6162         }
6163         return false;
6164     }
6165
6166     function isDateRange(dt) {
6167         if (dt && $scope.fromDate && angular.isDate($scope.currentDate) && (compare(dt, $scope.fromDate) >= 0) && (compare(dt, $scope.currentDate) <= 0)) {
6168             return true;
6169         } else if (dt && $scope.fromDate && compare(dt, $scope.fromDate) === 0) {
6170             return true;
6171         }
6172         return false;
6173     }
6174
6175     function isOld(date, currentMonthDate) {
6176         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())) {
6177             return true;
6178         } else {
6179             return false;
6180         }
6181     }
6182
6183     function isNew(date, currentMonthDate) {
6184         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())) {
6185             return true;
6186         } else {
6187             return false;
6188         }
6189     }
6190
6191     function isPastDue(dt) {
6192         if ($scope.dueDate) {
6193             return (dt > $scope.dueDate);
6194         }
6195         return false;
6196     }
6197
6198     function isDueDate(dt) {
6199         if ($scope.dueDate) {
6200             return (dt.getTime() === $scope.dueDate.getTime());
6201         }
6202         return false;
6203     }
6204
6205     var isDisabled = function (date, currentMonthDate) {
6206         if ($attrs.from && !angular.isDate($scope.fromDate)) {
6207             return true;
6208         }
6209         if (format.disableWeekend === true && (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday")) {
6210             return true;
6211         }
6212         if (format.disableSunday === true && (dateFilter(date, format.dayHeader) === "Sunday")) {
6213             return true;
6214         }
6215         if (isOld(date, currentMonthDate) || isNew(date, currentMonthDate)) {
6216             return true;
6217         }
6218         return (($scope.minDate && compare(date, $scope.minDate) < 0) || ($scope.maxDate && compare(date, $scope.maxDate) > 0) || (format.disableDates && format.disableDates({
6219             date: date
6220         })));
6221     };
6222     
6223     var isDisabledMonth = function (date, currentMonthDate) {
6224         if ($attrs.from && !angular.isDate($scope.fromDate)) {
6225             return true;
6226         }
6227         if (format.disableWeekend === true && (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday")) {
6228             return true;
6229         }
6230         if (format.disableSunday === true && (dateFilter(date, format.dayHeader) === "Sunday")) {
6231             return true;
6232         }
6233         return (($scope.minDate && compare(date, $scope.minDate) < 0) || ($scope.maxDate && compare(date, $scope.maxDate) > 0) || (format.disableDates && format.disableDates({
6234             date: date
6235         })));
6236     };    
6237          
6238     var compare = function (date1, date2) {
6239         return (new Date(date1.getFullYear(), date1.getMonth(), date1.getDate()) - new Date(date2.getFullYear(), date2.getMonth(), date2.getDate()));
6240     };
6241
6242     function isMinDateAvailable(startDate, endDate) {
6243         if (($scope.minDate && $scope.minDate.getTime() >= startDate.getTime()) && ($scope.minDate.getTime() <= endDate.getTime())) {
6244             $scope.disablePrev = true;
6245             $scope.visibilityPrev = "hidden";
6246         } else {
6247             $scope.disablePrev = false;
6248             $scope.visibilityPrev = "visible";
6249         }
6250     }
6251     
6252     function isMaxDateAvailable(startDate, endDate) {
6253         if (($scope.maxDate && $scope.maxDate.getTime() >= startDate.getTime()) && ($scope.maxDate.getTime() <= endDate.getTime())) {
6254             $scope.disableNext = true;
6255             $scope.visibilityNext = "hidden";
6256         } else {
6257             $scope.disableNext = false;
6258             $scope.visibilityNext = "visible";
6259         }
6260     }    
6261     
6262     function isYearInRange(currentYear) {
6263             
6264         if ($scope.minDate && currentYear === $scope.minDate.getFullYear()) {
6265             $scope.disablePrev = true;
6266             $scope.visibilityPrev = "hidden";
6267         } else {
6268             $scope.disablePrev = false;
6269             $scope.visibilityPrev = "visible";
6270         }
6271         
6272         if ($scope.maxDate && currentYear === $scope.maxDate.getFullYear()) {
6273             $scope.disableNext = true;
6274             $scope.visibilityNext = "hidden";
6275         } else {
6276             $scope.disableNext = false;
6277             $scope.visibilityNext = "visible";
6278         }
6279         
6280     }    
6281
6282     this.focusNextPrev = function(b2bMonthpickerPopupTemplate,init){
6283         if(init){
6284             if (!$scope.disablePrev){
6285                 b2bMonthpickerPopupTemplate[0].querySelector('th.prev').focus();
6286             }else if (!$scope.disableNext){
6287                 b2bMonthpickerPopupTemplate[0].querySelector('th.next').focus();
6288             }else{
6289                 b2bMonthpickerPopupTemplate[0].querySelector('th.b2b-monthSelector-label').focus();
6290             }
6291         }else{
6292             if ($scope.disableNext || $scope.disablePrev){
6293                 b2bMonthpickerPopupTemplate[0].querySelector('th.b2b-monthSelector-label').focus();
6294             }       
6295         }    
6296     };
6297
6298     function getLabel(label) {
6299         if (label) {
6300             var labelObj = {
6301                 pre: label.substr(0, 1).toUpperCase(),
6302                 post: label
6303             };
6304             return labelObj;
6305         }
6306         return;
6307     }
6308
6309     function makeDate(date, dayFormat, dayHeaderFormat, isSelected, isFromDate, isDateRange, isOld, isNew, isDisabled, dueDate, pastDue) {
6310         return {
6311             date: date,
6312             label: dateFilter(date, dayFormat),
6313             header: dateFilter(date, dayHeaderFormat),
6314             selected: !!isSelected,
6315             fromDate: !!isFromDate,
6316             dateRange: !!isDateRange,
6317             oldMonth: !!isOld,
6318             nextMonth: !!isNew,
6319             disabled: !!isDisabled,
6320             dueDate: !!dueDate,
6321             pastDue: !!pastDue,
6322             focusable: !((isDisabled && !(isSelected || isDateRange)) || (isOld || isNew))
6323         };
6324     }
6325     
6326     this.modes = [
6327         {
6328             name: 'day',
6329             getVisibleDates: function (date) {
6330                 var year = date.getFullYear(),
6331                     month = date.getMonth(),
6332                     firstDayOfMonth = new Date(year, month, 1),
6333                     lastDayOfMonth = new Date(year, month + 1, 0);
6334                 var difference = startingDay - firstDayOfMonth.getDay(),
6335                     numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : -difference,
6336                     firstDate = new Date(firstDayOfMonth),
6337                     numDates = 0;
6338
6339                 if (numDisplayedFromPreviousMonth > 0) {
6340                     firstDate.setDate(-numDisplayedFromPreviousMonth + 1);
6341                     numDates += numDisplayedFromPreviousMonth; // Previous
6342                 }
6343                 numDates += getDaysInMonth(year, month + 1); // Current
6344                 numDates += (7 - numDates % 7) % 7; // Next
6345
6346                 var days = getDates(firstDate, numDates),
6347                     labels = new Array(7);
6348                 for (var i = 0; i < numDates; i++) {
6349                     var dt = new Date(days[i]);
6350                     days[i] = makeDate(dt,
6351                         format.day,
6352                         format.dayHeader,
6353                         isSelected(dt),
6354                         isFromDate(dt),
6355                         isDateRange(dt),
6356                         isOld(dt, date),
6357                         isNew(dt, date),
6358                         isDisabled(dt, date),
6359                         isDueDate(dt),
6360                         isPastDue(dt));
6361                 }
6362                 for (var j = 0; j < 7; j++) {
6363                     labels[j] = getLabel(dateFilter(days[j].date, format.dayHeader));
6364                 }
6365                 isMinDateAvailable(firstDayOfMonth, lastDayOfMonth);
6366                 isMaxDateAvailable(firstDayOfMonth, lastDayOfMonth);
6367                 return {
6368                     objects: days,
6369                     title: dateFilter(date, format.dayTitle),
6370                     labels: labels
6371                 };
6372             },
6373             split: 7,
6374             step: {
6375                 months: 1
6376             }
6377         },
6378         {
6379             name: 'month',
6380             getVisibleDates: function(date) {
6381                 var months = [], 
6382                     labels = [], 
6383                     year = date.getFullYear();
6384                     for (var i = 0; i < 12; i++) {
6385                         var dt = new Date(year,i,1);                
6386                         months[i] = makeDate(dt,
6387                                     format.month,
6388                                     format.dayHeader,
6389                                     isSelected(dt), 
6390                                     isFromDate(dt),
6391                                     isDateRange(dt),
6392                                     false,
6393                                     false,
6394                                     isDisabledMonth(dt, date),
6395                                     isDueDate(dt),                                       
6396                                     isPastDue(dt));                                                                                                                                                         
6397                     }
6398                 isYearInRange(year);  
6399                 return {objects: months, title: dateFilter(date, format.year), labels: labels};
6400             },
6401             split:4,
6402             step: {years: 1}
6403         }
6404     ];
6405 }])
6406
6407 .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) {
6408     return {
6409         restrict: 'EA',
6410         scope: {
6411           trigger: '='
6412         },
6413         replace: true,
6414         transclude: true,
6415         templateUrl: function (elem, attr) {
6416             if (attr.inline === 'true') {
6417                 return 'b2bTemplate/monthSelector/monthSelector-popup.html';
6418             }else if (attr.link === 'true') {
6419                 return 'b2bTemplate/monthSelector/monthSelectorLink.html';
6420             }else {
6421                 return 'b2bTemplate/monthSelector/monthSelector.html';
6422             }
6423         },
6424         scope: {},
6425         require: ['b2bMonthpickerPopup', 'ngModel', '?^b2bMonthpickerGroup'],
6426         controller: 'b2bMonthpickerController',
6427         link: function (scope, element, attrs, ctrls) {
6428             var MonthpickerCtrl = ctrls[0],
6429                 ngModel = ctrls[1],
6430                 b2bMonthpickerGroupCtrl = ctrls[2];
6431             var b2bMonthpickerPopupTemplate;
6432
6433             if (!ngModel) {
6434                 $log.error("ng-model is required.");
6435                 return; // do nothing if no ng-model
6436             }
6437
6438             // Configuration parameters
6439             var mode = scope.mode,
6440                 selected;
6441             scope.isOpen = false;
6442
6443             scope.headers = [];
6444             scope.footers = [];
6445             scope.triggerInterval=undefined;
6446
6447
6448             if (b2bMonthpickerGroupCtrl) {
6449                 b2bMonthpickerGroupCtrl.registerMonthpickerScope(scope);
6450             }
6451
6452             element.bind('keydown', function (ev) {                   
6453                 if (!ev.keyCode) {
6454                     if (ev.which) {
6455                         ev.keyCode = ev.which;
6456                     } else if (ev.charCode) {
6457                         ev.keyCode = ev.charCode;
6458                     }
6459                 }                                
6460                 if(ev.keyCode === keymap.KEY.ESC)
6461                 {
6462                     scope.isOpen = false;
6463                     toggleCalendar(scope.isOpen);
6464                     scope.$apply();
6465                 }
6466             });
6467             
6468             element.find('button').bind('click', function () {
6469                 onClicked();                
6470             });
6471
6472             element.find('a').bind('click', function () {
6473                 onClicked();                
6474             });
6475
6476             
6477             element.find('input').bind('click', function () {
6478                 onClicked();
6479             });
6480
6481             var onClicked = function() {        
6482                 if (!scope.ngDisabled) {
6483                     scope.isOpen = !scope.isOpen;
6484                     toggleCalendar(scope.isOpen);                    
6485                     MonthpickerCtrl.updatePosition(b2bMonthpickerPopupTemplate);
6486                     scope.$apply();
6487                 }
6488             };
6489         
6490             var toggleCalendar = function (flag) {
6491                 if (!scope.inline) {
6492                     if (flag) {
6493                         b2bMonthpickerPopupTemplate = angular.element($templateCache.get('b2bTemplate/monthSelector/monthSelector-popup.html'));
6494                         b2bMonthpickerPopupTemplate.attr('b2b-trap-focus-inside-element', 'false');
6495                         b2bMonthpickerPopupTemplate.attr('trigger', 'true');
6496                         b2bMonthpickerPopupTemplate = $compile(b2bMonthpickerPopupTemplate)(scope);
6497                         $document.find('body').append(b2bMonthpickerPopupTemplate);
6498                         b2bMonthpickerPopupTemplate.bind('keydown', escPress);
6499                         $timeout(function () {
6500                             scope.getFocus = true;
6501                             scope.trigger=0;
6502                             scope.$apply();
6503                             $timeout(function () {
6504                                 scope.getFocus = false;
6505                                 scope.$apply();
6506                                 MonthpickerCtrl.focusNextPrev(b2bMonthpickerPopupTemplate,true);
6507                             }, 100);
6508                         });
6509                         scope.triggerInterval = $interval(function () {
6510                             //This value is updated to trigger init() function of directive on year change.
6511                             scope.trigger=(scope.trigger === 0 ? 1 : 0);
6512                         }, 200);
6513
6514                     } else {
6515                         b2bMonthpickerPopupTemplate.unbind('keydown', escPress);
6516                         if(scope.triggerInterval)
6517                         {
6518                             $interval.cancel(scope.triggerInterval);
6519                             scope.triggerInterval=undefined;
6520                         }
6521                         b2bMonthpickerPopupTemplate.remove();
6522                         if(element.find('button').length > 0){
6523                             element.find('button')[0].focus();
6524                         }else{
6525                             element.find('a')[0].focus();
6526                         }
6527                         
6528                         scope.getFocus = false;
6529                     }
6530                 }
6531             };
6532
6533             var outsideClick = function (e) {
6534                 var isElement = $isElement(angular.element(e.target), element, $document);
6535                 var isb2bMonthpickerPopupTemplate = $isElement(angular.element(e.target), b2bMonthpickerPopupTemplate, $document);
6536                 if (!(isElement || isb2bMonthpickerPopupTemplate)) {
6537                     scope.isOpen = false;
6538                     toggleCalendar(scope.isOpen);
6539                     scope.$apply();
6540                 }
6541             };
6542
6543             var escPress = function (ev) {
6544                 if (!ev.keyCode) {
6545                     if (ev.which) {
6546                         ev.keyCode = ev.which;
6547                     } else if (ev.charCode) {
6548                         ev.keyCode = ev.charCode;
6549                     }
6550                 }
6551                 if (ev.keyCode) {
6552                     if (ev.keyCode === keymap.KEY.ESC) {
6553                         scope.isOpen = false;
6554                         toggleCalendar(scope.isOpen);
6555                         ev.preventDefault();
6556                         ev.stopPropagation();
6557                     } else if (ev.keyCode === 33) {
6558                         !scope.disablePrev && scope.move(-1);
6559                         $timeout(function () {
6560                             scope.getFocus = true;
6561                             scope.$apply();
6562                             $timeout(function () {
6563                                 scope.getFocus = false;
6564                                 scope.$apply();
6565                             }, 100);
6566                         });
6567                         ev.preventDefault();
6568                         ev.stopPropagation();
6569                     } else if (ev.keyCode === 34) {
6570                         !scope.disableNext && scope.move(1);
6571                         $timeout(function () {
6572                             scope.getFocus = true;
6573                             scope.$apply();
6574                             $timeout(function () {
6575                                 scope.getFocus = false;
6576                                 scope.$apply();
6577                             }, 100);
6578                         });
6579                         ev.preventDefault();
6580                         ev.stopPropagation();
6581                     }
6582                     scope.$apply();
6583                 }
6584             };              
6585                     
6586             $documentBind.click('isOpen', outsideClick, scope);
6587
6588             scope.$on('$destroy', function () {
6589                 if (scope.isOpen) {
6590                     scope.isOpen = false;
6591                     toggleCalendar(scope.isOpen);
6592                 }
6593             });
6594
6595             scope.resetTime = function (date) {
6596                 if (typeof date === 'string') {
6597                     date = date + 'T12:00:00';
6598                 }
6599                 var dt;
6600                 if (!isNaN(new Date(date))) {
6601                     dt = new Date(date);
6602                     if(scope.mode === 1){
6603                         dt = new Date(dt.getFullYear(), dt.getMonth());
6604                     }else{
6605                         dt = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());
6606                     }                                                            
6607                 } else {
6608                     return null;
6609                 }
6610                 return new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());
6611             };
6612             
6613             if (attrs.min) {
6614                 scope.$parent.$watch($parse(attrs.min), function (value) {
6615                     scope.minDate = value ? scope.resetTime(value) : null;
6616                     refill();
6617                 });
6618             }
6619             if (attrs.max) {
6620                 scope.$parent.$watch($parse(attrs.max), function (value) {
6621                     scope.maxDate = value ? scope.resetTime(value) : null;
6622                     refill();
6623                 });
6624             }
6625             if (attrs.due) {
6626                 scope.$parent.$watch($parse(attrs.due), function (value) {
6627                     scope.dueDate = value ? scope.resetTime(value) : null;
6628                     refill();
6629                 });
6630             }
6631             if (attrs.from) {
6632                 scope.$parent.$watch($parse(attrs.from), function (value) {
6633                     scope.fromDate = value ? scope.resetTime(value) : null;
6634                     refill();
6635                 });
6636             }
6637
6638             if (attrs.legendIcon) {
6639                 scope.$parent.$watch(attrs.legendIcon, function (value) {
6640                     scope.legendIcon = value ? value : null;
6641                     refill();
6642                 });
6643             }
6644             if (attrs.legendMessage) {
6645                 scope.$parent.$watch(attrs.legendMessage, function (value) {
6646                     scope.legendMessage = value ? value : null;
6647                     refill();
6648                 });
6649             }
6650             if (attrs.ngDisabled) {
6651                 scope.$parent.$watch(attrs.ngDisabled, function (value) {
6652                     scope.ngDisabled = value ? value : null;
6653                 });
6654             }      
6655             
6656
6657             // Split array into smaller arrays
6658             function split(arr, size) {
6659                 var arrays = [];
6660                 while (arr.length > 0) {
6661                     arrays.push(arr.splice(0, size));
6662                 }
6663                 return arrays;
6664             }
6665             
6666             var moveMonth = function(selectedDate, direction) {
6667                 var step = MonthpickerCtrl.modes[scope.mode].step;
6668                 selectedDate.setDate(1);
6669                 selectedDate.setMonth(selectedDate.getMonth() + direction * (step.months || 0));
6670                 selectedDate.setFullYear(selectedDate.getFullYear() + direction * (step.years || 0));
6671
6672                 return selectedDate;
6673             };            
6674
6675             function refill(date) {
6676                 if (angular.isDate(date) && !isNaN(date)) {
6677                     selected = new Date(date);
6678                 } else {
6679                     if (!selected) {
6680                         selected = new Date();
6681                     }
6682                 }
6683
6684                 if (selected) {                    
6685                     var selectedCalendar;
6686                     if(scope.mode === 1){
6687                         if(!angular.isDate(selected))
6688                            {                           
6689                                 selected = new Date();
6690                            }
6691                         selectedCalendar = moveMonth(angular.copy(selected), -1);
6692                     } else {
6693                         selectedCalendar = angular.copy(selected);
6694                     }
6695                     
6696                     var currentMode = MonthpickerCtrl.modes[mode],
6697                         data = currentMode.getVisibleDates(selected);
6698
6699                     scope.rows = split(data.objects, currentMode.split);
6700             
6701                     var flag=false;
6702                     var startFlag=false;
6703                     var firstSelected = false;
6704                     for(var i=0; i<scope.rows.length; i++)
6705                     {
6706                         for(var j=0; j<scope.rows[i].length; j++)
6707                         {
6708                             if(!scope.rows[i][j].disabled && !firstSelected)
6709                             {
6710                                 firstSelected=true;
6711                                 var firstDay = scope.rows[i][j];
6712                             }
6713
6714                             if(scope.rows[i][j].selected)
6715                             {
6716                                 flag=true;
6717                                 break;
6718                             }                  
6719                         }
6720                         if(flag)
6721                         {
6722                             break;
6723                         }
6724                     }
6725                     if(!flag && firstSelected)
6726                     {
6727                        firstDay.firstFocus=true;
6728                     }
6729
6730                     scope.labels = data.labels || [];
6731                     scope.title = data.title;                    
6732                 }
6733             }
6734
6735             scope.select = function (date,$event) {
6736                 var dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());
6737                 scope.currentDate = dt;
6738                 if (!scope.onSelectClose || (scope.onSelectClose && scope.onSelectClose({
6739                         date: dt
6740                     }) !== false)) {
6741                     if (angular.isNumber(scope.collapseWait)) {
6742                         $timeout(function () {
6743                             scope.isOpen = false;
6744                             toggleCalendar(scope.isOpen);
6745                         }, scope.collapseWait);
6746                     } else {
6747                         scope.isOpen = false;
6748                         toggleCalendar(scope.isOpen);
6749                     }
6750                 }
6751             };
6752
6753             scope.move = function (direction,$event) {
6754                 var step = MonthpickerCtrl.modes[mode].step;
6755                 selected.setDate(1);
6756                 selected.setMonth(selected.getMonth() + direction * (step.months || 0));
6757                 selected.setFullYear(selected.getFullYear() + direction * (step.years || 0));
6758                 refill();
6759                 scope.getFocus = true;
6760                 $timeout(function () {
6761                     if (attrs.inline === 'true') {
6762                         MonthpickerCtrl.focusNextPrev(element,false); 
6763                     }else{
6764                         MonthpickerCtrl.focusNextPrev(b2bMonthpickerPopupTemplate,false);
6765                     }
6766                 },100);
6767                 $event.preventDefault();
6768                 $event.stopPropagation();
6769             };
6770
6771             scope.$watch('currentDate', function (value) {
6772                 if (angular.isDefined(value) && value !== null) {
6773                     refill(value);
6774                 } else {
6775                     refill();
6776                 }
6777                 ngModel.$setViewValue(value);
6778             });
6779
6780             ngModel.$render = function () {
6781                 scope.currentDate = ngModel.$viewValue;
6782             };
6783
6784             var stringToDate = function (value) {
6785                 if (!isNaN(new Date(value))) {
6786                     value = new Date(value);
6787                 }
6788                 return value;
6789             };
6790             ngModel.$formatters.unshift(stringToDate);
6791         }
6792     };
6793 }])
6794
6795 .directive('b2bMonthpicker', ['$compile', '$log', 'b2bMonthpickerConfig', 'b2bMonthpickerService', function ($compile, $log, b2bMonthpickerConfig, b2bMonthpickerService) {
6796     return {
6797         restrict: 'A',
6798         scope: {
6799             disableDates: '&',
6800             onSelectClose: '&'
6801         },
6802         require: 'ngModel',
6803         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
6804             var dateFormatString = angular.isDefined(attr.dateFormat) ? scope.$parent.$eval(attr.dateFormat) : b2bMonthpickerConfig.dateFormat;
6805             var helperText = angular.isDefined(attr.helperText) ? scope.$parent.$eval(attr.helperText) : b2bMonthpickerConfig.helperText; 
6806             helperText = helperText.replace('$date', '{{dt | date : \'' + dateFormatString + '\'}}');
6807
6808             var descriptionText = angular.isDefined(attr.descriptionText) ? scope.$parent.$eval(attr.descriptionText) : b2bMonthpickerConfig.descriptionText;  
6809
6810
6811             var inline = false;
6812             if (elem.prop('nodeName') !== 'INPUT' && elem.prop('nodeName') !== 'A') {
6813                 inline = true;
6814             }
6815
6816             var selectedDateMessage = "";
6817             
6818             if (elem.prop('nodeName') !== 'A'){
6819                 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>';    
6820                 elem.attr('tabindex', '-1'); 
6821                 elem.attr('aria-hidden', 'true');  
6822                 elem.attr('readonly', 'true'); 
6823             }else{
6824                 selectedDateMessage = ''
6825                 elem.attr('aria-label', helperText);
6826             }
6827             
6828             var descriptionTextSpan = '<span class="offscreen-text" id="monthpicker-description'+scope.$id+'">'+descriptionText+'</span>';
6829             elem.removeAttr('b2b-Monthpicker');
6830             elem.removeAttr('ng-model');
6831             elem.removeAttr('ng-disabled');
6832             elem.addClass('Monthpicker-input');
6833             elem.attr('ng-model', 'dt');
6834             elem.attr('aria-describedby', 'monthpicker-description'+scope.$id);
6835             
6836             
6837             
6838             elem.attr('ng-disabled', 'ngDisabled');
6839             elem.attr('b2b-format-date', dateFormatString);
6840
6841             var wrapperElement = angular.element('<div></div>');
6842             wrapperElement.attr('b2b-Monthpicker-popup', '');
6843             wrapperElement.attr('ng-model', 'dt');
6844             if (inline) {
6845                 wrapperElement.attr('inline', inline);
6846             }
6847             if (elem.prop('nodeName') === 'A'){
6848                 wrapperElement.attr('link', true);
6849             }
6850             b2bMonthpickerService.setAttributes(attr, wrapperElement);
6851             b2bMonthpickerService.bindScope(attr, scope);
6852
6853             wrapperElement.html('');
6854             wrapperElement.append(selectedDateMessage);
6855             wrapperElement.append('');
6856             wrapperElement.append(descriptionTextSpan);
6857             wrapperElement.append('');
6858             wrapperElement.append(elem.prop('outerHTML'));
6859
6860             var elm = wrapperElement.prop('outerHTML');
6861             elm = $compile(elm)(scope);
6862             elem.replaceWith(elm);
6863         }],
6864         link: function (scope, elem, attr, ctrl) {
6865             if (!ctrl) {
6866                 $log.error("ng-model is required.");
6867                 return; // do nothing if no ng-model
6868             }
6869             
6870             scope.$watch('dt', function (value) {
6871                 ctrl.$setViewValue(value);
6872             });
6873             ctrl.$render = function () {
6874                 scope.dt = ctrl.$viewValue;
6875             };
6876         }
6877     };
6878 }])
6879
6880 .directive('b2bMonthpickerGroup', [function () {
6881     return {
6882         restrict: 'EA',
6883         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
6884             this.$$headers = [];
6885             this.$$footers = [];
6886             this.registerMonthpickerScope = function (MonthpickerScope) {
6887                 MonthpickerScope.headers = this.$$headers;
6888                 MonthpickerScope.footers = this.$$footers;
6889             };
6890         }],
6891         link: function (scope, elem, attr, ctrl) {}
6892     };
6893 }])
6894
6895 .directive('b2bFormatDate', ['dateFilter', function (dateFilter) {
6896     return {
6897         restrict: 'A',
6898         require: 'ngModel',
6899         link: function (scope, elem, attr, ctrl) {
6900             var b2bFormatDate = "";
6901             attr.$observe('b2bFormatDate', function (value) {
6902                 b2bFormatDate = value;
6903             });
6904             var dateToString = function (value) {
6905                 if (!isNaN(new Date(value))) {
6906                     return dateFilter(new Date(value), b2bFormatDate);
6907                 }
6908                 return value;
6909             };
6910             ctrl.$formatters.unshift(dateToString);
6911         }
6912     };
6913 }])
6914
6915 .directive('b2bMonthpickerHeader', [function () {
6916     return {
6917         restrict: 'EA',
6918         require: '^b2bMonthpickerGroup',
6919         transclude: true,
6920         replace: true,
6921         template: '',
6922         compile: function (elem, attr, transclude) {
6923             return function link(scope, elem, attr, ctrl) {
6924                 if (ctrl) {
6925                     ctrl.$$headers.push(transclude(scope, function () {}));
6926                 }
6927                 elem.remove();
6928             };
6929         }
6930     };
6931 }])
6932
6933 .directive('b2bMonthpickerFooter', [function () {
6934     return {
6935         restrict: 'EA',
6936         require: '^b2bMonthpickerGroup',
6937         transclude: true,
6938         replace: true,
6939         template: '',
6940         compile: function (elem, attr, transclude) {
6941             return function link(scope, elem, attr, ctrl) {
6942                 if (ctrl) {
6943                     ctrl.$$footers.push(transclude(scope, function () {}));
6944                 }
6945                 elem.remove();
6946             };
6947         }
6948     };
6949 }]);
6950 /**
6951  * @ngdoc directive
6952  * @name Navigation.att:multiLevelNavigation
6953  *
6954  * @description
6955  *  <file src="src/multiLevelNavigation/docs/readme.md" />
6956  *
6957  * @usage
6958  *       <div class="b2b-ml-nav">
6959  *          <ul role="tree">
6960  *             <li aria-label="{{child.name}}" tabindex="-1" b2b-ml-nav="{{child.type}}" role="treeitem" ng-repeat="child in treeStructure">
6961  *                  <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>
6962  *                      <!-- Below UL tag is RECURSIVE to generate n-childs -->
6963  *                      <ul role="group" ng-if="child.child">
6964  *                          <li aria-label="{{child.name}}" b2b-ml-nav="{{child.type}}" tabindex="-1" role="treeitem" ng-repeat="child in child.child">
6965  *                          <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>
6966  *                               <!-- RECURSIVE UL tag goes here -->
6967  *                          </li>
6968  *                      </ul>
6969  *             </li>
6970  *           </ul>
6971  *        </div>
6972  *
6973  * @example
6974  *  <section id="code">
6975         <example module="b2b.att">
6976             <file src="src/multiLevelNavigation/docs/demo.html" />
6977             <file src="src/multiLevelNavigation/docs/demo.js" />
6978        </example>
6979     </section>
6980  *
6981  */
6982 angular.module('b2b.att.multiLevelNavigation', ['b2b.att.utilities'])
6983     //directive b2bMlNav Test coverage 100% on 5/13
6984     .directive('b2bMlNav', ['keymap', function (keymap) {
6985         return {
6986             restrict: 'EA',
6987             link: function (scope, element) {
6988                 var rootE, parentE, upE, downE, lastE, homeE, endE;
6989                 //default root tree element tabindex set zero
6990                 if (element.parent().parent().hasClass('b2b-ml-nav') && (element[0].previousElementSibling === null)) {
6991                     element.attr('tabindex', 0);
6992                 }
6993                 //check root via class
6994                 var isRoot = function (elem) {
6995                         if (elem.parent().parent().eq(0).hasClass('b2b-ml-nav')) {
6996                             return true;
6997                         } else {
6998                             return false;
6999                         }
7000
7001                     }
7002                     //for any expandable tree item on click
7003                 var toggleState = function (e) {
7004                     if (angular.element(e.target).attr("b2b-ml-nav") !== "endNode") {
7005                         var eLink = element.find('a').eq(0);
7006                         if (eLink.hasClass('active')) {
7007                             eLink.removeClass('active');
7008                             eLink.parent().attr("aria-expanded", "false");
7009                             eLink.find('i').eq(0).removeClass('icon-primary-expanded');
7010                             eLink.find('i').eq(0).addClass('icon-primary-collapsed');
7011                         } else {
7012                             eLink.addClass('active');
7013                             eLink.parent().attr("aria-expanded", "true");
7014                             eLink.find('i').eq(0).removeClass('icon-primary-collapsed');
7015                             eLink.find('i').eq(0).addClass('icon-primary-expanded');
7016                         }
7017                     }
7018                 };
7019                 //function finds the main root-item from particular tree-group
7020                 var findRoot = function (elem) {
7021                     if (isRoot(elem)) {
7022                         rootE = elem;
7023                         return;
7024                     }
7025                     if (elem.attr("b2b-ml-nav") === "middleNode" || elem.attr("b2b-ml-nav") === "endNode") {
7026                         parentE = elem.parent().parent();
7027                     } else {
7028                         parentE = elem;
7029                     }
7030                     if (parentE.attr("b2b-ml-nav") === "rootNode") {
7031                         rootE = parentE;
7032                     } else {
7033                         findRoot(parentE);
7034                     }
7035                 };
7036                 //finds the last visible node of the previous tree-group
7037                 var findPreActive = function (elem) {
7038                     if (!(elem.hasClass("active"))) {
7039                         return;
7040                     } else {
7041                         var childElems = angular.element(elem[0].nextElementSibling.children);
7042                         lastE = angular.element(childElems[childElems.length - 1]);
7043                         if (lastE.attr("b2b-ml-nav") === "middleNode" && lastE.find('a').eq(0).hasClass('active')) {
7044                             findPreActive(lastE.find('a').eq(0));
7045                         }
7046                         upE = lastE;
7047                     }
7048                 };
7049                 //find above visible link
7050                 var findUp = function (elem) {
7051                     if (elem[0].previousElementSibling !== null) {
7052                         upE = angular.element(elem[0].previousElementSibling);
7053                     } else {
7054                         upE = elem.parent().parent();
7055                     }
7056                     if (isRoot(elem) || (upE.attr('b2b-ml-nav') === "middleNode" && upE[0] !== elem.parent().parent()[0])) {
7057                         findPreActive(upE.find('a').eq(0)); 
7058                     }
7059                 };
7060                 //find below visible link
7061                 var findDown = function (elem) {
7062                     if (elem.hasClass('active')) {
7063                         downE = elem.next().find('li').eq(0);
7064                     } else {
7065                         if (elem.parent().next().length !== 0) {
7066                             downE = elem.parent().next().eq(0);
7067                         } else {
7068                             if (elem.parent().parent().parent().next().length !== 0) {
7069                                 downE = elem.parent().parent().parent().next().eq(0);
7070                                 return;
7071                             }
7072                             downE = elem.parent().eq(0);
7073                         }
7074                     }
7075                 };
7076                 //finds last root-group element of the tree
7077                 var findEnd = function (elem) {
7078                     findRoot(elem);
7079                     endE = angular.element(rootE.parent()[0].children[rootE.parent()[0].children.length - 1]);
7080                 };
7081                 //finds first root element of tree
7082                 var findHome = function (elem) {
7083                     findRoot(elem);
7084                     homeE = angular.element(rootE.parent()[0].children[0]);
7085                 };
7086                 element.bind('click', function (e) {
7087                     if(element.attr("b2b-ml-nav") !== "endNode") { 
7088                         toggleState(e); 
7089                     }
7090                     e.stopPropagation();
7091                 });
7092                 element.bind('focus', function (e) {
7093                     if(element.attr("b2b-ml-nav") !== "endNode") {
7094                         if(element.find('a').eq(0).hasClass('active')) {
7095                             element.attr("aria-expanded", true);
7096                         }
7097                         else {
7098                             element.attr("aria-expanded", false);
7099                         }
7100                         
7101                     }
7102                 })
7103                 //Keyboard functionality approach:
7104                 //find keycode
7105                 //set set tabindex -1 on the current focus element
7106                 //find the next element to be focussed, set tabindex 0 and throw focus
7107                 element.bind('keydown', function (evt) {
7108                     switch (evt.keyCode) {
7109                     case keymap.KEY.ENTER:
7110                     case keymap.KEY.SPACE:
7111                         element.triggerHandler('click');
7112                         evt.stopPropagation();
7113                         evt.preventDefault();
7114                         break;
7115                     case keymap.KEY.END:
7116                         evt.preventDefault();
7117                         element.attr('tabindex', -1);
7118                         findEnd(element);
7119                         endE.eq(0).attr('tabindex', 0);
7120                         endE[0].focus();
7121                         evt.stopPropagation();
7122                         break;
7123                     case keymap.KEY.HOME:
7124                         evt.preventDefault();
7125                         element.attr('tabindex', -1);
7126                         findHome(element);
7127                         homeE.eq(0).attr('tabindex', 0);
7128                         homeE[0].focus();
7129                         evt.stopPropagation();
7130                         break;
7131                     case keymap.KEY.LEFT:
7132                         evt.preventDefault();
7133                         if (!isRoot(element)) {
7134                             element.attr('tabindex', -1);
7135                             parentE = element.parent().parent();
7136                             parentE.eq(0).attr('tabindex', 0);
7137                             parentE[0].focus();
7138                             parentE.eq(0).triggerHandler('click');
7139                         } else {
7140                             if (element.find('a').eq(0).hasClass('active')) {
7141                                 element.triggerHandler('click');
7142                             }
7143                         }
7144                         evt.stopPropagation();
7145                         break;
7146                     case keymap.KEY.UP:
7147                         evt.preventDefault();
7148                         if (!(isRoot(element) && element[0].previousElementSibling === null)) {
7149                             element.attr('tabindex', -1);
7150                             findUp(element);
7151                             upE.eq(0).attr('tabindex', 0);
7152                             upE[0].focus();
7153                         }
7154                         evt.stopPropagation();
7155                         break;
7156                     case keymap.KEY.RIGHT:
7157                         evt.preventDefault();
7158                         if (element.attr("b2b-ml-nav") !== "endNode") {
7159                             if (!element.find('a').eq(0).hasClass('active')) {
7160                                 element.triggerHandler('click');
7161                             }
7162                             element.attr('tabindex', -1);
7163                             findDown(element.find('a').eq(0));
7164                             downE.eq(0).attr('tabindex', 0);
7165                             downE[0].focus();
7166                         }
7167                         evt.stopPropagation();
7168                         break;
7169                     case keymap.KEY.DOWN:
7170                         evt.preventDefault();
7171                         element.attr('tabindex', -1);
7172                         if (!(element.attr("b2b-ml-nav") === "middleNode" && element.find('a').eq(0).hasClass('active')) && (element.next().length === 0)) {
7173                             if(element.parent().parent().attr("b2b-ml-nav") !== "rootNode" && element.parent().parent()[0].nextElementSibling !== null)
7174                             {
7175                                 findDown(element.find('a').eq(0));
7176                                 downE.eq(0).attr('tabindex', 0);
7177                                 downE[0].focus();
7178                                 evt.stopPropagation();
7179                                 break;
7180                             }
7181                             findRoot(element);
7182                             if (!(rootE.next().length === 0)) {
7183                                 rootE.next().eq(0).attr('tabindex', 0);
7184                                 rootE.next()[0].focus();
7185                             } else {
7186                                 rootE.eq(0).attr('tabindex', 0);
7187                                 rootE[0].focus();
7188                             }
7189                             evt.stopPropagation();
7190                             break;
7191                         }
7192                         findDown(element.find('a').eq(0));
7193                         downE.eq(0).attr('tabindex', 0);
7194                         downE[0].focus();
7195                         evt.stopPropagation();
7196                         break;
7197                     default:
7198                         break;
7199                     }
7200                 });
7201             }
7202         };
7203     }]);
7204 /**
7205  * @ngdoc directive
7206  * @name Tabs, tables & accordions.att:multipurposeExpander
7207  *
7208  * @description
7209  *  <file src="src/multipurposeExpander/docs/readme.md" />
7210  *
7211  * @usage
7212  * <!--With Close Other -->
7213  * <b2b-expander-group close-others="true">
7214  *  <b2b-expanders class="mpc-expanders" is-open="testmpc">            
7215  *      <b2b-expander-heading ng-class=" { 'b2b-toggle-header-active': !testmpc, 'b2b-toggle-header-inactive': testmpc } ">Heading content goes here</b2b-expander-heading>               
7216  *      <b2b-expander-body>
7217             <p>body content goes here</p>
7218         </b2b-expander-body>
7219  *  </b2b-expanders>
7220  *  </b2b-expander-group>
7221  *  
7222  * <!-- Without Close Other -->
7223  *  <b2b-expanders class="mpc-expanders" is-open="testmpc2">            
7224  *      <b2b-expander-heading ng-class=" { 'b2b-toggle-header-active': !testmpc2, 'b2b-toggle-header-inactive': testmpc2 } ">Heading content goes here</b2b-expander-heading>               
7225  *      <b2b-expander-body>
7226             <p>body content goes here</p>
7227         </b2b-expander-body>
7228  *  </b2b-expanders>
7229  *  
7230  * @example
7231  *  <section id="code">
7232         <example module="b2b.att.multipurposeExpander">
7233             <file src="src/multipurposeExpander/docs/demo.html" />
7234             <file src="src/multipurposeExpander/docs/demo.js" />
7235         </example>
7236     </section>
7237  *
7238  */
7239
7240 angular.module('b2b.att.multipurposeExpander', ['b2b.att', 'b2b.att.collapse'])
7241 .directive('b2bExpanderGroup', function () {
7242     return {
7243         restrict: 'EA',
7244         transclude: true,
7245         template: "<ng-transclude></ng-transclude>",
7246         controller:['$scope','$attrs', function($scope,$attrs){
7247             this.groups = [];
7248             this.index = -1;            
7249             this.scope = $scope;
7250             
7251             this.addGroup = function (groupScope) {
7252                 var that = this;
7253                 groupScope.index = this.groups.length;
7254                 this.groups.push(groupScope);
7255                 if(this.groups.length > 0){
7256                     this.index = 0;
7257                 }
7258                 groupScope.$on('$destroy', function () {
7259                 that.removeGroup(groupScope);
7260             });
7261             };
7262
7263             this.closeOthers = function (openGroup) {
7264                 var closeOthers = angular.isDefined($attrs.closeOthers);
7265                 if (closeOthers && !$scope.forceExpand) {
7266                     angular.forEach(this.groups, function (group) {
7267                         if (group !== openGroup) {
7268                             group.isOpen = false;
7269                         }
7270                     });
7271                 }
7272                 if (this.groups.indexOf(openGroup) === (this.groups.length - 1) && $scope.forceExpand) {
7273                     $scope.forceExpand = false;
7274                 }
7275             };
7276             this.removeGroup = function (group) {
7277             var index = this.groups.indexOf(group);
7278             if (index !== -1) {
7279                 this.groups.splice(this.groups.indexOf(group), 1);
7280             }
7281         };
7282         }]
7283        
7284     };
7285     
7286 })
7287 .directive('b2bExpanders', function () {
7288     return{
7289         restrict: 'EA',
7290         replace: true,
7291         require:['b2bExpanders','?^b2bExpanderGroup'],
7292         transclude: true,
7293         scope:{isOpen:'=?'},
7294         template: "<div ng-transclude></div>",
7295         controller: ['$scope', function ($scope){
7296                 var bodyScope = null;
7297                 var expanderScope = null;
7298                 this.isOpened = function(){                
7299                     if($scope.isOpen)
7300                     {
7301                         return  true;
7302                     }else
7303                     {
7304                         return false;
7305                     }
7306                 };                
7307                 this.setScope = function (scope) {
7308                     bodyScope = scope; 
7309                     bodyScope.isOpen = $scope.isOpen;                   
7310                 };                
7311                 this.setExpanderScope = function (scope) {
7312                     expanderScope = scope;                                   
7313                 };
7314                 this.toggle = function () {
7315                     $scope.isOpen = bodyScope.isOpen = !bodyScope.isOpen;                    
7316                     return bodyScope.isOpen;
7317                     
7318                 };
7319                 this.watchToggle = function(io){ 
7320                     bodyScope.isOpen = io;
7321                     expanderScope.updateIcons(io);
7322                 };  
7323             }],
7324         link: function (scope, elem, attr, myCtrl)
7325         {
7326             //scope.isOpen = false; 
7327             if(myCtrl[1]){
7328                 myCtrl[1].addGroup(scope);
7329             }
7330             scope.$watch('isOpen', function(val){                               
7331                 myCtrl[0].watchToggle(scope.isOpen);
7332                 if(val && myCtrl[1]){
7333                     myCtrl[1].closeOthers(scope);
7334                 }
7335             });            
7336         }
7337     };
7338 })
7339
7340 .directive('b2bExpanderHeading', function () {
7341     return{
7342         require: "^b2bExpanders",
7343         restrict: 'EA',
7344         replace: true,
7345         transclude: true,
7346         scope: true,
7347         template: "<div style='padding:10px 10px 10px 0 !important' ng-transclude></div>"
7348     };
7349 })
7350
7351 .directive('b2bExpanderBody', function () {
7352     return{
7353         restrict: 'EA',
7354         require: "^b2bExpanders",
7355         replace: true,
7356         transclude: true,
7357         scope: {},
7358         template: "<div b2b-collapse='!isOpen' ><div ng-transclude></div></div>",
7359         link: function (scope, elem, attr, myCtrl) {
7360             scope.isOpen = false;
7361             myCtrl.setScope(scope);
7362         }
7363     };
7364 })
7365
7366 .directive('b2bExpanderToggle', function () {
7367     return{
7368         restrict: 'EA',
7369         require: "^b2bExpanders",
7370         scope: {
7371             expandIcon: '@',
7372             collapseIcon: '@'
7373         },
7374         
7375         link: function (scope, element, attr, myCtrl)
7376         {
7377             myCtrl.setExpanderScope(scope);
7378             var isOpen = myCtrl.isOpened();   
7379
7380             scope.setIcon = function () {
7381                 element.attr("role", "tab");
7382
7383                 if (scope.expandIcon && scope.collapseIcon)
7384                 {
7385                     if (isOpen) {
7386                         element.removeClass(scope.expandIcon);
7387                         element.addClass(scope.collapseIcon);
7388
7389                         element.attr("aria-expanded", "true");
7390                     }
7391                     else {
7392                         element.removeClass(scope.collapseIcon);
7393                         element.addClass(scope.expandIcon);
7394
7395                         element.attr("aria-expanded", "false");
7396                     }
7397                 }                               
7398             };
7399             
7400             element.bind('click', function (){
7401                 scope.toggleit();
7402             });
7403             scope.updateIcons = function(nStat){
7404                 isOpen = nStat;
7405                 scope.setIcon();                
7406             };
7407             scope.toggleit = function (){
7408                 isOpen = myCtrl.toggle();
7409                 scope.setIcon();
7410                 scope.$apply();
7411             };                    
7412             scope.setIcon();
7413         }
7414     };
7415 });
7416 /**
7417  * @ngdoc directive
7418  * @name Messages, modals & alerts.att:notesMessagesAndErrors
7419  *
7420  * @description
7421  *  <file src="src/notesMessagesAndErrors/docs/readme.md" />
7422  *
7423  * @usage
7424  *  See Demo
7425  *
7426  * @example
7427  *  <section id="code">
7428         <example module="b2b.att">
7429             <file src="src/notesMessagesAndErrors/docs/demo.html" />
7430             <file src="src/notesMessagesAndErrors/docs/demo.js" />
7431        </example>
7432         </section>
7433  *
7434  */
7435 angular.module('b2b.att.notesMessagesAndErrors', []);
7436 /** 
7437  * @ngdoc directive 
7438  * @name Template.att:Notification Card
7439  * 
7440  * @description 
7441  *  <file src="src/notificationCardTemplate/docs/readme.md" /> 
7442  * 
7443  * @example 
7444  *  <section id="code"> 
7445         <b>HTML + AngularJS</b> 
7446         <example module="b2b.att"> 
7447             <file src="src/notificationCardTemplate/docs/demo.html" /> 
7448             <file src="src/notificationCardTemplate/docs/demo.js" /> 
7449        </example> 
7450     </section>    
7451  * 
7452  */
7453 angular.module('b2b.att.notificationCardTemplate', [])
7454   
7455 /** 
7456  * @ngdoc directive 
7457  * @name Template.att:Order Confirmation Template
7458  * 
7459  * @description 
7460  *  <file src="src/orderConfirmationTemplate/docs/readme.md" /> 
7461  * 
7462  * @example 
7463  *  <section id="code"> 
7464         <b>HTML + AngularJS</b> 
7465         <example module="b2b.att"> 
7466             <file src="src/orderConfirmationTemplate/docs/demo.html" /> 
7467             <file src="src/orderConfirmationTemplate/docs/demo.js" /> 
7468        </example> 
7469     </section>    
7470  * 
7471  */
7472 angular.module('b2b.att.orderConfirmationTemplate', []);
7473   
7474 /**
7475  * @ngdoc directive
7476  * @name Navigation.att:pagination
7477  *
7478  * @description
7479  *  <file src="src/pagination/docs/readme.md" />
7480  *
7481  * @usage
7482  *   <div b2b-pagination="" input-id="goto-page-2" total-pages="totalPages1" current-page="currentPage1" click-handler="customHandler" show-input="showInput"></div> 
7483  *
7484  * @example
7485  *  <section id="code">
7486         <example module="b2b.att">
7487             <file src="src/pagination/docs/demo.html" />
7488             <file src="src/pagination/docs/demo.js" />
7489        </example>
7490         </section>
7491  *
7492  */
7493 angular.module('b2b.att.pagination', ['b2b.att.utilities', 'ngTouch'])
7494     .directive('b2bPagination', ['b2bUserAgent', 'keymap', '$window', '$timeout', function (b2bUserAgent, keymap, $window, $timeout) {
7495         return {
7496             restrict: 'A',
7497             scope: {
7498                 totalPages: '=',
7499                 currentPage: '=',
7500                 showInput: '=',
7501                 clickHandler: '=?',
7502                 inputId: '='
7503             },
7504             replace: true,
7505             templateUrl: 'b2bTemplate/pagination/b2b-pagination.html',
7506             link: function (scope, elem) {
7507                 scope.isMobile = b2bUserAgent.isMobile();
7508                 scope.notMobile = b2bUserAgent.notMobile();
7509                 scope.focusedPage;
7510                 scope.meanVal = 3;
7511                 scope.$watch('totalPages', function (value) {
7512                     if (angular.isDefined(value) && value !== null) {
7513                         scope.pages = [];
7514                         if (value < 1) {
7515                             scope.totalPages = 1;
7516                             return;
7517                         }
7518                         if (value <= 10) {
7519                             for (var i = 1; i <= value; i++) {
7520                                 scope.pages.push(i);
7521                             }
7522                         } else if (value > 10) {
7523                             var midVal = Math.ceil(value / 2);
7524                             scope.pages = [midVal - 2, midVal - 1, midVal, midVal + 1, midVal + 2];
7525                         }
7526                         if(scope.currentPage === undefined || scope.currentPage === 1)
7527                         {
7528                             currentPageChanged(1);
7529                         }
7530                     }
7531                 });
7532                 scope.$watch('currentPage', function (value) {
7533                     currentPageChanged(value);
7534                     callbackHandler(value);
7535                 });
7536                 var callbackHandler = function (num) {
7537                     if (angular.isFunction(scope.clickHandler)) {
7538                         scope.clickHandler(num);
7539                     }
7540                 };
7541
7542                 function currentPageChanged(value) {
7543                     if (angular.isDefined(value) && value !== null) {
7544                         if (!value || value < 1) {
7545                             value = 1;
7546                         }
7547                         if (value > scope.totalPages) {
7548                             value = scope.totalPages;
7549                         }
7550                         if (scope.currentPage !== value) {
7551                             scope.currentPage = value;
7552                             callbackHandler(scope.currentPage);
7553                         }
7554                         if (scope.totalPages > 10) {
7555                             var val = parseInt(value);
7556                             if (val <= 6) {
7557                                 scope.pages = [1, 2, 3, 4, 5, 6, 7, 8];
7558                             } else if (val > 6 && val <= scope.totalPages - 5) {
7559                                 scope.pages = [val - 1, val, val + 1];
7560                             } else if (val >= scope.totalPages - 5) {
7561                                 scope.pages = [scope.totalPages - 7, scope.totalPages - 6, scope.totalPages - 5, scope.totalPages - 4, scope.totalPages - 3, scope.totalPages - 2, scope.totalPages - 1, scope.totalPages];
7562                             }
7563                         }
7564                         if (scope.isMobile) {
7565                             var inWidth = $window.innerWidth;
7566                             var viewLimit = 7;
7567                             if (inWidth <= 400) {
7568                                 viewLimit = 7;
7569                             } else if (inWidth > 400 && inWidth < 500) {
7570                                 viewLimit = 9;
7571                             } else if (inWidth >= 500 && inWidth < 600) {
7572                                 viewLimit = 11;
7573                             } else if (inWidth >= 600 && inWidth < 700) {
7574                                 viewLimit = 13;
7575                             } else if (inWidth >= 700 && inWidth < 800) {
7576                                 viewLimit = 15;
7577                             }
7578
7579                             var val = parseInt(value);
7580
7581                             scope.meanVal = Math.floor(viewLimit / 2);
7582                             var lowerLimit = (val - scope.meanVal) < 1 ? 1 : val - scope.meanVal;
7583                             var upperLimit = (lowerLimit + viewLimit - 1) > scope.totalPages ? scope.totalPages : lowerLimit + viewLimit - 1;
7584                             scope.pages = [];
7585                             for (var i = lowerLimit; i <= upperLimit; i++) {
7586                                 scope.pages.push(i);
7587                             }
7588                         }
7589                     }
7590                 }
7591                 scope.gotoKeyClick = function (keyEvent) {
7592                   if (keyEvent.which === keymap.KEY.ENTER) {
7593                     scope.gotoBtnClick()
7594                   }
7595                 }
7596                 scope.gotoBtnClick = function () {
7597                     currentPageChanged(parseInt(scope.gotoPage)); 
7598                     callbackHandler(scope.currentPage);
7599                     var qResult = elem[0].querySelector('button');
7600                     angular.element(qResult).attr('disabled','true');
7601                     $timeout(function(){
7602                         elem[0].querySelector('.b2b-pager__item--active').focus();
7603                     }, 50); 
7604                     scope.gotoPage = null;               
7605                 }
7606                 scope.onfocusIn = function(evt)
7607                 {
7608                     var qResult = elem[0].querySelector('button');
7609                     angular.element(qResult).removeAttr('disabled');
7610                 }
7611                 scope.onfocusOut = function(evt)
7612                 {
7613                     if(evt.target.value === "")
7614                     {
7615                         var qResult = elem[0].querySelector('button');
7616                         angular.element(qResult).attr('disabled','true');
7617                     }                    
7618                 }
7619                 scope.next = function (event) {
7620                     if (event != undefined) {
7621                         event.preventDefault();
7622                     }
7623                     if (scope.currentPage < scope.totalPages) {
7624                         scope.currentPage += 1;
7625                         callbackHandler(scope.currentPage);
7626                     }
7627                 };
7628                 scope.prev = function (event) {
7629                     if (event != undefined) {
7630                         event.preventDefault();
7631                     }
7632                     if (scope.currentPage > 1) {
7633                         scope.currentPage -= 1;
7634                         callbackHandler(scope.currentPage);
7635                     }
7636                 };
7637                 scope.selectPage = function (value, event) {
7638                     event.preventDefault();
7639                     scope.currentPage = value;
7640                     scope.focusedPage = value;
7641                     callbackHandler(scope.currentPage);
7642                 };
7643                 scope.checkSelectedPage = function (value) {
7644                     if (scope.currentPage === value) {
7645                         return true;
7646                     }
7647                     return false;
7648                 };
7649                 scope.isFocused = function (page) {
7650                     return scope.focusedPage === page;
7651                 };
7652             }
7653         };
7654     }]);
7655 /**
7656  * @ngdoc directive
7657  * @name Navigation.att:paneSelector
7658  *
7659  * @description
7660  *  <file src="src/paneSelector/docs/readme.md" />
7661  *
7662  * @usage
7663  *  Please refer demo.html tab in Example section below.
7664  *
7665  * @example
7666     <section id="code">
7667         <b>HTML + AngularJS</b>
7668         <example module="b2b.att">
7669             <file src="src/paneSelector/docs/demo.html" />
7670             <file src="src/paneSelector/docs/demo.js" />
7671         </example>
7672     </section>
7673  */
7674
7675 angular.module('b2b.att.paneSelector', ['b2b.att.tabs', 'b2b.att.utilities'])
7676
7677 .filter('paneSelectorSelectedItemsFilter', [function () {
7678     return function (listOfItemsArray) {
7679
7680         if (!listOfItemsArray) {
7681             listOfItemsArray = [];
7682         }
7683
7684         var returnArray = [];
7685
7686         for (var i = 0; i < listOfItemsArray.length; i++) {
7687             if (listOfItemsArray[i].isSelected) {
7688                 returnArray.push(listOfItemsArray[i]);
7689             }
7690         }
7691
7692         return returnArray;
7693     };
7694 }])
7695
7696 .filter('paneSelectorFetchChildItemsFilter', [function () {
7697     return function (listOfItemsArray) {
7698
7699         if (!listOfItemsArray) {
7700             listOfItemsArray = [];
7701         }
7702
7703         var returnArray = [];
7704
7705         for (var i = 0; i < listOfItemsArray.length; i++) {
7706             for (var j = 0; j < listOfItemsArray[i].childItems.length; j++) {
7707                 returnArray.push(listOfItemsArray[i].childItems[j]);
7708             }
7709         }
7710
7711         return returnArray;
7712     };
7713 }])
7714
7715 .directive('b2bPaneSelector', [function () {
7716     return {
7717         restrict: 'AE',
7718         replace: true,
7719         templateUrl: 'b2bTemplate/paneSelector/paneSelector.html',
7720         transclude: true,
7721         scope: {}
7722     };
7723 }])
7724
7725 .directive('b2bPaneSelectorPane', [ function () {
7726     return {
7727         restrict: 'AE',
7728         replace: true,
7729         templateUrl: 'b2bTemplate/paneSelector/paneSelectorPane.html',
7730         transclude: true,
7731         scope: {}
7732     };
7733 }])
7734
7735 .directive('b2bTabVertical', ['$timeout', 'keymap', function ($timeout, keymap) {
7736     return {
7737         restrict: 'A',
7738         require: '^b2bTab',
7739         link: function (scope, element, attr, b2bTabCtrl) {
7740
7741             if (!b2bTabCtrl) {
7742                 return;
7743             }
7744
7745             // retreive the isolateScope
7746             var iScope = angular.element(element).isolateScope();
7747
7748             $timeout(function () {
7749                 angular.element(element[0].querySelector('a')).unbind('keydown');
7750                 angular.element(element[0].querySelector('a')).bind('keydown', function (evt) {
7751
7752                     if (!(evt.keyCode)) {
7753                         evt.keyCode = evt.which;
7754                     }
7755
7756                     switch (evt.keyCode) {
7757                         case keymap.KEY.DOWN:
7758                             evt.preventDefault();
7759                             iScope.nextKey();
7760                             break;
7761
7762                         case keymap.KEY.UP:
7763                             evt.preventDefault();
7764                             iScope.previousKey();
7765                             break;
7766
7767                         default:;
7768                     }
7769                 });
7770             });
7771         }
7772     };
7773 }]);
7774 /**
7775  * @ngdoc directive
7776  * @name Forms.att:phoneNumberInput
7777  *
7778  * @description
7779  *  <file src="src/phoneNumberInput/docs/readme.md" />
7780  *
7781  * @usage
7782 <form name="userForm1">
7783     <div class="form-row" ng-class="{'error':!userForm1.text.$valid && userForm1.text.$dirty}">
7784         <label>Phone Mask<span style="color:red">*</span>: (npa) nxx-line &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Model Value: {{mask.text}}</label>
7785         <div>
7786             <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 />
7787             <div ng-messages="userForm1.text.$error" class="error-msg" aria-live="polite" aria-atomic="true">
7788                 <span ng-message="required" role="alert">This field is mandatory!</span>
7789                 <span ng-message="invalidPhoneNumber" role="alert">Please enter valid phone number!</span>
7790                 <span ng-message="mask" role="alert">Please enter valid phone number!</span>
7791             </div>
7792         </div>
7793     </div>
7794 </form>
7795  *
7796  * @example
7797  *  <section id="code">
7798         <example module="b2b.att">
7799             <file src="src/phoneNumberInput/docs/demo.html" />
7800             <file src="src/phoneNumberInput/docs/demo.js" />
7801        </example>
7802     </section>
7803  *
7804  */
7805 angular.module('b2b.att.phoneNumberInput', ['ngMessages', 'b2b.att.utilities'])
7806     .constant("CoreFormsUiConfig", {
7807         phoneMask: '(___) ___-____',
7808         phoneMaskDot: '___.___.____',
7809         phoneMaskHyphen: '___-___-____'
7810     })
7811     .directive('b2bPhoneMask', ['$parse', 'CoreFormsUiConfig', 'keymap', function ($parse, CoreFormsUiConfig, keymap) {
7812         return {
7813             require: 'ngModel',
7814             scope: {
7815                 ngModel: '='
7816             },
7817             link: function (scope, iElement, iAttrs, ctrl) {
7818                 var navigatorAgent = navigator.userAgent.toLowerCase(),
7819                     isAndroid = navigatorAgent.indexOf("android") > -1,
7820                     oldIE = navigatorAgent.indexOf('msie 8.0') !== -1;
7821                 var mask = '';
7822                 var validPhoneNumber = false;
7823                 var currentKey = '';
7824                 if (isAndroid) {
7825                     mask = "__________";
7826                 } else {
7827                     switch (iAttrs.b2bPhoneMask) {
7828                     case "phoneMask":
7829                         mask = CoreFormsUiConfig.phoneMask;
7830                         break;
7831                     case "phoneMaskDot":
7832                         mask = CoreFormsUiConfig.phoneMaskDot;
7833                         break;
7834                     case "phoneMaskHyphen":
7835                         mask = CoreFormsUiConfig.phoneMaskHyphen;
7836                         break;
7837                     default:
7838                         mask = CoreFormsUiConfig.phoneMask;
7839                     }
7840                 }
7841                 iElement.attr("maxlength", mask.length);
7842                 var checkValidity = function (unmaskedValue, rawValue) {
7843                     var valid = false;
7844                     if (angular.isUndefined(rawValue) || rawValue === '') {
7845                         valid = true;
7846                     } else if (unmaskedValue) {
7847                         valid = (unmaskedValue.length === 10);
7848                     }
7849                     ctrl.$setValidity('invalidPhoneNumber', validPhoneNumber);
7850                     ctrl.$setValidity('mask', valid);
7851                     return valid;
7852                 };
7853                 var handleKeyup = function (evt) {
7854
7855                     if (evt && evt.keyCode === keymap.KEY.SHIFT) {
7856                         return;
7857                     }
7858
7859                     var index, formattedNumber;
7860                     if (ctrl.$modelValue) {
7861                         formattedNumber = ctrl.$modelValue;
7862                     } else {
7863                         formattedNumber = iElement.val();
7864                     }
7865                     if (!formattedNumber.length && currentKey === '') {
7866                         return;
7867                     }
7868                     var maskLength, inputNumbers, maskArray, tempArray, maskArrayLength;
7869                     tempArray = [];
7870                     maskArray = mask.split("");
7871                     maskArrayLength = maskArray.length;
7872                     maskLength = formattedNumber.substring(0, mask.length);
7873                     inputNumbers = formattedNumber.replace(/[^0-9]/g, "").split("");
7874                     for (index = 0; index < maskArrayLength; index++) {
7875                         tempArray.push(maskArray[index] === "_" ? inputNumbers.shift() : maskArray[index]);
7876                         if (inputNumbers.length === 0) {
7877                             break;
7878                         }
7879                     }
7880                     formattedNumber = tempArray.join("");
7881                     if (formattedNumber === '(') {
7882                         formattedNumber = '';
7883                     }
7884
7885                     if ( (angular.isDefined(evt) && evt.which) && currentKey !== '') {
7886                         if (maskArray[0] === currentKey && formattedNumber === '') {
7887                             formattedNumber = '(';
7888                         } else if (evt.which === keymap.KEY.SPACE && currentKey === ' ') {
7889                             formattedNumber = formattedNumber + ') ';
7890                         } else if (maskArray[0] === currentKey && formattedNumber === '') {
7891                             formattedNumber = formattedNumber + currentKey;
7892                         } else if (maskArray[formattedNumber.length] === currentKey) {
7893                             formattedNumber = formattedNumber + currentKey;
7894                         }
7895                         currentKey = '';
7896                     }
7897
7898                     ctrl.$setViewValue(formattedNumber);
7899                     ctrl.$render();
7900                     return formattedNumber;
7901                 };
7902
7903
7904                 // since we are only allowing 0-9, why even let the keypress go forward?
7905                 // also added in delete... in case they want to delete :)
7906                 var handlePress = function (e) {
7907                     if (e.which) {
7908                         if ((e.which < 48 || e.which > 57) && (e.which < 96 || e.which > 105)) {
7909                             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 &&
7910                                 // Allow: Ctrl+V/v
7911                                 (!(e.ctrlKey) && (e.which !== '118' || e.which !== '86')) &&
7912                                 // Allow: Ctrl+C/c
7913                                 (!(e.ctrlKey) && (e.which !== '99' || e.which !== '67')) &&
7914                                 // Allow: Ctrl+X/x
7915                                 (!(e.ctrlKey) && (e.which !== '120' || e.which !== '88'))) {
7916                                 e.preventDefault ? e.preventDefault() : e.returnValue = false;
7917                                 iElement.attr("aria-label", "Only numbers are allowed");
7918                                 validPhoneNumber = false;
7919                             }
7920                         } else {
7921                             iElement.removeAttr("aria-label");
7922                             validPhoneNumber = true;
7923                         }
7924
7925                         setCurrentKey(e);
7926                     }
7927                     scope.$apply();
7928                 };
7929                 // i moved this out because i thought i might need focus as well..
7930                 // to handle setting the model as the view changes
7931                 var parser = function (fromViewValue) {
7932                     var letters = /^[A-Za-z]+$/;
7933                     var numbers = /^[0-9]+$/;
7934                     if (angular.isUndefined(fromViewValue) || fromViewValue === '') {
7935                         validPhoneNumber = true;
7936                     } else {
7937                         if (fromViewValue.match(letters)) {
7938                             validPhoneNumber = false;
7939                         }
7940                         if (fromViewValue.match(numbers)) {
7941                             validPhoneNumber = true;
7942                         }
7943                     }
7944                     var clean = "";
7945                     if (fromViewValue && fromViewValue.length > 0) {
7946                         clean = fromViewValue.replace(/[^0-9]/g, '');
7947                     }
7948                     checkValidity(clean, fromViewValue);
7949                     return clean;
7950                 };
7951
7952                 //to handle reading the model and formatting it
7953                 var formatter = function (fromModelView) {
7954                     var input = '';
7955                     checkValidity(fromModelView);
7956                     if (fromModelView) {
7957                         input = handleKeyup();
7958                     }
7959                     return input;
7960                 };
7961
7962                 var setCurrentKey = function (e) {
7963                     switch (e.which) {
7964                     case 189:
7965                     case 109:
7966                         currentKey = '-';
7967                         break;
7968                     case 190:
7969                     case 110:
7970                         currentKey = '.';
7971                         break;
7972                     case 57:
7973                         if (e.shiftKey === true) {
7974                             currentKey = '(';
7975                         }
7976                         break;
7977                     case 48:
7978                         if (e.shiftKey === true) {
7979                             currentKey = ')';
7980                         }
7981                         break;
7982                     case 32:
7983                         currentKey = ' ';
7984                         break;
7985                     }
7986                 };
7987
7988                 if (angular.isDefined(scope.ngModel)) {
7989                     parser(scope.ngModel);
7990                 }
7991
7992                 ctrl.$parsers.push(parser);
7993                 ctrl.$formatters.push(formatter);
7994                 iElement.bind('keyup', handleKeyup);
7995                 iElement.bind('keydown', handlePress);
7996             }
7997         };
7998 }]);
7999 /** 
8000  * @ngdoc directive 
8001  * @name Template.att:Profile Blocks 
8002  * 
8003  * @description 
8004  *  <file src="src/profileBlockTemplate/docs/readme.md" /> 
8005  * @example 
8006  *  <section id="code">  
8007         <example module="b2b.att"> 
8008             <file src="src/profileBlockTemplate/docs/demo.html" /> 
8009             <file src="src/profileBlockTemplate/docs/demo.js" /> 
8010        </example>  
8011     </section>  
8012  *  
8013  */   
8014
8015 angular.module('b2b.att.profileBlockTemplate', [])
8016     
8017      
8018   
8019 /**
8020  * @ngdoc directive
8021  * @name Layouts.att:profileCard
8022  *
8023  * @description
8024  *  <file src="src/profileCard/docs/readme.md" />
8025  *
8026  * @usage
8027  *  <b2b-profile-card></b2b-profile-card>
8028  *
8029  * @example
8030     <section id="code">   
8031         <example module="b2b.att">
8032             <file src="src/profileCard/docs/demo.html" />
8033             <file src="src/profileCard/docs/demo.js" />
8034         </example>
8035     </section>
8036  */
8037
8038 angular.module('b2b.att.profileCard', ['b2b.att'])
8039 .constant('profileStatus',{
8040     status: {
8041         ACTIVE: {
8042             status: "Active",
8043             color: "green"
8044         },
8045         DEACTIVATED: {
8046             status: "Deactivated",
8047             color: "red"
8048         },
8049         LOCKED: {
8050             status: "Locked",
8051             color: "red"
8052         },
8053         IDLE: {
8054             status: "Idle",
8055             color: "yellow"
8056         },
8057         PENDING: {
8058             status: "Pending",
8059             color: "blue"
8060         }
8061     },
8062     role: "COMPANY ADMINISTRATOR"
8063
8064 })
8065 .directive('b2bProfileCard',['$http','$q','profileStatus', function($http,$q,profileStatus) {
8066    return {
8067         restrict: 'EA',
8068         replace: 'true',
8069         templateUrl: function(element, attrs){
8070             if(!attrs.addUser){
8071                 return 'b2bTemplate/profileCard/profileCard.html';
8072             }
8073             else{
8074                 return 'b2bTemplate/profileCard/profileCard-addUser.html';
8075             }
8076         },
8077         scope: {
8078             profile:'=',
8079             characterLimit: '@'
8080         },
8081         link: function(scope, elem, attr){
8082             scope.characterLimit = parseInt(attr.characterLimit, 10) || 25;
8083             scope.shouldClip = function(str) {
8084                 return str.length > scope.characterLimit;
8085             };
8086
8087             scope.showEmailTooltip = false;
8088
8089             scope.image=true;
8090             function isImage(src) {
8091                 var deferred = $q.defer();
8092                 var image = new Image();
8093                 image.onerror = function() {
8094                     deferred.reject(false);
8095                 };
8096                 image.onload = function() {
8097                     deferred.resolve(true);
8098                 };
8099                 if(src !== undefined && src.length>0 ){
8100                     image.src = src;
8101                 } else {
8102                      deferred.reject(false);
8103                 }
8104                 return deferred.promise;
8105             }
8106             if(!attr.addUser){
8107             scope.image=false;
8108             isImage(scope.profile.img).then(function(img) {
8109                 scope.image=img;
8110             });
8111             var splitName=(scope.profile.name).split(' ');
8112             scope.initials='';
8113             for(var i=0;i<splitName.length;i++){
8114                 scope.initials += splitName[i][0];
8115             }
8116             if(scope.profile.role.toUpperCase() === profileStatus.role){
8117                 scope.badge=true;
8118             }
8119             var profileState=profileStatus.status[scope.profile.state.toUpperCase()];
8120             if(profileState) {
8121                 scope.profile.state=profileStatus.status[scope.profile.state.toUpperCase()].status;
8122                 scope.colorIcon=profileStatus.status[scope.profile.state.toUpperCase()].color;
8123                 if(scope.profile.state.toUpperCase()===profileStatus.status.PENDING.status.toUpperCase()||scope.profile.state.toUpperCase()===profileStatus.status.LOCKED.status.toUpperCase()){
8124                         scope.profile.lastLogin=scope.profile.state;
8125                 }
8126             }
8127             var today=new Date().getTime();
8128             var lastlogin=new Date(scope.profile.lastLogin).getTime();
8129             var diff=(today-lastlogin)/(1000*60*60*24);
8130             if(diff<=1){
8131                 scope.profile.lastLogin="Today";
8132             }
8133             else if(diff<=2){
8134                 scope.profile.lastLogin="Yesterday";
8135             }
8136         }
8137     }
8138 };
8139 }]);
8140 /**
8141  * @ngdoc directive
8142  * @name Forms.att:radios
8143  *
8144  * @description
8145  *  <file src="src/radios/docs/readme.md" />
8146  *
8147  * @usage
8148  *  See demo section
8149  *
8150  * @param {boolean} refreshRadioGroup - A trigger that recalculates and updates the accessibility roles on radios in a group.
8151  * 
8152  * @example
8153     <section id="code">
8154                <b>HTML + AngularJS</b>
8155                <example module="b2b.att">
8156                 <file src="src/radios/docs/demo.html" />
8157                 <file src="src/radios/docs/demo.js" />
8158                </example>
8159             </section>
8160  */
8161 angular.module('b2b.att.radios', ['b2b.att.utilities'])
8162 .directive('b2bRadioGroupAccessibility', ['$timeout', 'b2bUserAgent', function($timeout, b2bUserAgent) {
8163     return {
8164         restrict: "A",
8165         scope: {
8166             refreshRadioGroup: "=",
8167         },
8168         link: function(scope, ele, attr) {
8169
8170             var roleRadioElement, radioProductSelectElement, radioInputTypeElement;
8171
8172             $timeout(calculateNumberOfRadio);
8173
8174             scope.$watch('refreshRadioGroup', function(value) {
8175                 if (value === true) {
8176                     addingRoleAttribute();
8177                     $timeout(calculateNumberOfRadio);
8178                     scope.refreshRadioGroup = false;
8179                 } else {
8180                     return;
8181                 }
8182             })
8183
8184
8185             function calculateNumberOfRadio() {
8186                 roleRadioElement = ele[0].querySelectorAll('[role="radio"]');
8187
8188                 radioProductSelectElement = ele[0].querySelectorAll('[role="radiogroup"] li.radio-box');
8189
8190                 radioInputTypeElement = ele[0].querySelectorAll('input[type="radio"]');
8191
8192                 for (var i = 0; i < radioInputTypeElement.length; i++) {
8193                     var isChecked = radioInputTypeElement[i].checked ? 'true' : 'false';
8194                     var isDisabled = radioInputTypeElement[i].disabled ? 'true' : 'false';
8195                     var numOfx = i + 1 + ' of ' + radioInputTypeElement.length;
8196                     angular.element(roleRadioElement[i]).attr({
8197                         'aria-checked': isChecked,
8198                         'aria-disabled': isDisabled,
8199                         'data-opNum': numOfx
8200                     });
8201                     if (b2bUserAgent.notMobile()) {
8202                         angular.element(roleRadioElement[i]).removeAttr("role");
8203                     }
8204
8205                     if (radioProductSelectElement.length) {
8206                         isChecked === 'true' ? angular.element(radioProductSelectElement[i]).addClass('active') : angular.element(radioProductSelectElement[i]).removeClass('active');
8207                     }
8208
8209                     if (/Android/i.test(navigator.userAgent)) {
8210                         angular.element(roleRadioElement[i]).append('<span class="hidden-spoken">. ' + numOfx + '.</span>');
8211                     }
8212
8213
8214                     angular.element(radioInputTypeElement[i]).bind('click', radioStateChangeonClick);
8215
8216                 }
8217             }
8218
8219             function addingRoleAttribute() {
8220                 for (var i = 0; i < radioInputTypeElement.length; i++) {
8221                     if (b2bUserAgent.notMobile()) {
8222                         angular.element(roleRadioElement[i]).attr("role", "radio");
8223                     }
8224                 }
8225             }
8226
8227             function radioStateChangeonClick() {
8228                 for (var i = 0; i < radioInputTypeElement.length; i++) {
8229                     var isChecked = radioInputTypeElement[i].checked ? 'true' : 'false';
8230                     var isDisabled = radioInputTypeElement[i].disabled ? 'true' : 'false';
8231                     if (radioProductSelectElement.length) {
8232                         isChecked === 'true' ? angular.element(radioProductSelectElement[i]).addClass('active') : angular.element(radioProductSelectElement[i]).removeClass('active');
8233                     }
8234                     angular.element(roleRadioElement[i]).attr({
8235                         'aria-checked': isChecked,
8236                         'aria-disabled': isDisabled
8237                     });
8238                 }
8239
8240             }
8241         }
8242     }
8243
8244 }]);
8245
8246 /**
8247  * @ngdoc directive
8248  * @name Forms.att:searchField
8249  *
8250  * @description
8251  *  <file src="src/searchField/docs/readme.md" />
8252  *
8253  * @usage
8254  *  <div b2b-search-field dropdown-list="listdata" on-click-callback="clickFn(value)" class="span12" input-model='typedString' config-obj='keyConfigObj'></div>
8255  *
8256  * @example
8257  <section id="code">
8258     <example module="b2b.att">
8259     <file src="src/searchField/docs/demo.html" />
8260     <file src="src/searchField/docs/demo.js" />
8261     </example>
8262 </section>
8263  */
8264
8265 angular.module('b2b.att.searchField', ['b2b.att.utilities', 'b2b.att.position'])
8266     .filter('b2bFilterInput', [function() {
8267         return function(list, str, keyArray, displayListKey, isContainsSearch, searchSeperator) {
8268             var res = [];
8269             var searchLabel;
8270             var searchCondition;
8271             var conditionCheck = function(searchSeperator, listItem, displayListKey, splitString) {
8272                 var displayTitle = null;
8273                 if (splitString) {
8274                     for (var i = 0; i < displayListKey.length; i++) {
8275                         if (i <= 0) {
8276                             displayTitle = listItem[displayListKey[i]].toLowerCase().indexOf(splitString[i].toLowerCase()) > -1;
8277                         } else {
8278                             displayTitle = (splitString[i]) ? displayTitle && listItem[displayListKey[i]].toLowerCase().indexOf(splitString[i].toLowerCase().trim()) > -1 : displayTitle;
8279                         }
8280                     }
8281                 } else {
8282                     angular.forEach(displayListKey, function(value) {
8283                         if (!displayTitle) {
8284                             displayTitle = listItem[value];
8285                         } else {
8286                             displayTitle = displayTitle + (listItem[value] ? searchSeperator + ' ' + listItem[value] : '');
8287                         }
8288                     });
8289                 }
8290                 return displayTitle;
8291             }
8292             angular.forEach(list, function(listItem) {
8293                 var splitString = str.indexOf(searchSeperator) > -1 ? str.split(searchSeperator) : false;
8294                 var displayList = conditionCheck(searchSeperator, listItem, displayListKey, splitString)
8295                 for (var i = 0; i < keyArray.length; i++) {
8296                     searchLabel = keyArray[i];
8297                     if (listItem[searchLabel]) {
8298                         if (isContainsSearch) {
8299                             var displaySearchList = listItem[searchLabel].toLowerCase().indexOf(str.toLowerCase()) > -1;
8300                             if (splitString.length > 1) {
8301                                 displaySearchList = (splitString.length <= keyArray.length) ? displayList : false;
8302                             }
8303                             searchCondition = displaySearchList;
8304                         } else {
8305                             searchCondition = listItem[searchLabel].match(new RegExp('^' + str, 'gi'));
8306                         }
8307                         if (searchCondition) {
8308                             res.push({
8309                                 'title': conditionCheck(searchSeperator, listItem, displayListKey),
8310                                 'valueObj': listItem
8311                             });
8312                             break;
8313                         }
8314                     }
8315                 }
8316             });
8317             return res;
8318         };
8319     }]).directive('b2bSearchField', ['$filter', 'b2bFilterInputFilter', 'keymap', '$documentBind', '$isElement', '$document', 'events', '$timeout', function($filter, b2bFilterInput, keymap, $documentBind, $isElement, $document, events, $timeout) {
8320         return {
8321             restrict: 'A',
8322             scope: {
8323                 dataList: '=dropdownList',
8324                 onClickCallback: '&',
8325                 inputModel: '=',
8326                 configObj: '=',
8327                 objModel: '=',
8328                 inputDeny: '=?',
8329                 disabled: '=?'
8330             },
8331             replace: true,
8332             templateUrl: 'b2bTemplate/searchField/searchField.html',
8333             controller: ['$scope', function($scope) {
8334                 this.searchKeyArray = [];
8335                 if ($scope.configObj.searchKeys) {
8336                     this.searchKeyArray = $scope.configObj.searchKeys;
8337                 }
8338                 if (angular.isUndefined($scope.disabled)) {
8339                     $scope.disabled = false;
8340                 }
8341                 this.triggerInput = function(searchString) {
8342                     $scope.originalInputModel = searchString;
8343                     if (searchString === '') {
8344                         $scope.currentIndex = -1;
8345                         $scope.filterList = [];
8346                         $scope.showListFlag = false;
8347                     } else if (searchString !== '' && !$scope.isFilterEnabled) {
8348                         $scope.filterList = $filter('b2bFilterInput')($scope.dataList, searchString, this.searchKeyArray, $scope.configObj.displayListDataKey, $scope.configObj.isContainsSearch, $scope.configObj.searchSeperator);
8349                         $scope.showListFlag = true;
8350                     }
8351                 };
8352                 this.denyRegex = function() {
8353                     return $scope.inputDeny;
8354                 };
8355             }],
8356             link: function(scope, elem) {
8357                 scope.isFilterEnabled = false;
8358                 scope.showListFlag = false;
8359                 scope.currentIndex = -1;
8360                 scope.setCurrentIdx = function(idx) {
8361                     scope.currentIndex = idx;
8362                     if (idx > -1) {
8363                         scope.inputModel = scope.filterList[idx].title;
8364                         scope.objModel = scope.filterList[idx];
8365                     }
8366                 };
8367                 scope.isActive = function(index, dropdownLength) {
8368                     scope.dropdownLength = dropdownLength;
8369                     return scope.currentIndex === index;
8370                 };
8371                 scope.selectItem = function(idx) {
8372                     scope.setCurrentIdx(idx);
8373                     scope.onClickCallback({
8374                         value: scope.inputModel,
8375                         objValue: scope.objModel
8376                     });
8377                     scope.showListFlag = false;
8378                     $timeout(function() {
8379                         elem.find('div').find('input')[0].focus();
8380                     }, 150);
8381                 };
8382                 scope.startSearch = function() {
8383                     scope.onClickCallback({
8384                         value: scope.inputModel,
8385                         objValue: scope.objModel
8386                     });
8387                 };
8388                 scope.selectPrev = function() {
8389                     if (scope.currentIndex > 0 && scope.filterList.length > 0) {
8390                         scope.currentIndex = scope.currentIndex - 1;
8391                         scope.setCurrentIdx(scope.currentIndex);
8392                     } else if (scope.currentIndex === 0) {
8393                         scope.currentIndex = scope.currentIndex - 1;
8394                         scope.inputModel = scope.originalInputModel;
8395                         scope.isFilterEnabled = true;
8396                     }
8397                 };
8398                 scope.selectNext = function() {
8399                     if (scope.currentIndex < scope.configObj.noOfItemsDisplay - 1) {
8400                         if (scope.currentIndex < scope.filterList.length - 1) {
8401                             scope.currentIndex = scope.currentIndex + 1;
8402                             scope.setCurrentIdx(scope.currentIndex);
8403                         }
8404                     }
8405                 };
8406                 scope.selectCurrent = function() {
8407                     scope.selectItem(scope.currentIndex);
8408                 };
8409                 scope.selectionIndex = function(e) {
8410                     switch (e.keyCode) {
8411                         case keymap.KEY.DOWN:
8412                             events.preventDefault(e);
8413                             scope.isFilterEnabled = true;
8414                             scope.selectNext();
8415                             break;
8416                         case keymap.KEY.UP:
8417                             events.preventDefault(e);
8418                             scope.isFilterEnabled = true;
8419                             scope.selectPrev();
8420                             break;
8421                         case keymap.KEY.ENTER:
8422                             events.preventDefault(e);
8423                             scope.isFilterEnabled = true;
8424                             scope.selectCurrent();
8425                             break;
8426                         case keymap.KEY.ESC:
8427                             events.preventDefault(e);
8428                             scope.isFilterEnabled = false;
8429                             scope.showListFlag = false;
8430                             scope.inputModel = '';
8431                             break;
8432                         default:
8433                             scope.isFilterEnabled = false;
8434                             break;
8435                     }
8436                     if (elem[0].querySelector('.filtercontainer')) {
8437                         elem[0].querySelector('.filtercontainer').scrollTop = (scope.currentIndex - 1) * 35;
8438                     }
8439                 };
8440                 scope.$watch('filterList', function(newVal, oldVal) {
8441                     if (newVal !== oldVal) {
8442                         scope.currentIndex = -1;
8443                     }
8444                 });
8445                 scope.blurInput = function() {
8446                     $timeout(function() {
8447                         scope.showListFlag = false;
8448                     }, 150);
8449                 };
8450                 var outsideClick = function(e) {
8451                     var isElement = $isElement(angular.element(e.target), elem.find('ul').eq(0), $document);
8452                     if (!isElement && document.activeElement.tagName.toLowerCase() !== 'input') {
8453                         scope.showListFlag = false;
8454                         scope.$apply();
8455                     }
8456                 };
8457                 $documentBind.click('showListFlag', outsideClick, scope);
8458             }
8459         };
8460     }])
8461     .directive('b2bSearchInput', [function() {
8462         return {
8463             restrict: 'A',
8464             require: ['ngModel', '^b2bSearchField'],
8465             link: function(scope, elem, attr, ctrl) {
8466                 var ngModelCtrl = ctrl[0];
8467                 var attSearchBarCtrl = ctrl[1];
8468                 var REGEX = ctrl[1].denyRegex();
8469                 var parser = function(viewValue) {
8470                     attSearchBarCtrl.triggerInput(viewValue);
8471                     return viewValue;
8472                 };
8473                 ngModelCtrl.$parsers.push(parser);
8474
8475                 if (REGEX !== undefined || REGEX !== '') {
8476                     elem.bind('input', function() {
8477                         var inputString = ngModelCtrl.$viewValue && ngModelCtrl.$viewValue.replace(REGEX, '');
8478                         if (inputString !== ngModelCtrl.$viewValue) {
8479                             ngModelCtrl.$setViewValue(inputString);
8480                             ngModelCtrl.$render();
8481                             scope.$apply();
8482                         }
8483                     });
8484                 }
8485             }
8486         };
8487     }]);
8488
8489 /**
8490  * @ngdoc directive
8491  * @name Buttons, links & UI controls.att:Seek bar
8492  *
8493  * @description
8494  *  <file src="src/seekBar/docs/readme.md" />
8495  *
8496  * @usage
8497  *  Horizontal Seek Bar
8498  *  <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>
8499
8500  *  Vertical Seek Bar
8501  *  <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>
8502  *
8503  * @example
8504     <section id="code">   
8505         <b>HTML + AngularJS</b>
8506         <example module="b2b.att">
8507             <file src="src/seekBar/docs/demo.html" />
8508             <file src="src/seekBar/docs/demo.js" />
8509         </example>
8510     </section>
8511  */
8512
8513 angular.module('b2b.att.seekBar', ['b2b.att.utilities','b2b.att.position'])
8514         .constant('b2bSeekBarConfig', {
8515             'min': 0,
8516             'max': 100,
8517             'step': 1,
8518             'skipInterval': 1
8519         })
8520         .directive('b2bSeekBar', ['$documentBind', 'events', 'b2bSeekBarConfig', 'keymap', '$compile', function($documentBind, events, b2bSeekBarConfig, keymap, $compile) {
8521                 return {
8522                     restrict: 'AE',
8523                     replace: true,
8524                     require: 'ngModel',
8525                     templateUrl: 'b2bTemplate/seekBar/seekBar.html',
8526                     scope: {
8527                         onDragEnd: '&?',
8528                         onDragInit: '&?'
8529                     },
8530                     link: function(scope, elm, attr, ngModelCtrl) {
8531                         scope.isDragging = false;
8532                         scope.verticalSeekBar = false;
8533                         var min;
8534                         var max;
8535                         var step = b2bSeekBarConfig.step;
8536                         var skipInterval = b2bSeekBarConfig.skipInterval;
8537                         var knob = angular.element(elm[0].querySelector('.b2b-seek-bar-knob-container'));
8538                         var seekBarKnob = angular.element(knob[0].querySelector('.b2b-seek-bar-knob'));
8539                         var trackContainer = angular.element(elm[0].querySelector('.b2b-seek-bar-track-container'));
8540                         var trackFill = angular.element(elm[0].querySelector('.b2b-seek-bar-track-fill'));
8541                         var trackContainerRect = {};
8542                         var axisPosition;
8543                         var trackFillOrderPositioning;
8544
8545                         if (angular.isDefined(attr.vertical)) {
8546                             scope.verticalSeekBar = true;
8547                             axisPosition = "clientY";
8548                         }
8549                         else {
8550                             scope.verticalSeekBar = false;
8551                             axisPosition = "clientX";
8552                         }
8553                         var getValidStep = function(val) {
8554                             val = parseFloat(val);
8555                             // in case $modelValue came in string number
8556                             if (angular.isNumber(val)) {
8557                                 val = Math.round((val - min) / step) * step + min;
8558                                 return Math.round(val * 1000) / 1000;
8559                             }
8560                         };
8561
8562                         var getPositionToPercent = function(x) {
8563                             if (scope.verticalSeekBar) {
8564                                 return Math.max(0, Math.min(1, (trackContainerRect.bottom - x) / (trackFillOrderPositioning)));
8565                             }
8566                             else {
8567                                 return Math.max(0, Math.min(1, (x - trackContainerRect.left) / (trackFillOrderPositioning)));
8568                             }
8569                         };
8570
8571                         var getPercentToValue = function(percent) {
8572                             return (min + percent * (max - min));
8573                         };
8574
8575                         var getValueToPercent = function(val) {
8576                             return (val - min) / (max - min);
8577                         };
8578
8579                         var getValidMinMax = function(val) {
8580                             return Math.max(min, Math.min(max, val));
8581                         };
8582
8583                         var updateTrackContainerRect = function() {
8584                             trackContainerRect = trackContainer[0].getBoundingClientRect();
8585                             if (scope.verticalSeekBar) {
8586                                 if (!trackContainerRect.height) {
8587                                     trackFillOrderPositioning = trackContainer[0].scrollHeight;
8588                                 } else {
8589                                     trackFillOrderPositioning = trackContainerRect.height;
8590                                 }
8591                             }
8592                             else {
8593                                 if (!trackContainerRect.width) {
8594                                     trackFillOrderPositioning = trackContainer[0].scrollWidth;
8595                                 } else {
8596                                     trackFillOrderPositioning = trackContainerRect.width;
8597                                 }
8598
8599                             }
8600
8601                         };
8602
8603                         var updateKnobPosition = function(percent) {
8604                             var percentStr = (percent * 100) + '%';
8605                             if (scope.verticalSeekBar) {
8606                                 knob.css('bottom', percentStr);
8607                                 trackFill.css('height', percentStr);
8608                             }
8609                             else {
8610                                 knob.css('left', percentStr);
8611                                 trackFill.css('width', percentStr);
8612                             }
8613                         };
8614
8615                         var modelRenderer = function() {
8616                             if (isNaN(ngModelCtrl.$viewValue)) {
8617                                 ngModelCtrl.$viewValue = ngModelCtrl.$modelValue || min;
8618                             }
8619
8620                             var viewVal = ngModelCtrl.$viewValue;
8621                             scope.currentModelValue = viewVal;
8622
8623                             //wait for min, max and step to be set then only update UI to avoid NaN on percent calculation
8624                             if ((min || min === 0) && max && step) {
8625                                 updateKnobPosition(getValueToPercent(viewVal));
8626                             }
8627                         };
8628
8629                         var setModelValue = function(val) {
8630                             scope.currentModelValue = getValidMinMax(getValidStep(val));
8631                             ngModelCtrl.$setViewValue(scope.currentModelValue);
8632                         };
8633
8634                         var updateMin = function(val) {
8635                             min = parseFloat(val);
8636                             if(isNaN(min)){
8637                                min = b2bSeekBarConfig.min; 
8638                             }
8639                             modelRenderer();
8640                         };
8641
8642                         var updateMax = function(val) {
8643                             max = parseFloat(val);
8644                             if(isNaN(max)){
8645                                max = b2bSeekBarConfig.max; 
8646                             }
8647                             modelRenderer();
8648                         };
8649
8650                         var updateStep = function(val) {
8651                             step = parseFloat(val);
8652                             if (!attr['skipInterval']) {
8653                                 skipInterval = step;
8654                             }
8655                         };
8656
8657                         var updateSkipInterval = function(val) {
8658                             skipInterval = step * Math.ceil(val / (step!==0?step:1));
8659                         };
8660
8661                         angular.isDefined(attr.min) ? attr.$observe('min', updateMin) : updateMin(b2bSeekBarConfig.min);
8662                         angular.isDefined(attr.max) ? attr.$observe('max', updateMax) : updateMax(b2bSeekBarConfig.max);
8663                         if (angular.isDefined(attr.step)) {
8664                             attr.$observe('step', updateStep);
8665                         }
8666                         if (angular.isDefined(attr.skipInterval)) {
8667                             attr.$observe('skipInterval', updateSkipInterval);
8668                         }
8669                         scope.currentModelValue = getValidMinMax(getValidStep(min));
8670                         var onMouseDown = function(e) {
8671                             switch (e.which) {
8672                                 case 1:
8673                                     // left mouse button
8674                                     break;
8675                                 case 2:
8676                                 case 3:
8677                                     // right or middle mouse button
8678                                     return;
8679                             }
8680                             ;
8681
8682                             scope.isDragging = true;
8683                             seekBarKnob[0].focus();
8684                             updateTrackContainerRect();
8685                             if (attr['onDragInit']) {
8686                                 scope.onDragInit();
8687                             }
8688                             events.stopPropagation(e);
8689                             events.preventDefault(e);
8690                              scope.$apply(function() {
8691                                 setModelValue(getPercentToValue(getPositionToPercent(e[axisPosition])));
8692                             });
8693                         };
8694
8695                         var onMouseUp = function() {
8696
8697                             if (attr['onDragEnd']) {
8698                                 scope.onDragEnd();
8699                             }
8700                             scope.isDragging = false;
8701                             scope.$digest();
8702                         };
8703
8704                         var onMouseMove = function(e) {
8705                             if (scope.isDragging) {
8706                                 events.stopPropagation(e);
8707                                 events.preventDefault(e);
8708
8709                                 scope.$apply(function() {
8710                                     setModelValue(getPercentToValue(getPositionToPercent(e[axisPosition])));
8711                                 });
8712                             }
8713                         };
8714
8715                         function onKeyDown(e) {
8716                             if (!(e.keyCode)) {
8717                                 e.keyCode = e.which;
8718                             }
8719                             var updateStep;
8720                             switch (e.keyCode) {
8721                                 case keymap.KEY.LEFT:
8722                                     if (!scope.verticalSeekBar) {
8723                                         updateStep = -skipInterval;
8724                                     }
8725                                     break;
8726                                 case keymap.KEY.RIGHT:
8727                                     if (!scope.verticalSeekBar) {
8728                                         updateStep = skipInterval;
8729                                     }
8730                                     break;
8731                                 case keymap.KEY.UP:
8732                                     if (scope.verticalSeekBar) {
8733                                         updateStep = skipInterval;
8734                                     }
8735                                     break;
8736                                 case keymap.KEY.DOWN:
8737                                     if (scope.verticalSeekBar) {
8738                                         updateStep = -skipInterval;
8739                                     }
8740                                     break;
8741                                 default:
8742                                     return;
8743                             }
8744
8745                             if (updateStep) {
8746                                 events.stopPropagation(e);
8747                                 events.preventDefault(e);
8748                                 scope.$apply(function() {
8749                                     setModelValue(ngModelCtrl.$viewValue + updateStep);
8750                                 });
8751                                 if (attr['onDragEnd']) {
8752                                 scope.onDragEnd();
8753                             }
8754                             }
8755                         }
8756
8757                         elm.on('keydown', onKeyDown);
8758                         elm.on('mousedown', onMouseDown);
8759
8760                         $documentBind.event('mousemove', 'isDragging', onMouseMove, scope, true, 0);
8761                         $documentBind.event('mouseup', 'isDragging', onMouseUp, scope, true, 0);
8762
8763                         ngModelCtrl.$render = function() {
8764                             if (!scope.isDragging) {
8765                                 modelRenderer();
8766                             }
8767                         };
8768                         ngModelCtrl.$viewChangeListeners.push(modelRenderer);
8769                         ngModelCtrl.$formatters.push(getValidMinMax);
8770                         ngModelCtrl.$formatters.push(getValidStep);
8771                     }
8772                 };
8773             }]);
8774 /**
8775  * @ngdoc directive
8776  * @name Forms.att:selectorModule
8777  *
8778  * @description
8779  *  <file src="src/selectorModule/docs/readme.md" />
8780  *
8781  * @usage
8782  * <select name="myNameBig" type="large" b2b-dropdown ng-model="Controller Variable here">
8783  *   <option b2b-dropdown-list option-repeat="option data here" imgsrc="image path" value="value">List Text</option>
8784  * </select>
8785  *
8786  * <select name="myNameBig" type="large" b2b-dropdown ng-model="Controller Variable here">
8787  * <option b2b-dropdown-list option-repeat="option data here" imgsrc="image path" value="value">List Text</option>
8788  * </select>
8789  *
8790  * <select name="myNameBig" b2b-dropdown ng-model="Controller Variable here">
8791  *   <optgroup b2b-dropdown-group label="Group Label here">
8792  *     <option b2b-dropdown-list option-repeat="option data here" imgsrc="image path" value="value">List Text</option>
8793  *   </optgroup>
8794  * </select>
8795  *
8796  *  @example
8797  *  <section id="code">
8798         <example module="b2b.att">
8799             <file src="src/selectorModule/docs/demo.html" />
8800             <file src="src/selectorModule/docs/demo.js" />
8801        </example>
8802     </section>
8803  *
8804  */
8805 angular.module('b2b.att.selectorModule', ['b2b.att.dropdowns']);
8806 /**
8807  * @ngdoc directive
8808  * @name Layouts.att:separators
8809  *
8810  * @description
8811  *  <file src="src/separators/docs/readme.md" />
8812  *
8813  * @usage
8814
8815  *
8816  * @example
8817  *  <section id="code">   
8818  <b>HTML + AngularJS</b>
8819  <example module="b2b.att">
8820  <file src="src/separators/docs/demo.html" />
8821  <file src="src/separators/docs/demo.js" />
8822  </example>
8823  </section>
8824  *
8825  */
8826
8827 angular.module('b2b.att.separators', []);
8828 /**
8829  * @ngdoc directive
8830  * @name Buttons, links & UI controls.att:slider
8831  *
8832  * @description
8833  *  <file src="src/slider/docs/readme.md" />
8834  *
8835  * @usage
8836  *  <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>
8837  *
8838  * @example
8839     <section id="code">   
8840         <b>HTML + AngularJS</b>
8841         <example module="b2b.att">
8842             <file src="src/slider/docs/demo.html" />
8843             <file src="src/slider/docs/demo.js" />
8844         </example>
8845     </section>
8846  */
8847
8848 angular.module('b2b.att.slider', ['b2b.att.utilities'])
8849         .constant('SliderConfig', {
8850             'min': 0,
8851             'max': 100,
8852             'step': 1,
8853             'skipInterval': 1
8854         })
8855         .directive('b2bSlider', ['$documentBind', 'SliderConfig', 'keymap', '$compile', '$log', function($documentBind, SliderConfig, keymap, $compile, $log) {
8856                 return {
8857                     restrict: 'AE',
8858                     replace: true,
8859                     require: 'ngModel',
8860                     templateUrl: 'b2bTemplate/slider/slider.html',
8861                     scope: {
8862                         onDragEnd: '&?',
8863                         onDragInit: '&?',
8864                         trackFillColor: '=?',
8865                         preAriaLabel: '=?',
8866                         postAriaLabel: '=?',
8867                         onRenderEnd: '&?',
8868                         sliderSnapPoints: '=?',
8869                         customAriaLabel: '=?',
8870                         labelId: '@?'
8871                     },
8872                     link: function(scope, elm, attr, ngModelCtrl) {
8873                         scope.isDragging = false;
8874                         scope.verticalSlider = false;
8875                         var min;
8876                         var max;
8877                         var step = SliderConfig.step;
8878                         var skipInterval = SliderConfig.skipInterval;
8879                         var knob = angular.element(elm[0].querySelector('.slider-knob-container'));
8880                         var sliderKnob = angular.element(knob[0].querySelector('.slider-knob'));
8881                         var trackContainer = angular.element(elm[0].querySelector('.slider-track-container'));
8882                         var trackFill = angular.element(elm[0].querySelector('.slider-track-fill'));
8883                         var trackContainerRect = {};
8884                         var axisPosition = "clientX";
8885                         var trackFillOrderPositioning;
8886
8887                         //Forcefully disabling the vertical Slider code.
8888                         if (angular.isDefined(attr.vertical)) {
8889                             scope.verticalSlider = true;
8890                             axisPosition = "clientY";
8891                         }
8892
8893                         if (angular.isDefined(scope.noAriaLabel) && scope.noAriaLabel !== '') {
8894                             $log.warn('no-aria-label has been deprecated. This will be removed in v0.6.0.');
8895                         }
8896                         if (angular.isDefined(scope.preAriaLabel) && scope.preAriaLabel !== '') {
8897                             $log.warn('pre-aria-label has been deprecated. Please use label-id instead. This will be removed in v0.6.0.');
8898                         }
8899                         if (angular.isDefined(scope.customAriaLabel) && scope.customAriaLabel !== '') {
8900                             $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.');
8901                         }
8902
8903                         var binarySearchNearest = function (num, arr) {
8904                             var mid;
8905                             var lo = 0;
8906                             var hi = arr.length - 1;
8907                             
8908                             while (hi - lo > 1) {
8909                                 mid = Math.floor((lo + hi) / 2);
8910                                 if (arr[mid] < num) {
8911                                     lo = mid;
8912                                 } else {
8913                                     hi = mid;
8914                                 }
8915                             }
8916                             if (num - arr[lo] < arr[hi] - num) {
8917                                 return arr[lo];
8918                             }
8919                             return arr[hi];
8920                         };
8921                         
8922                         var getValidStep = function(val) {
8923                             val = parseFloat(val);
8924                             // in case $modelValue came in string number
8925                             if (!isNaN(val)) {
8926                                 
8927                                 if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {
8928                                     val = binarySearchNearest(val, scope.sliderSnapPoints);
8929                                 }
8930                                 else {
8931                                     val = Math.round((val - min) / step) * step + min;
8932                                 }
8933                                 
8934                                 return Math.round(val * 1000) / 1000;
8935                             }
8936                         };
8937
8938                         var getPositionToPercent = function(x) {
8939                             if (scope.verticalSlider) {
8940                                 return Math.max(0, Math.min(1, (trackContainerRect.bottom - x) / (trackFillOrderPositioning)));
8941                             }
8942                             else {
8943                                 return Math.max(0, Math.min(1, (x - trackContainerRect.left) / (trackFillOrderPositioning)));
8944                             }
8945                         };
8946
8947                         var getPercentToValue = function(percent) {
8948                             return (min + percent * (max - min));
8949                         };
8950
8951                         var getValueToPercent = function(val) {
8952                             return (val - min) / (max - min);
8953                         };
8954
8955                         var getValidMinMax = function(val) {
8956                             return Math.max(min, Math.min(max, val));
8957                         };
8958
8959                         var updateTrackContainerRect = function() {
8960                             trackContainerRect = trackContainer[0].getBoundingClientRect();
8961                             if (scope.verticalSlider) {
8962                                 if (!trackContainerRect.height) {
8963                                     trackFillOrderPositioning = trackContainer[0].scrollHeight;
8964                                 } else {
8965                                     trackFillOrderPositioning = trackContainerRect.height;
8966                                 }
8967                             }
8968                             else {
8969                                 if (!trackContainerRect.width) {
8970                                     trackFillOrderPositioning = trackContainer[0].scrollWidth;
8971                                 } else {
8972                                     trackFillOrderPositioning = trackContainerRect.width;
8973                                 }
8974
8975                             }
8976
8977                         };
8978
8979                         var updateKnobPosition = function(percent) {
8980                             var percentStr = (percent * 100) + '%';
8981                             if (scope.verticalSlider) {
8982                                 knob.css('bottom', percentStr);
8983                                 trackFill.css('height', percentStr);
8984                             }
8985                             else {
8986                                 knob.css('left', percentStr);
8987                                 trackFill.css('width', percentStr);
8988                             }
8989                         };
8990
8991                         var modelRenderer = function() {
8992
8993                             if(attr['disabled']){
8994                                 return;
8995                             }
8996
8997                             if (isNaN(ngModelCtrl.$viewValue)) {
8998                                 ngModelCtrl.$viewValue = ngModelCtrl.$modelValue || min;
8999                             }
9000
9001                             var viewVal = ngModelCtrl.$viewValue;
9002                             scope.currentModelValue = viewVal;
9003
9004                             //wait for min, max and step to be set then only update UI to avoid NaN on percent calculation
9005                             if ((min || min === 0) && max && step) {
9006                                 updateKnobPosition(getValueToPercent(viewVal));
9007                             }
9008                         };
9009
9010                         var setModelValue = function(val) {
9011                             scope.currentModelValue = getValidMinMax(getValidStep(val));
9012                             ngModelCtrl.$setViewValue(scope.currentModelValue);
9013                         };
9014
9015                         var updateMin = function(val) {
9016                             min = parseFloat(val);
9017                             if(isNaN(min)){
9018                                min = SliderConfig.min; 
9019                             }
9020                             scope.min = min;
9021                             modelRenderer();
9022                         };
9023
9024                         var updateMax = function(val) {
9025                             max = parseFloat(val);
9026                             if(isNaN(max)){
9027                                max = SliderConfig.max; 
9028                             }
9029                             scope.max = max;
9030                             modelRenderer();
9031                         };
9032
9033                         var updateStep = function(val) {
9034                             step = parseFloat(val);
9035                             if (!attr['skipInterval']) {
9036                                 skipInterval = step;
9037                             }
9038                         };
9039
9040                         var updateSkipInterval = function(val) {
9041                             skipInterval = step * Math.ceil(val / (step!==0?step:1));
9042                         };
9043
9044                         angular.isDefined(attr.min) ? attr.$observe('min', updateMin) : updateMin(SliderConfig.min);
9045                         angular.isDefined(attr.max) ? attr.$observe('max', updateMax) : updateMax(SliderConfig.max);
9046                         if (angular.isDefined(attr.step)) {
9047                             attr.$observe('step', updateStep);
9048                         }
9049                         if (angular.isDefined(attr.skipInterval)) {
9050                             attr.$observe('skipInterval', updateSkipInterval);
9051                         }
9052                         scope.currentModelValue = getValidMinMax(getValidStep(min));
9053                         var onMouseDown = function(e) {
9054
9055                             if(attr['disabled']){
9056                                 return;
9057                             }
9058
9059                             switch (e.which) {
9060                                 case 1:
9061                                     // left mouse button
9062                                     break;
9063                                 case 2:
9064                                 case 3:
9065                                     // right or middle mouse button
9066                                     return;
9067                             }
9068
9069                             scope.isDragging = true;
9070                             sliderKnob[0].focus();
9071                             updateTrackContainerRect();
9072                             if (attr['onDragInit']) {
9073                                 scope.onDragInit();
9074                             }
9075                             e.stopPropagation();
9076                             e.preventDefault();
9077                              scope.$apply(function() {
9078                                 setModelValue(getPercentToValue(getPositionToPercent(e[axisPosition])));
9079                             });
9080                         };
9081
9082                         var onMouseUp = function() {
9083
9084                             if (attr['onDragEnd']) {
9085                                 scope.onDragEnd();
9086                             }
9087                             scope.isDragging = false;
9088                             scope.$digest();
9089                         };
9090
9091                         var onMouseMove = function(e) {
9092                             if (scope.isDragging) {
9093                                 e.stopPropagation();
9094                                 e.preventDefault();
9095
9096                                 scope.$apply(function() {
9097                                     setModelValue(getPercentToValue(getPositionToPercent(e[axisPosition])));
9098                                 });
9099                             }
9100                         };
9101
9102                         function onKeyDown(e) {
9103                             if (!(e.keyCode)) {
9104                                 e.keyCode = e.which;
9105                             }
9106                             var updateStep;
9107                             switch (e.keyCode) {
9108                                 case keymap.KEY.DOWN:
9109                                 case keymap.KEY.LEFT:
9110                                     if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {
9111                                         var currentIndex = scope.sliderSnapPoints.indexOf(ngModelCtrl.$viewValue);
9112                                         if (currentIndex > 0) {
9113                                             currentIndex--;
9114                                         }
9115                                         updateStep = scope.sliderSnapPoints[currentIndex];
9116                                     }
9117                                     else {
9118                                         updateStep = ngModelCtrl.$viewValue - skipInterval;
9119                                     }
9120                                     break;
9121                                 case keymap.KEY.UP:
9122                                 case keymap.KEY.RIGHT:
9123                                     if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {
9124                                         var currentIndex = scope.sliderSnapPoints.indexOf(ngModelCtrl.$viewValue);
9125                                         if (currentIndex < scope.sliderSnapPoints.length-1) {
9126                                             currentIndex++;
9127                                         }
9128                                         updateStep = scope.sliderSnapPoints[currentIndex];
9129                                     }
9130                                     else {
9131                                         updateStep = ngModelCtrl.$viewValue + skipInterval;
9132                                     }
9133                                     break;
9134                                 case keymap.KEY.END:
9135                                     if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {
9136                                         currentIndex = scope.sliderSnapPoints.length-1;
9137                                         updateStep = scope.sliderSnapPoints[currentIndex];
9138                                     } else {
9139                                         setModelValue(scope.max);
9140                                     }
9141                                     e.preventDefault();
9142                                     e.stopPropagation();
9143                                     break;
9144                                 case keymap.KEY.HOME:
9145                                     if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {
9146                                         currentIndex = 0;
9147                                         updateStep = scope.sliderSnapPoints[currentIndex];
9148                                     } else {
9149                                         setModelValue(scope.min);
9150                                     }
9151                                     e.preventDefault();
9152                                     e.stopPropagation();
9153                                     break;
9154                                 default:
9155                                     return;
9156                             }
9157
9158                             if (angular.isNumber(updateStep) && !attr['disabled']) {
9159                                 e.stopPropagation();
9160                                 e.preventDefault();
9161                                 scope.$apply(function() {
9162                                     setModelValue(updateStep);
9163                                 });
9164                                 if (attr['onDragEnd']) {
9165                                     scope.onDragEnd();
9166                                 }
9167                             }
9168                         }
9169
9170                         elm.on('keydown', onKeyDown);
9171                         elm.on('mousedown', onMouseDown);
9172
9173                         $documentBind.event('mousemove', 'isDragging', onMouseMove, scope, true, 0);
9174                         $documentBind.event('mouseup', 'isDragging', onMouseUp, scope, true, 0);
9175
9176                         attr.$observe('disabled', function (disabled) {
9177                             if (disabled) {
9178                                 sliderKnob.removeAttr('tabindex');
9179                             } else {
9180                                 sliderKnob.attr('tabindex', '0');
9181                                 disabled = false;
9182                             }
9183
9184                             elm.toggleClass("slider-disabled", disabled);
9185
9186                             if (angular.isDefined(attr.hideDisabledKnob)) {
9187                                 scope.hideKnob = disabled;
9188                             }
9189                         });
9190
9191                         ngModelCtrl.$render = function() {
9192                             if (!scope.isDragging) {
9193                                 modelRenderer();
9194                                 if (attr['onRenderEnd'] && !attr['disabled']) {
9195                                     scope.onRenderEnd({currentModelValue: scope.currentModelValue});
9196                                 }
9197                             }
9198                         };
9199                         ngModelCtrl.$viewChangeListeners.push(modelRenderer);
9200                         ngModelCtrl.$formatters.push(getValidMinMax);
9201                         ngModelCtrl.$formatters.push(getValidStep);
9202                     }
9203                 };
9204             }]);
9205 /**
9206  * @ngdoc directive
9207  * @name Forms.att:spinButton
9208  *
9209  * @param {String} spin-button-id - An ID for the input field
9210  * @param {Integer} min - Minimum value for the input
9211  * @param {Integer} max - Maximum value for the input
9212  * @param {Integer} step - Value by which input field increments or decrements on up/down arrow keys
9213  * @param {Integer} page-step - Value by which input field increments or decrements on page up/down keys
9214  * @param {boolean} input-model-key - Default value for input field
9215  * @param {boolean} disabled-flag - A boolean that triggers directive once the min or max value has reached
9216  *
9217  * @description
9218  *  <file src="src/spinButton/docs/readme.md" />
9219  *
9220  * @example
9221  *  <section id="code">
9222         <example module="b2b.att">
9223             <file src="src/spinButton/docs/demo.html" />
9224             <file src="src/spinButton/docs/demo.js" />
9225        </example>
9226     </section>
9227  * 
9228  */
9229 angular.module('b2b.att.spinButton', ['b2b.att.utilities'])
9230     .constant('b2bSpinButtonConfig', {
9231         min: 1,
9232         max: 10,
9233         step: 1,
9234         pageStep: 10,
9235         inputModelKey: 'value',
9236         disabledFlag: false
9237     })
9238     .directive('b2bSpinButton', ['keymap', 'b2bSpinButtonConfig', 'b2bUserAgent', function (keymap, b2bSpinButtonConfig, userAgent) {
9239         return {
9240             restrict: 'EA',
9241             require: '?ngModel',
9242             transclude: false,
9243             replace: true,
9244             scope: {
9245                 min: '=min',
9246                 max: '=max',
9247                 step: '=step',
9248                 pageStep: '=pageStep',
9249                 spinButtonId: '@',
9250                 inputValue: '=ngModel',
9251                 inputModelKey: '@',
9252                 disabledFlag: "=?"
9253             },
9254             templateUrl: 'b2bTemplate/spinButton/spinButton.html',
9255             controller: ['$scope', '$element', '$attrs', function (scope, element, attrs) {
9256
9257                 scope.isMobile = userAgent.isMobile();
9258                 scope.notMobile = userAgent.notMobile();
9259
9260                 scope.min = attrs.min ? scope.min : b2bSpinButtonConfig.min;
9261                 scope.max = attrs.max ? scope.max : b2bSpinButtonConfig.max;
9262                 scope.step = attrs.step ? scope.step : b2bSpinButtonConfig.step;
9263                 scope.pageStep = attrs.pageStep ? scope.pageStep : b2bSpinButtonConfig.pageStep;
9264                 scope.inputModelKey = attrs.inputModelKey ? scope.inputModelKey : b2bSpinButtonConfig.inputModelKey;
9265                 scope.disabledFlag = attrs.disabledFlag ? scope.disabledFlag : b2bSpinButtonConfig.disabledFlag;
9266                 
9267                 if (scope.min < 0) {
9268                     scope.min = 0;
9269                 }
9270                 if (scope.max > 999) {
9271                     scope.max = 999;
9272                 }
9273
9274                 scope.isPlusDisabled = function () {
9275                     return (scope.disabledFlag || scope.inputValue[scope.inputModelKey] >= scope.max);
9276                 };
9277                 scope.isMinusDisabled = function () {
9278                     return (scope.disabledFlag || scope.inputValue[scope.inputModelKey] <= scope.min);
9279                 };
9280
9281                 scope.getValidateInputValue = function (value) {
9282                     if (value <= scope.min) {
9283                         return scope.min;
9284                     } else if (value >= scope.max) {
9285                         return scope.max;
9286                     } else {
9287                         return value;
9288                     }
9289                 };
9290
9291                 scope.plus = function () {
9292                     scope.inputValue[scope.inputModelKey] = scope.getValidateInputValue(parseInt(scope.inputValue[scope.inputModelKey], 10) + scope.step);
9293                 };
9294                 scope.minus = function () {
9295                     scope.inputValue[scope.inputModelKey] = scope.getValidateInputValue(parseInt(scope.inputValue[scope.inputModelKey], 10) - scope.step);
9296                 };
9297                 scope.pagePlus = function () {
9298                     scope.inputValue[scope.inputModelKey] = scope.getValidateInputValue(parseInt(scope.inputValue[scope.inputModelKey], 10) + scope.pageStep);
9299                 };
9300                 scope.pageMinus = function () {
9301                     scope.inputValue[scope.inputModelKey] = scope.getValidateInputValue(parseInt(scope.inputValue[scope.inputModelKey], 10) - scope.pageStep);
9302                 };
9303
9304             }],
9305             link: function (scope, elem) {
9306
9307                 if (scope.notMobile) {
9308                     angular.element(elem).find('input').attr('aria-live', 'off');
9309                     angular.element(elem).find('input').attr('role', 'spinbutton');
9310                 }
9311
9312                 elem.find('input').bind('keydown', function (e) {
9313                     if (e.keyCode === keymap.KEY.UP) {
9314                         scope.plus();
9315                     } else if (e.keyCode === keymap.KEY.DOWN){
9316                         scope.minus();
9317                     } else if (e.keyCode === keymap.KEY.HOME) {
9318                         scope.inputValue[scope.inputModelKey] = parseInt(scope.min);
9319                     } else if (e.keyCode === keymap.KEY.END) {
9320                         scope.inputValue[scope.inputModelKey] = parseInt(scope.max);
9321                     } else if (e.keyCode === keymap.KEY.PAGE_UP) {
9322                         scope.pagePlus();
9323                     } else if (e.keyCode === keymap.KEY.PAGE_DOWN) {
9324                         scope.pageMinus();
9325                     }
9326                     scope.$apply();
9327                 });
9328
9329                 elem.find('input').bind('keyup', function () {
9330                     if (scope.inputValue[scope.inputModelKey] === null ||
9331                         scope.inputValue[scope.inputModelKey] === '' ||
9332                         scope.inputValue[scope.inputModelKey] < scope.min) {
9333                         scope.inputValue[scope.inputModelKey] = scope.min;
9334                         scope.$apply();
9335                     } else if (angular.isUndefined(scope.inputValue[scope.inputModelKey]) || 
9336                                scope.inputValue[scope.inputModelKey] > scope.max) {
9337                         scope.inputValue[scope.inputModelKey] = scope.max;
9338                         scope.$apply();
9339                     }
9340                 });
9341
9342                 scope.focusInputSpinButton = function (evt) {
9343                     evt.preventDefault();
9344                     if (scope.notMobile) {
9345                         elem[0].querySelector('input').focus();
9346                     }
9347                 };
9348
9349             }
9350         };  
9351     }]);
9352 /** 
9353  * @ngdoc directive 
9354  * @name Template.att:Static Route
9355  * 
9356  * @description 
9357  *  <file src="src/staticRouteTemplate/docs/readme.md" /> 
9358  * 
9359  * @example 
9360  *  <section id="code"> 
9361         <example module="b2b.att"> 
9362             <file src="src/staticRouteTemplate/docs/demo.html" /> 
9363             <file src="src/staticRouteTemplate/docs/demo.js" /> 
9364        </example> 
9365     </section>    
9366  * 
9367  */
9368 angular.module('b2b.att.staticRouteTemplate', ['b2b.att.utilities'])
9369   
9370 /**
9371  * @ngdoc directive
9372  * @name Progress & usage indicators.att:statusTracker
9373  *
9374  * @scope
9375  * @param {array} statuses - An array of status objects
9376  * @description
9377  * <file src="src/statusTracker/docs/readme.md" />
9378  *
9379  * @usage
9380  *
9381 <div ng-controller="statusTrackerController">
9382     <b2b-status-tracker statuses="statusObject"></b2b-status-tracker>
9383 </div>
9384
9385  * @example
9386     <section id="code">   
9387         <b>HTML + AngularJS</b>
9388         <example module="b2b.att">
9389             <file src="src/statusTracker/docs/demo.html" />
9390             <file src="src/statusTracker/docs/demo.js" />
9391         </example>
9392     </section>
9393  */
9394
9395 angular.module('b2b.att.statusTracker', ['b2b.att.utilities'])
9396 .constant('b2bStatusTrackerConfig', {
9397     'maxViewItems': 3
9398 })
9399 .directive('b2bStatusTracker', ['b2bStatusTrackerConfig', function(b2bStatusTrackerConfig) {
9400         return {
9401             restrict: 'EA',
9402             transclude: false,
9403             replace: true,
9404             scope:{
9405                 statuses: '='
9406             },
9407             templateUrl: function(scope) {
9408                 return 'b2bTemplate/statusTracker/statusTracker.html';
9409             },
9410             link: function(scope, element, attr) {
9411                 scope.currentViewIndex = 0;
9412                 scope.b2bStatusTrackerConfig = b2bStatusTrackerConfig;
9413
9414                 scope.nextStatus = function() {
9415                     if (scope.currentViewIndex+1 <= scope.statuses.length) {
9416                         scope.currentViewIndex++;
9417                     }
9418                 };
9419                 scope.previousStatus = function() {
9420                     if (scope.currentViewIndex-1 >= 0) {
9421                         scope.currentViewIndex--;
9422                     }
9423                 };
9424                 scope.isInViewport = function(index) {
9425                     return (index < scope.currentViewIndex+3 && index >= scope.currentViewIndex);  // && index > scope.currentViewIndex-2
9426                 };
9427                 scope.currentStatus = function(index) {
9428                     if(index != undefined){
9429                         if(!scope.statuses[index].complete) {
9430                             if(index > 0 && scope.statuses[index-1].complete) {
9431                                 return true;
9432                             } else if(index == 0 && !scope.statuses[index].complete){
9433                                 return true;
9434                             } else {
9435                                 return false;
9436                             }
9437                         }
9438                     }
9439                 };
9440             }
9441         };
9442     }]);
9443 /**
9444  * @ngdoc directive
9445  * @name Progress & usage indicators.att:stepTracker
9446  *
9447  * @scope
9448  * @param {array} stepsItemsObject - An array of step objects
9449  * @param {Integer} currenIindex - This indicates the current running step
9450  * @param {Integer} viewportIndex - This is optional. This can used to start the view port rather than 1 item.
9451  * @description
9452  * <file src="src/stepTracker/docs/readme.md" />
9453  *
9454  * @usage
9455  *
9456  *  <b2b-step-tracker steps-items-object="stepsObject" current-index="currentStepIndex" step-indicator-heading="stepHeading"></b2b-step-tracker>
9457  *
9458
9459  * @example
9460     <section id="code">   
9461         <b>HTML + AngularJS</b>
9462         <example module="b2b.att">
9463             <file src="src/stepTracker/docs/demo.html" />
9464             <file src="src/stepTracker/docs/demo.js" />
9465         </example>
9466     </section>
9467  */
9468 angular.module('b2b.att.stepTracker', ['b2b.att.utilities'])
9469     .constant('b2bStepTrackerConfig', {
9470         'maxViewItems': 5
9471     })
9472     .directive('b2bStepTracker', ['b2bStepTrackerConfig', function(b2bStepTrackerConfig) {
9473         return {
9474             restrict: 'EA',
9475             transclude: true,
9476             scope:{
9477                 stepsItemsObject:"=",
9478                 currentIndex:"=",
9479                 viewportIndex:"=?"
9480             },
9481             templateUrl: 'b2bTemplate/stepTracker/stepTracker.html',
9482             link: function(scope, ele, attr) {
9483                 if (angular.isDefined(scope.viewportIndex)) {
9484                     scope.currentViewIndex = scope.viewportIndex - 1;   
9485                 }else{
9486                     scope.currentViewIndex = 0;
9487                 }
9488                
9489                scope.b2bStepTrackerConfig = b2bStepTrackerConfig;
9490                scope.nextStatus = function() {
9491                     if (scope.currentViewIndex+1 <= scope.stepsItemsObject.length) {
9492                         scope.currentViewIndex++;
9493                     }
9494                 };
9495                 scope.previousStatus = function() {
9496                     if (scope.currentViewIndex-1 >= 0) {
9497                         scope.currentViewIndex--;
9498                     }
9499                 };
9500                 scope.isInViewport = function(index) {
9501                     return (index < scope.currentViewIndex+b2bStepTrackerConfig.maxViewItems && index >= scope.currentViewIndex);
9502                 };
9503             }
9504         };
9505     }]);
9506      
9507 /**
9508  * @ngdoc directive
9509  * @name Buttons, links & UI controls.att:switches
9510  *
9511  * @description
9512  *  <file src="src/switches/docs/readme.md" />
9513  *
9514  * @usage
9515  *  
9516  *  <!-- On / Off Toggle switch -->
9517  *  <label for="switch1" class="controlled-text-wrap"> This is ON
9518  *      <input type="checkbox" role="checkbox" b2b-switches id="switch1" ng-model="switch1.value">
9519  *  </label>
9520  *
9521  *  <!-- On / Off Toggle switch and DISABLED -->
9522  *  <label for="switch2" class="controlled-text-wrap"> This is ON (disabled)
9523  *      <input type="checkbox" role="checkbox" b2b-switches id="switch2" ng-model="switch1.value" ng-disabled="true" >
9524  *  </label> 
9525  *
9526  *
9527  * @example
9528  *  <section id="code">
9529         <b>HTML + AngularJS</b>
9530         <example module="b2b.att">
9531             <file src="src/switches/docs/demo.js" />
9532             <file src="src/switches/docs/demo.html" />
9533         </example>
9534     </section>
9535  */
9536 angular.module('b2b.att.switches', ['b2b.att.utilities'])
9537     .directive('b2bSwitches', ['$compile', '$templateCache', 'keymap', 'events', function ($compile, $templateCache, keymap, events) {
9538         return {
9539             restrict: 'EA',
9540             require: ['ngModel'],
9541             link: function (scope, element, attrs, ctrl) {
9542                 var ngModelController = ctrl[0];
9543         
9544                 element.parent().bind("keydown", function (e) {
9545                     if (!attrs.disabled && (e.keyCode === keymap.KEY.ENTER || e.keyCode === keymap.KEY.SPACE)) {
9546                         events.preventDefault(e);
9547                         ngModelController.$setViewValue(!ngModelController.$viewValue);
9548                         element.prop("checked", ngModelController.$viewValue);
9549                     }
9550                 });
9551
9552                 element.wrap('<div class="btn-switch">');
9553                 //element.attr("tabindex", -1);
9554                 if (navigator.userAgent.match(/iphone/i)){
9555                     element.attr("aria-live", "polite");
9556                 }
9557                 else {
9558                     element.removeAttr('aria-live');
9559                 }
9560
9561                 var templateSwitch = angular.element($templateCache.get("b2bTemplate/switches/switches.html"));
9562                 if (angular.isDefined(attrs.typeSpanish)) {
9563                     templateSwitch = angular.element($templateCache.get("b2bTemplate/switches/switches-spanish.html"));
9564                 }
9565
9566                 templateSwitch = $compile(templateSwitch)(scope);
9567                 element.parent().append(templateSwitch);
9568
9569                 element.bind("focus", function (e) {
9570                     element.parent().addClass('focused');
9571                 });
9572
9573                 element.bind("blur", function (e) {
9574                     element.parent().removeClass('focused');
9575                 });
9576             }
9577         };
9578     }]);
9579 /**
9580  * @ngdoc directive
9581  * @name Messages, modals & alerts.att:tableMessages
9582  *
9583  * @description
9584  *  <file src="src/tableMessages/docs/readme.md" />
9585  *
9586  * @usage
9587     <!-- no matching results -->
9588     <b2b-table-message msg-type="'noMatchingResults'">
9589        <p>No Matching Results</p>
9590     </b2b-table-message>
9591   
9592     <!-- info could not load -->
9593     <b2b-table-message msg-type="'infoCouldNotLoad'" on-refresh-click="refreshClicked()">
9594     </b2b-table-message>
9595    
9596     <!-- magnify search -->
9597     <b2b-table-message msg-type="'magnifySearch'">
9598     </b2b-table-message>
9599    
9600     <!-- loading data -->
9601     <b2b-table-message msg-type="'loadingTable'">
9602           <!-- custom html -->
9603           <p>The data is currently loading...</p>
9604     </b2b-table-message>
9605
9606  * @example
9607     <section id="code">   
9608         <b>HTML + AngularJS</b>
9609         <example module="b2b.att">
9610             <file src="src/tableMessages/docs/demo.html" />
9611             <file src="src/tableMessages/docs/demo.js" />
9612         </example>
9613     </section>
9614  */
9615 angular.module('b2b.att.tableMessages', [])
9616     .directive('b2bTableMessage', [function() {
9617         return {
9618             restrict: 'AE',
9619             replace: true,
9620             transclude: true,
9621             scope: {
9622                 msgType: '=',
9623                 onRefreshClick: '&'
9624             },
9625             templateUrl: 'b2bTemplate/tableMessages/tableMessage.html',
9626             link: function(scope) {
9627                 scope.refreshAction = function(evt) {
9628                     scope.onRefreshClick(evt);
9629                 };
9630             }
9631         };
9632     }]);
9633
9634 /**
9635  * @ngdoc directive
9636  * @name Tabs, tables & accordions.att:tableScrollbar
9637  *
9638  * @description
9639  *  <file src="src/tableScrollbar/docs/readme.md" />
9640  *
9641  * @usage
9642  * 
9643 <b2b-table-scrollbar>
9644     <table>
9645         <thead type="header">
9646             <tr>
9647                 <th role="columnheader" scope="col" key="Id" id="col1">Id</th>
9648                 .....
9649             </tr>
9650         </thead>
9651         <tbody type="body">
9652             <tr>
9653                 <td id="rowheader0" headers="col1">1002</td>
9654                 .....
9655             </tr>
9656         </tbody>
9657     </table>
9658 </b2b-table-scrollbar>
9659  *
9660  * @example
9661  *  <section id="code">
9662         <example module="b2b.att">
9663             <file src="src/tableScrollbar/docs/demo.html" />
9664             <file src="src/tableScrollbar/docs/demo.js" />
9665        </example>
9666     </section>
9667  *
9668  */
9669 angular.module('b2b.att.tableScrollbar', [])
9670     .directive('b2bTableScrollbar', ['$timeout', function ($timeout) {
9671         return {
9672             restrict: 'E',
9673             scope: true,
9674             transclude: true,
9675             templateUrl: 'b2bTemplate/tableScrollbar/tableScrollbar.html',
9676             link: function (scope, element, attrs, ctrl) {
9677                 var firstThWidth, firstTdWidth, firstColumnWidth, firstColumnHeight, trHeight = 0;
9678                 var pxToScroll = '';
9679                 var tableElement = element.find('table');
9680                 var thElements = element.find('th');
9681                 var tdElements = element.find('td');
9682                 var innerContainer = angular.element(element[0].querySelector('.b2b-table-inner-container'));
9683                 var outerContainer = angular.element(element[0].querySelector('.b2b-table-scrollbar'));
9684
9685                 scope.disableLeft = true;
9686                 scope.disableRight = false;
9687
9688                 if (angular.isDefined(thElements[0])) {
9689                     firstThWidth = thElements[0].offsetWidth;
9690                 }
9691                 if (angular.isDefined(tdElements[0])) {
9692                     firstTdWidth = tdElements[0].offsetWidth;
9693                 }
9694                 firstColumnWidth = (firstThWidth > firstTdWidth) ? firstThWidth : firstTdWidth;
9695
9696                 innerContainer.css({
9697                     'padding-left': (firstColumnWidth + 2) + 'px'
9698                 });
9699
9700                 angular.forEach(element.find('tr'), function (eachTr, index) {
9701                     trObject = angular.element(eachTr);
9702                     firstColumn = angular.element(trObject.children()[0]);
9703
9704                     angular.element(firstColumn).css({
9705                         'margin-left': -(firstColumnWidth + 2) + 'px',
9706                         'width': (firstColumnWidth + 2) + 'px',
9707                         'position': 'absolute'
9708                     });
9709
9710                     trHeight = trObject[0].offsetHeight;
9711                     firstColumnHeight = firstColumn[0].offsetHeight;
9712                     if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
9713                         firstColumnHeight += 1;
9714                     }
9715
9716                     if (trHeight !== firstColumnHeight - 1) {
9717                         if (trHeight > firstColumnHeight) {
9718                             if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
9719                                 trHeight -= 1;
9720                             }
9721                             angular.element(firstColumn).css({
9722                                 'height': (trHeight + 1) + 'px'
9723                             });
9724                         } else {
9725                             angular.element(trObject).css({
9726                                 'height': (firstColumnHeight - 1) + 'px'
9727                             });
9728                         }
9729                     }
9730
9731                 });
9732
9733                 pxToScroll = outerContainer[0].offsetWidth - firstColumnWidth;
9734
9735                 scope.scrollLeft = function () {
9736                     innerContainer[0].scrollLeft = innerContainer[0].scrollLeft + 20 - pxToScroll;
9737                 };
9738
9739                 scope.scrollRight = function () {
9740                     innerContainer[0].scrollLeft = innerContainer[0].scrollLeft + pxToScroll - 20;
9741                 };
9742
9743                 scope.checkScrollArrows = function () {
9744                     if (innerContainer[0].scrollLeft == 0) {
9745                         scope.disableLeft = true;
9746                     } else {
9747                         scope.disableLeft = false;
9748                     }
9749
9750                     if (((innerContainer[0].offsetWidth - firstColumnWidth) + innerContainer[0].scrollLeft) >= tableElement[0].offsetWidth) {
9751                         scope.disableRight = true;
9752                     } else {
9753                         scope.disableRight = false;
9754                     }
9755                 };
9756
9757                 innerContainer.bind('scroll', function () {
9758                     $timeout(function () {
9759                         scope.checkScrollArrows();
9760                     }, 1);
9761                 });
9762
9763             }
9764         };
9765     }]);
9766 /**
9767  * @ngdoc directive
9768  * @name Tabs, tables & accordions.att:tables
9769  *
9770  * @description
9771  *  <file src="src/tables/docs/readme.md" />
9772  *
9773  * @usage
9774  *   
9775  Table
9776  <table b2b-table table-data="tableData" search-string="searchString">
9777     <thead b2b-table-row type="header">
9778         <tr>
9779             <th b2b-table-header key="requestId" default-sort="a" id="col1">Header 1</th>
9780             <th b2b-table-header key="requestType" sortable="false" id="col2">Header 2</th>
9781         </tr>
9782     </thead>
9783     <tbody b2b-table-row type="body" row-repeat="rowData in tableData">
9784         <tr>
9785             <td b2b-table-body id="rowheader{{$index}}" headers="col1" ng-bind="rowData['requestId']"> </td>
9786             <td b2b-table-body ng-bind="rowData['requestType']"></td>
9787         </tr>
9788     </tbody>
9789  </table>
9790  *
9791  * @example
9792  *  <section id="code">
9793         <example module="b2b.att">
9794             <file src="src/tables/docs/demo.html" />
9795             <file src="src/tables/docs/demo.js" />
9796        </example>
9797     </section>
9798  *
9799  */
9800 angular.module('b2b.att.tables', ['b2b.att.utilities'])
9801     .constant('b2bTableConfig', {
9802         defaultSortPattern: false, // true for descending & false for ascending
9803         highlightSearchStringClass: 'tablesorter-search-highlight',
9804         zebraStripCutOff: 6, // > zebraStripCutOff
9805         tableBreakpoints: [ // breakpoints are >= min and < max
9806             {
9807                 min: 0,
9808                 max: 480,
9809                 columns: 2
9810             },
9811             {
9812                 min: 480,
9813                 max: 768,
9814                 columns: 3
9815             },
9816             {
9817                 min: 768,
9818                 max: 1025,
9819                 columns: 5
9820             },
9821             {
9822                 min: 1025,
9823                 max: 1920,
9824                 columns: 7
9825             }
9826         ]
9827     })
9828     .directive('b2bTable', ['$filter', '$window', 'b2bTableConfig', '$timeout', function ($filter, $window, b2bTableConfig, $timeout) {
9829         return {
9830             restrict: 'EA',
9831             replace: true,
9832             transclude: true,
9833             scope: {
9834                 tableData: "=",
9835                 viewPerPage: "=",
9836                 currentPage: "=",
9837                 totalPage: "=",
9838                 searchCategory: "=",
9839                 searchString: "=",
9840                 nextSort: '='
9841             },
9842             require: 'b2bTable',
9843             templateUrl: 'b2bTemplate/tables/b2bTable.html',
9844             controller: ['$scope', '$attrs', function ($scope, $attrs) {
9845                 this.headers = [];
9846                 this.currentSortIndex = null;
9847                 this.responsive = $scope.responsive = $attrs.responsive;
9848                 this.maxTableColumns = -1;
9849                 this.totalTableColums = 0;
9850                 this.active = $scope.active = false;
9851                 this.responsiveRowScopes = [];
9852                 this.hideColumnPriority = [];
9853                 this.hiddenColumn = [];
9854                 this.setIndex = function (headerScope, priority) {
9855                     this.headers.push(headerScope);
9856                     if (this.responsive) {
9857                         this.totalTableColums++;
9858                         if (!isNaN(priority)) {
9859                             this.hideColumnPriority[priority] = this.totalTableColums - 1;
9860                         } else {
9861                             this.hideColumnPriority[this.totalTableColums - 1] = this.totalTableColums - 1;
9862                         }
9863                     }
9864                     return this.totalTableColums - 1;
9865                 };
9866                 this.getIndex = function (headerName) {
9867                     for (var i = 0; i < this.headers.length; i++) {
9868                         if (this.headers[i].headerName === headerName) {
9869                             return this.headers[i].index;
9870                         }
9871                     }
9872                     return null;
9873                 };
9874                 this.setResponsiveRow = function (responsiveRowScope) {
9875                     this.responsiveRowScopes.push(responsiveRowScope);
9876                 }
9877                 $scope.nextSort = '';
9878                 this.sortData = function (columnIndex, reverse, externalSort) {
9879                     if ($scope.$parent && $scope.$parent !== undefined) {
9880                         $scope.$parent.columnIndex = columnIndex;
9881                         $scope.$parent.reverse = reverse;
9882                     }
9883                     this.currentSortIndex = columnIndex;
9884                     if (externalSort === true) {
9885                         if (!reverse) {
9886                             $scope.nextSort = 'd'
9887                         } else {
9888                             $scope.nextSort = 'a'
9889                         }
9890                     }
9891                     $scope.currentPage = 1;
9892                     this.resetSortPattern();
9893                 };
9894                 this.getSearchString = function () {
9895                     return $scope.searchString;
9896                 };
9897                 this.resetSortPattern = function () {
9898                     for (var i = 0; i < this.headers.length; i++) {
9899                         var currentScope = this.headers[i];
9900                         if (currentScope.index !== this.currentSortIndex) {
9901                             currentScope.resetSortPattern();
9902                         }
9903                     }
9904                 };
9905
9906                 $scope.$watch('nextSort', function (val) {
9907                     if ($scope.$parent && $scope.$parent !== undefined) {
9908                         $scope.$parent.nextSort = val;
9909                     }
9910
9911                 });
9912             }],
9913             link: function (scope, elem, attr, ctrl) {
9914                 scope.searchCriteria = {};
9915                 scope.tableBreakpoints = attr.tableConfig ? scope.$parent.$eval(attr.tableConfig) : angular.copy(b2bTableConfig.tableBreakpoints);
9916                 scope.$watchCollection('tableData', function (value) {
9917                     if (value && !isNaN(value.length)) {
9918                         scope.totalRows = value.length;
9919                     }
9920                 });
9921                 scope.$watch('currentPage', function (val) {
9922                     if (scope.$parent && scope.$parent !== undefined) {
9923                         scope.$parent.currentPage = val;
9924                     }
9925
9926                 });
9927                 scope.$watch('viewPerPage', function (val) {
9928                     if (scope.$parent && scope.$parent !== undefined) {
9929                         scope.$parent.viewPerPage = val;
9930                     }
9931                 });
9932                 scope.$watch('totalRows', function (val) {
9933                     if (scope.$parent && scope.$parent !== undefined) {
9934                         if (val > b2bTableConfig.zebraStripCutOff) {
9935                             scope.$parent.zebraStripFlag = true;
9936                         } else {
9937                             scope.$parent.zebraStripFlag = false;
9938                         }
9939                     }
9940                 });
9941                 scope.$watch(function () {
9942                     return scope.totalRows / scope.viewPerPage;
9943                 }, function (value) {
9944                     if (!isNaN(value)) {
9945                         scope.totalPage = Math.ceil(value);
9946                         scope.currentPage = 1;
9947                     }
9948                 });
9949                 var searchValCheck = function (val) {
9950                     if (angular.isDefined(val) && val !== null && val !== "") {
9951                         return true;
9952                     }
9953                 };
9954                 var setSearchCriteria = function (v1, v2) {
9955                     if (searchValCheck(v1) && searchValCheck(v2)) {
9956                         var index = ctrl.getIndex(v2);
9957                         scope.searchCriteria = {};
9958                         if (index !== null) {
9959                             scope.searchCriteria[index] = v1;
9960                         }
9961                     } else if (searchValCheck(v1) && (!angular.isDefined(v2) || v2 === null || v2 === "")) {
9962                         scope.searchCriteria = {
9963                             $: v1
9964                         };
9965                     } else {
9966                         scope.searchCriteria = {};
9967                     }
9968                 };
9969                 scope.$watch('searchCategory', function (newVal, oldVal) {
9970                     if (newVal !== oldVal) {
9971                         setSearchCriteria(scope.searchString, newVal);
9972                     }
9973                 });
9974                 scope.$watch('searchString', function (newVal, oldVal) {
9975                     if (newVal !== oldVal) {
9976                         setSearchCriteria(newVal, scope.searchCategory);
9977                     }
9978                 });
9979                 scope.$watchCollection('searchCriteria', function (val) {
9980                     if (scope.$parent && scope.$parent !== undefined) {
9981                         scope.$parent.searchCriteria = val;
9982                     }
9983                     scope.totalRows = scope.tableData && ($filter('filter')(scope.tableData, val, false)).length || 0;
9984                     scope.currentPage = 1;
9985                 });
9986                 var window = angular.element($window);
9987                 var findMaxTableColumns = function () {
9988                     var windowWidth;
9989                     windowWidth = $window.innerWidth;
9990                     ctrl.maxTableColumns = -1;
9991                     for (var i in scope.tableBreakpoints) {
9992                         if (windowWidth >= scope.tableBreakpoints[i].min && windowWidth < scope.tableBreakpoints[i].max) {
9993                             ctrl.maxTableColumns = scope.tableBreakpoints[i].columns;
9994                             break;
9995                         }
9996                     }
9997                     if (ctrl.maxTableColumns > -1 && ctrl.totalTableColums > ctrl.maxTableColumns) {
9998                         ctrl.active = true;
9999                     } else {
10000                         ctrl.active = false;
10001                     }
10002                     for (var i in ctrl.responsiveRowScopes) {
10003                         ctrl.responsiveRowScopes[i].setActive(ctrl.active);
10004                     }
10005                 };
10006                 var findHiddenColumn = function () {
10007                     var columnDiffenence = ctrl.maxTableColumns > -1 ? ctrl.totalTableColums - ctrl.maxTableColumns : 0;
10008                     ctrl.hiddenColumn = [];
10009                     if (columnDiffenence > 0) {
10010                         var tempHideColumnPriority = angular.copy(ctrl.hideColumnPriority);
10011                         for (var i = 0; i < columnDiffenence; i++) {
10012                             ctrl.hiddenColumn.push(tempHideColumnPriority.pop());
10013                         }
10014                     }
10015                 };
10016                 var resizeListener = function () {
10017                     findMaxTableColumns();
10018                     findHiddenColumn();
10019                 };
10020                 if (ctrl.responsive) {
10021                     window.bind('resize', function () {
10022                         resizeListener();
10023                         scope.$apply();
10024                     });
10025                     $timeout(function () {
10026                         resizeListener();
10027                     }, 100);
10028                 }
10029             }
10030         };
10031     }])
10032     .directive('b2bTableRow', [function () {
10033         return {
10034             restrict: 'EA',
10035             compile: function (elem, attr) {
10036                 if (attr.type === 'header') {
10037                     angular.noop();
10038                 } else if (attr.type === 'body') {
10039                     var html = elem.children();
10040                     if (attr.rowRepeat) {
10041                         html.attr('ng-repeat', attr.rowRepeat.concat(" | orderBy : columnIndex : reverse | filter : searchCriteria : false "));
10042                     }
10043                     html.attr('ng-class', "{'odd': $odd && zebraStripFlag}");
10044                     html.attr('class', 'data-row');
10045                     html.attr('b2b-responsive-row', '{{$index}}');
10046                     elem.append(html);
10047                 }
10048             }
10049         };
10050     }])
10051     .directive('b2bTableHeader', ['b2bTableConfig', function (b2bTableConfig) {
10052         return {
10053             restrict: 'EA',
10054             replace: true,
10055             transclude: true,
10056             scope: {
10057                 sortable: '@',
10058                 defaultSort: '@',
10059                 index: '@key'
10060             },
10061             require: '^b2bTable',
10062             templateUrl: function (elem, attr) {
10063                 if (attr.sortable === 'false') {
10064                     return 'b2bTemplate/tables/b2bTableHeaderUnsortable.html';
10065                 } else {
10066                     return 'b2bTemplate/tables/b2bTableHeaderSortable.html';
10067                 }
10068             },
10069             link: function (scope, elem, attr, ctrl) {
10070                 var reverse = b2bTableConfig.defaultSortPattern;
10071                 scope.headerName = elem.text();
10072                 scope.headerId = elem.attr('id');
10073                 scope.sortPattern = null;
10074                 var priority = parseInt(attr.priority, 10);
10075                 scope.columnIndex = ctrl.setIndex(scope, priority);
10076
10077                 scope.isHidden = function () {
10078                     return (ctrl.hiddenColumn.indexOf(scope.columnIndex) > -1);
10079                 };
10080
10081                 scope.$watch(function () {
10082                     return elem.text();
10083                 }, function (value) {
10084                     scope.headerName = value;
10085                 });
10086                 scope.sort = function (sortType) {
10087                     if (typeof sortType === 'boolean') {
10088                         reverse = sortType;
10089                     }
10090                     ctrl.sortData(scope.index, reverse, false);
10091                     scope.sortPattern = reverse ? 'descending' : 'ascending';
10092                     reverse = !reverse;
10093                 };
10094                 scope.$watch(function () {
10095                     return ctrl.currentSortIndex;
10096                 }, function (value) {
10097                     if (value !== scope.index) {
10098                         scope.sortPattern = null;
10099                     }
10100                 });
10101
10102                 if (scope.sortable === undefined || scope.sortable === 'true' || scope.sortable === true) {
10103                     scope.sortable = 'true';
10104                 } else if (scope.sortable === false || scope.sortable === 'false') {
10105                     scope.sortable = 'false';
10106                 }
10107
10108                 if (scope.sortable !== 'false') {
10109                     if (scope.defaultSort === 'A' || scope.defaultSort === 'a') {
10110                         scope.sort(false);
10111                     } else if (scope.defaultSort === 'D' || scope.defaultSort === 'd') {
10112                         scope.sort(true);
10113                     }
10114                 }
10115                 scope.resetSortPattern = function () {
10116                     reverse = b2bTableConfig.defaultSortPattern;
10117                 };
10118             }
10119         };
10120     }])
10121     .directive('b2bResponsiveRow', ['$templateCache', '$timeout', '$compile', function ($templateCache, $timeout, $compile) {
10122         return {
10123             restrict: 'EA',
10124             require: '^b2bTable',
10125             controller: ['$scope', function ($scope) {
10126                 this.rowValues = $scope.rowValues = [];
10127                 this.setRowValues = function (rowValue) {
10128                     this.rowValues.push(rowValue);
10129                 };
10130                 var columnIndexCounter = -1;
10131                 this.getIndex = function () {
10132                     columnIndexCounter++;
10133                     return columnIndexCounter;
10134                 };
10135             }],
10136             link: function (scope, elem, attr, ctrl) {
10137                 if (ctrl.responsive) {
10138                     scope.rowIndex = attr.b2bResponsiveRow;
10139                     scope.active = false;
10140                     scope.expandFlag = false;
10141                     scope.headerValues = ctrl.headers;
10142                     ctrl.setResponsiveRow(scope);
10143                     var firstTd = elem.find('td').eq(0);
10144                     scope.setActive = function (activeFlag) {
10145                         scope.active = activeFlag;
10146                         if (scope.active) {
10147                             elem.addClass('has-button');
10148                             firstTd.attr('role', 'rowheader');
10149                             firstTd.parent().attr('role', 'row');
10150                         } else {
10151                             elem.removeClass('has-button');
10152                             firstTd.removeAttr('role');
10153                             firstTd.parent().removeAttr('role');
10154                         }
10155                     };
10156                     scope.toggleExpandFlag = function (expandFlag) {
10157                         if (angular.isDefined(expandFlag)) {
10158                             scope.expandFlag = expandFlag;
10159                         } else {
10160                             scope.expandFlag = !scope.expandFlag;
10161                         }
10162                         if (scope.expandFlag) {
10163                             elem.addClass('opened');
10164                         } else {
10165                             elem.removeClass('opened');
10166                         }
10167                     };
10168
10169                     firstTd.attr('scope', 'row');
10170                     firstTd.addClass('col-1');
10171                     scope.$on('$destroy', function () {
10172                         elem.next().remove();
10173                     });
10174                     $timeout(function () {
10175                         scope.firstTdId = firstTd.attr('id');
10176                         var firstTdContent = firstTd.html();
10177                         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>';
10178                         toggleButtonTemplate = $compile(toggleButtonTemplate)(scope);
10179                         firstTd.html('');
10180                         firstTd.prepend(toggleButtonTemplate);
10181
10182                         var template = $templateCache.get('b2bTemplate/tables/b2bResponsiveRow.html');
10183                         template = $compile(template)(scope);
10184                         elem.after(template);
10185                     }, 100);
10186                 }
10187             }
10188         };
10189     }])
10190     .directive('b2bResponsiveList', ['$templateCache', '$timeout', '$compile', function ($templateCache, $timeout, $compile) {
10191         return {
10192             restrict: 'EA',
10193             require: '^b2bTable',
10194             link: function (scope, elem, attr, ctrl) {
10195                 scope.columnIndex = parseInt(attr.b2bResponsiveList, 10);
10196                 scope.isVisible = function () {
10197                     return (ctrl.hiddenColumn.indexOf(scope.columnIndex) > -1);
10198                 };
10199             }
10200         };
10201     }])
10202     .directive('b2bTableBody', ['$filter', '$timeout', 'b2bTableConfig', function ($filter, $timeout, b2bTableConfig) {
10203         return {
10204             restrict: 'EA',
10205             require: ['^b2bTable', '?^b2bResponsiveRow'],
10206             scope: true,
10207             replace: true,
10208             transclude: true,
10209             templateUrl: 'b2bTemplate/tables/b2bTableBody.html',
10210             link: function (scope, elem, attr, ctrl) {
10211                 var b2bTableCtrl = ctrl[0];
10212                 var b2bResponsiveRowCtrl = ctrl[1];
10213                 var highlightSearchStringClass = b2bTableConfig.highlightSearchStringClass;
10214                 var searchString = "";
10215                 var wrapElement = function (elem) {
10216                     var text = elem.text();
10217                     elem.html($filter('b2bHighlight')(text, searchString, highlightSearchStringClass));
10218                 };
10219                 var traverse = function (elem) {
10220                     var innerHtml = elem.children();
10221                     if (innerHtml.length > 0) {
10222                         for (var i = 0; i < innerHtml.length; i++) {
10223                             traverse(innerHtml.eq(i));
10224                         }
10225                     } else {
10226                         wrapElement(elem);
10227                         return;
10228                     }
10229                 };
10230                 var clearWrap = function (elem) {
10231                     var elems = elem.find('*');
10232                     for (var i = 0; i < elems.length; i++) {
10233                         if (elems.eq(i).attr('class') && elems.eq(i).attr('class').indexOf(highlightSearchStringClass) !== -1) {
10234                             var text = elems.eq(i).text();
10235                             elems.eq(i).replaceWith(text);
10236                         }
10237                     }
10238                 };
10239                 if (b2bResponsiveRowCtrl) {
10240                     scope.columnIndex = b2bResponsiveRowCtrl.getIndex();
10241                     scope.isHidden = function () {
10242                         return (b2bTableCtrl.hiddenColumn.indexOf(scope.columnIndex) > -1);
10243                     };
10244                 }
10245                 $timeout(function () {
10246                     var actualHtml = elem.children();
10247                     scope.$watch(function () {
10248                         return b2bTableCtrl.getSearchString();
10249                     }, function (val) {
10250                         searchString = val;
10251                         clearWrap(elem);
10252                         if (actualHtml.length > 0) {
10253                             traverse(elem);
10254                         } else {
10255                             wrapElement(elem);
10256                         }
10257                     });
10258                     if (b2bResponsiveRowCtrl) {
10259                         b2bResponsiveRowCtrl.setRowValues(elem.html());
10260                     }
10261                 }, 50);
10262             }
10263         };
10264     }])
10265     .directive('b2bTableSort', ['b2bTableConfig','$timeout', function (b2bTableConfig,$timeout) {
10266         return {
10267             restrict: 'EA',
10268             replace: true,
10269             require: '^b2bTable',
10270             link: function (scope, elem, attr, ctrl) {
10271                 var initialSort = '',
10272                     nextSort = '',
10273                     tempsort = '';
10274                 initialSort = attr.initialSort;
10275
10276                 scope.sortTable = function (msg) {
10277                     $timeout(function(){
10278                         if (nextSort.length > 0) {
10279
10280                         if (nextSort === 'd' || nextSort === 'D') {
10281                             tempsort = nextSort
10282                             ctrl.sortData(msg, true, true);
10283                             nextSort = 'a';
10284                              $timeout(function(){
10285                                 if(!angular.isUndefined(elem[0].querySelector('.sortButton')) || elem[0].querySelector('.sortButton') !== null ){
10286                                     angular.element(elem[0].querySelector('.sortButton'))[0].focus();
10287                                 }   
10288                             },100);
10289                             
10290                         } else {
10291                             tempsort = nextSort
10292                             ctrl.sortData(msg, false, true);
10293                             nextSort = 'd';
10294                              $timeout(function(){
10295                                 if(!angular.isUndefined(elem[0].querySelector('.sortButton')) || elem[0].querySelector('.sortButton') !== null ){
10296                                     angular.element(elem[0].querySelector('.sortButton'))[0].focus();
10297                                 }   
10298                             },100);
10299                         }
10300                     } else if (initialSort.length > 0) {
10301
10302                         if (initialSort === 'd' || initialSort === 'D') {
10303                             tempsort = nextSort
10304                             ctrl.sortData(msg, true, true);
10305                             nextSort = 'a';
10306                             $timeout(function(){
10307                                 if(!angular.isUndefined(elem[0].querySelector('.sortButton')) || elem[0].querySelector('.sortButton') !== null ){
10308                                     angular.element(elem[0].querySelector('.sortButton'))[0].focus();
10309                                 }   
10310                             },100);
10311                              
10312                         } else {
10313                             tempsort = nextSort
10314                             ctrl.sortData(msg, false, true);
10315                             nextSort = 'd';
10316                              $timeout(function(){
10317                                 if(!angular.isUndefined(elem[0].querySelector('.sortButton')) || elem[0].querySelector('.sortButton') !== null ){
10318                                     angular.element(elem[0].querySelector('.sortButton'))[0].focus();
10319                                 }   
10320                             },100);
10321
10322                              
10323                         }
10324                     }
10325                     },10)
10326
10327                 };
10328
10329                 scope.sortDropdown = function(msg) {
10330
10331                     if(tempsort==='') {
10332
10333                         tempsort='a'
10334                     }
10335                     if(tempsort === 'd' || tempsort === 'D' ) {
10336                         ctrl.sortData(msg, true, false);       
10337                     } else {
10338                        ctrl.sortData(msg, false, false);
10339                     }
10340
10341                 };
10342             }
10343         };
10344     }]);
10345 /**
10346  * @ngdoc directive
10347  * @name Tabs, tables & accordions.att:tabs
10348  *
10349  * @description
10350  *  <file src="src/tabs/docs/readme.md" />
10351  *
10352  * @usage
10353  *  <b2b-tabset tab-id-selected="activeTabsId">
10354         <b2b-tab ng-repeat="tab in gTabs" tab-item="tab" 
10355                  id="{{tab.uniqueId}}" aria-controls="{{tab.tabPanelId}}"
10356                  ng-disabled="tab.disabled">
10357             {{tab.title}}
10358         </b2b-tab>
10359     </b2b-tabset>
10360  *
10361  * @example
10362  *  <section id="code">
10363         <example module="b2b.att">
10364             <file src="src/tabs/docs/demo.html" />
10365             <file src="src/tabs/docs/demo.js" />
10366         </example>
10367     </section>
10368  *
10369  */
10370
10371 angular.module('b2b.att.tabs', ['b2b.att.utilities'])
10372     .directive('b2bTabset', function () {
10373         return {
10374             restrict: 'EA',
10375             transclude: true,
10376             replace: true,
10377             scope: {
10378                 tabIdSelected: '='
10379             },
10380             templateUrl: 'b2bTemplate/tabs/b2bTabset.html',
10381             controller: ['$scope', function ($scope) {
10382
10383                 this.setTabIdSelected = function (tab) {
10384                     $scope.tabIdSelected = tab.id;
10385                 };
10386
10387                 this.getTabIdSelected = function () {
10388                     return $scope.tabIdSelected;
10389                 };
10390             }]
10391         };
10392     })
10393     .directive('b2bTab', ['keymap', function (keymap) {
10394         return {
10395             restrict: 'EA',
10396             transclude: true,
10397             replace: true,
10398             require: '^b2bTabset',
10399             scope: {
10400                 tabItem: "="
10401             },
10402             templateUrl: 'b2bTemplate/tabs/b2bTab.html',
10403             controller: [function(){}],
10404             link: function (scope, element, attr, b2bTabsetCtrl) {
10405
10406                 if (scope.tabItem && !scope.tabItem.disabled) {
10407                     scope.tabItem.disabled = false;
10408                 }
10409
10410                 scope.isTabActive = function () {
10411                     return (scope.tabItem.id === b2bTabsetCtrl.getTabIdSelected());
10412                 };
10413
10414                 scope.clickTab = function () {
10415                     if (attr.disabled) {
10416                         return;
10417                     }
10418                     b2bTabsetCtrl.setTabIdSelected(scope.tabItem);
10419                 };
10420
10421                 scope.nextKey = function () {
10422                     var el = angular.element(element[0])[0];
10423                     var elementToFocus = null;
10424                     while (el && el.nextElementSibling) {
10425                         el = el.nextElementSibling;
10426                         if (!el.querySelector('a').disabled) {
10427                             elementToFocus = el.querySelector('a');
10428                             break;
10429                         }
10430                     }
10431
10432                     if (!elementToFocus) {
10433                         var childTabs = element.parent().children();
10434                         for (var i = 0; i < childTabs.length; i++) {
10435                             if (!childTabs[i].querySelector('a').disabled) {
10436                                 elementToFocus = childTabs[i].querySelector('a');
10437                                 break;
10438                             }
10439                         }
10440                     }
10441
10442                     if (elementToFocus) {
10443                         elementToFocus.focus();
10444                     }
10445                 };
10446
10447                 scope.previousKey = function () {
10448                     var el = angular.element(element[0])[0];
10449                     var elementToFocus = null;
10450
10451                     while (el && el.previousElementSibling) {
10452                         el = el.previousElementSibling;
10453                         if (!el.querySelector('a').disabled) {
10454                             elementToFocus = el.querySelector('a');
10455                             break;
10456                         }
10457                     }
10458
10459                     if (!elementToFocus) {
10460                         var childTabs = element.parent().children();
10461                         for (var i = childTabs.length - 1; i > 0; i--) {
10462                             if (!childTabs[i].querySelector('a').disabled) {
10463                                 elementToFocus = childTabs[i].querySelector('a');
10464                                 break;
10465                             }
10466                         }
10467                     }
10468
10469                     if (elementToFocus) {
10470                         elementToFocus.focus();
10471                     }
10472                 };
10473
10474                 angular.element(element[0].querySelector('a')).bind('keydown', function (evt) {
10475
10476                     if (!(evt.keyCode)) {
10477                         evt.keyCode = evt.which;
10478                     }
10479
10480                     switch (evt.keyCode) {
10481                         case keymap.KEY.RIGHT:
10482                             evt.preventDefault();
10483                             scope.nextKey();
10484                             break;
10485
10486                         case keymap.KEY.LEFT:
10487                             evt.preventDefault();
10488                             scope.previousKey();
10489                             break;
10490
10491                         default:;
10492                     }
10493                 });
10494             }
10495         };
10496     }]);
10497 /**
10498  * @ngdoc directive
10499  * @name Messages, modals & alerts.att:tagBadges
10500  *
10501  * @description
10502  *  <file src="src/tagBadges/docs/readme.md" />
10503  *
10504  * @example
10505  *  <section id="code">
10506         <example module="b2b.att">
10507             <file src="src/tagBadges/docs/demo.html" />
10508             <file src="src/tagBadges/docs/demo.js" />
10509         </example>
10510     </section>
10511  *
10512  */
10513 angular.module('b2b.att.tagBadges', ['b2b.att.utilities'])
10514         .directive('b2bTagBadge',['$timeout',function($timeout){
10515             return{
10516                 restrict: 'EA',
10517                 link: function(scope,elem,attr,ctrl){
10518                     elem.addClass('b2b-tags');
10519                     if(angular.element(elem[0].querySelector('.icon-primary-close')).length>0) {
10520                         var item = angular.element(elem[0].querySelector('.icon-primary-close'));
10521                         item.bind('click',function(){
10522                         elem.css({'height':'0','width':'0','padding':'0','border':'0'});
10523                         elem.attr('tabindex','0');
10524                         elem[0].focus();
10525                         item.parent().remove();
10526                         elem[0].bind('blur',function(){
10527                             elem[0].remove();
10528                         });
10529                     });  
10530                     }
10531                   
10532
10533
10534
10535                 }
10536             };   
10537 }]);
10538 /**
10539  * @ngdoc directive
10540  * @name Forms.att:textArea
10541  *
10542  * @description
10543  *  <file src="src/textArea/docs/readme.md" />
10544  *
10545  * @usage
10546  *  <textarea b2b-reset b2b-reset-textarea ng-model="textAreaModel" ng-disabled="disabled" ng-trim="false" placeholder="{{placeholderText}}" rows="{{textAreaRows}}" maxlength="{{textAreaMaxlength}}" role="textarea"></textarea>
10547  *
10548  * @example
10549     <section id="code">
10550         <b>HTML + AngularJS</b>
10551         <example module="b2b.att">
10552             <file src="src/textArea/docs/demo.html" />
10553             <file src="src/textArea/docs/demo.js" />
10554         </example>
10555     </section>
10556  */
10557 angular.module('b2b.att.textArea', ['b2b.att.utilities'])
10558
10559 .directive('b2bResetTextarea', [ function () {
10560     return {
10561         restrict: 'A',
10562         require: 'b2bReset',
10563         link: function (scope, element, attrs, ctrl) {
10564
10565             var resetButton = ctrl.getResetButton();
10566             
10567             var computeScrollbarAndAddClass = function () {
10568                 if (element.prop('scrollHeight') > element[0].clientHeight) {
10569                     element.addClass('hasScrollbar');
10570                 } else {
10571                     element.removeClass('hasScrollbar');
10572                 }
10573             };
10574             
10575             computeScrollbarAndAddClass();
10576
10577             element.on('focus keyup', function(){
10578                 computeScrollbarAndAddClass();
10579             });
10580         }
10581     };
10582 }]);
10583
10584 /**
10585  * @ngdoc directive
10586  * @name Forms.att:tooltipsForForms
10587  *
10588  * @description
10589  *  <file src="src/tooltipsForForms/docs/readme.md" />
10590  *
10591  * @example
10592  <example module="b2b.att">
10593  <file src="src/tooltipsForForms/docs/demo.html" />
10594  <file src="src/tooltipsForForms/docs/demo.js" />
10595  </example>
10596  */
10597 angular.module('b2b.att.tooltipsForForms', ['b2b.att.utilities'])
10598         .directive('b2bTooltip', ['$document', '$window', '$isElement', function ($document, $window, $isElement) {
10599                 return  {
10600                     restrict: 'A',
10601                     link: function (scope, elem, attr, ctrl) {
10602                         var icon = elem[0].querySelector('a.tooltip-element');
10603                         var btnIcon = elem[0].querySelector('.btn.tooltip-element');
10604                         var tooltipText = elem[0].querySelector('.helpertext');
10605                         var tooltipWrapper = elem[0].querySelector('.tooltip-size-control');
10606                         if (elem.hasClass('tooltip-onfocus')) {
10607                             var inputElm = angular.element(elem[0].querySelector("input"));
10608                             var textAreaElm = angular.element(elem[0].querySelector("textarea"));
10609                         }
10610                         angular.element(icon).attr({'aria-expanded': false});
10611                         angular.element(btnIcon).attr({'aria-expanded': false});
10612                         var calcTooltip = function () {
10613                             if (!elem.hasClass('tooltip active')) {
10614                                 if (elem.hasClass('tooltip-onfocus')) {
10615                                     angular.element(elem[0].querySelector("input")).triggerHandler('focusout');
10616                                 }
10617                                 if (elem.hasClass('tooltip-onclick')) {
10618                                     return false;
10619                                 }
10620                                 angular.element(icon).removeClass('active');
10621                                 angular.element(icon).attr({'aria-expanded': true});
10622                                 angular.element(icon).attr({'aria-describedby': angular.element(tooltipText).attr('id')});
10623                                 angular.element(tooltipText).attr({'aria-hidden': false});
10624                                 elem.addClass('active');
10625
10626                                 var tooltipIconPos = angular.element(icon).prop('offsetLeft'),
10627                                         tooltipPosition = angular.element(tooltipText).prop('offsetWidth') / 2,
10628                                         tipOffset = (tooltipIconPos - 30) - tooltipPosition,
10629                                         maxRightPos = (($window.innerWidth - 72) - (tooltipPosition * 2)) - 14.5;
10630
10631                                 if ($window.innerWidth >= '768') {
10632                                     if (tipOffset < 0) {// if icon on far left side of page
10633                                         tipOffset = 15;
10634                                     }
10635                                     else if (tooltipIconPos > maxRightPos) {// if icon is far right side of page
10636                                         tipOffset = maxRightPos;
10637                                     }
10638                                     else {// if tooltip in the middle somewhere
10639                                         tipOffset = tipOffset;
10640                                     }
10641                                     angular.element(tooltipWrapper).css({left: tipOffset + 'px'});
10642                                 }
10643                             }
10644                         };
10645                         
10646                         // TOOLTIP LINK ONCLICK AND FOCUS
10647                         angular.element(icon).on('click mouseover mouseout focus blur', function (e) {
10648                             if (e.type == 'mouseover') {
10649                                 calcTooltip();
10650                             }
10651                             else if (e.type == 'mouseout' && elem.hasClass('active')) {
10652                                 if (!elem.hasClass('activeClick')) {
10653                                     angular.element(tooltipText).attr({
10654                                         'aria-hidden': true,
10655                                         'tabindex': '-1'
10656                                     });
10657                                     elem.removeClass('active');
10658                                 } else if (elem.hasClass('activeClick') && navigator.userAgent.match(/iphone/i)) {
10659                                     elem.removeClass('active activeClick');
10660                                 }
10661                             }
10662
10663                             else {
10664                                 if (elem.hasClass('activeClick')) {
10665                                     angular.element(icon).attr({'aria-expanded': false});
10666                                     angular.element(tooltipText).attr({'aria-hidden': true});
10667                                     angular.element(icon).removeAttr('aria-describedby');
10668                                     elem.removeClass('activeClick active');
10669                                     e.preventDefault();
10670                                 }
10671                                 else if (e.type == 'click') {
10672                                     elem.addClass('activeClick');
10673                                     calcTooltip();
10674                                     e.preventDefault();
10675                                 }
10676                                 else {
10677                                     angular.element(icon).on('keydown', function (e) {
10678                                         if (e.keyCode == '32') {
10679                                             (elem.hasClass('active')) ? elem.removeClass('active') : elem.addClass('value');
10680                                             angular.element(icon).triggerHandler('click');
10681                                             e.preventDefault();
10682                                         } else if (e.keyCode == '27') {
10683                                             (elem.hasClass('active')) ? elem.removeClass('active activeClick') : elem.addClass('value');
10684                                         }
10685                                     });
10686                                     e.preventDefault();
10687                                 }
10688                             }
10689                             e.preventDefault();
10690                         });
10691
10692                         // TOOLTIP BUTTON INSIDE A TEXT FIELD
10693                         angular.element(btnIcon).on('click', function (e) {
10694                             var $this = angular.element(this);
10695                             if ($this.hasClass('active') && elem.hasClass('tooltip-onclick')) {
10696                                 elem.removeClass('active');
10697                                 $this.removeClass('active');
10698                                 angular.element(tooltipText).removeAttr('aria-live');
10699                                 $this.attr({'aria-expanded': 'false'});
10700                                 $this.removeAttr('aria-describedby');
10701                             } else {
10702                                 elem.addClass('active');
10703                                 $this.addClass('active');
10704                                 $this.attr({'aria-expanded': 'true', 'aria-describedby': angular.element(tooltipText).attr('id')});
10705                                 angular.element(tooltipText).attr({'aria-live': 'polite'});
10706                             }
10707                         });
10708
10709                         angular.element(btnIcon).on('blur', function (e) {
10710                             var $this = angular.element(this);
10711                             if ($this.hasClass('active') && elem.hasClass('tooltip-onclick')) {
10712                                 elem.removeClass('active');
10713                                 $this.removeClass('active');
10714                                 angular.element(tooltipText).removeAttr('aria-live');
10715                                 $this.attr({'aria-expanded': 'false'});
10716                                 $this.removeAttr('aria-describedby');
10717                             }
10718                         });  
10719
10720                         angular.element(btnIcon).on('keydown', function (e) {
10721                             var $this = angular.element(this);
10722                             if (e.keyCode == '27') {
10723                                 var $this = angular.element(this);
10724                                 if ($this.hasClass('active') && elem.hasClass('tooltip-onclick')) {
10725                                     elem.removeClass('active');
10726                                     $this.removeClass('active');
10727                                     angular.element(tooltipText).removeAttr('aria-live');
10728                                     $this.attr({'aria-expanded': 'false'});
10729                                     $this.removeAttr('aria-describedby');
10730                                 }
10731                             }
10732                         });
10733
10734                         // close all tooltips if clicking something else
10735                         $document.bind('click', function (e) {
10736                             var isElement = $isElement(angular.element(e.target), elem, $document);
10737                             if (!isElement) {
10738                                 elem.removeClass('active');
10739                                 angular.element(elem[0].querySelector('.tooltip-element')).removeClass('active');
10740                                 angular.element(tooltipText).removeAttr('aria-live');
10741                                 angular.element(elem[0].querySelector('.tooltip-element')).attr({'aria-expanded': 'false'});
10742                                 angular.element(elem[0].querySelector('.tooltip-element')).removeAttr('aria-describedby');
10743                             };
10744                         });
10745
10746                         angular.element(inputElm).on('keydown', function (e) {
10747                             if (e.keyCode == '27'){
10748                                 elem.removeClass('active');
10749                                 angular.element(tooltipText).css('display', 'none');
10750                                 angular.element(tooltipText).removeAttr('aria-live');
10751
10752                                 if (angular.element(this).attr('aria-describedby') === undefined){
10753
10754                                 }
10755
10756                                 else if ((spaceIndex = angular.element(this).attr('aria-describedby').lastIndexOf(' ')) >= 0){
10757
10758                                     var describedByValue = angular.element(this).attr('aria-describedby').slice(0, spaceIndex);
10759
10760                                     angular.element(this).attr('aria-describedby', describedByValue);
10761
10762                                 }
10763                                 else {
10764                                     angular.element(this).removeAttr('aria-describedby');
10765                                 }
10766                             }
10767                         });
10768
10769                         angular.element(textAreaElm).on('keydown', function (e) {
10770                             if (e.keyCode == '27'){
10771                                 elem.removeClass('active');
10772                                 angular.element(tooltipText).css('display', 'none');
10773                                 angular.element(tooltipText).removeAttr('aria-live');
10774                                 if (angular.element(this).attr('aria-describedby') === undefined){
10775
10776                                 }
10777
10778                                 else if ((spaceIndex = angular.element(this).attr('aria-describedby').lastIndexOf(' ')) >= 0){
10779
10780                                     var describedByValue = angular.element(this).attr('aria-describedby').slice(0, spaceIndex);
10781
10782                                     angular.element(this).attr('aria-describedby', describedByValue);
10783
10784                                 }
10785                                 else {
10786                                     angular.element(this).removeAttr('aria-describedby');
10787                                 }
10788                             }
10789                         });
10790
10791                         // TOOLTIP TRIGGERED AUTOMATICALLY INSIDE A TEXT FIELD
10792                         angular.element(inputElm).on('focus', function (e) {
10793                             var allTooltip = $document[0].querySelectorAll('[class*="tooltip"]');
10794                             for (var i = 0; i < allTooltip.length; i++) {
10795                                 if (angular.element(allTooltip[i]).hasClass('active')) {
10796                                     angular.element(allTooltip[i]).triggerHandler('click');
10797                                 }
10798                             };
10799                             angular.element(this).attr({'aria-describedby': angular.element(tooltipText).attr('id')});
10800                             angular.element(tooltipText).css('display', 'block');
10801                             angular.element(tooltipText).attr({'aria-live': 'polite'});
10802                             elem.addClass('active');
10803                         });
10804                         angular.element(inputElm).on('blur', function (e) {
10805                             elem.removeClass('active');
10806                             angular.element(tooltipText).css('display', 'none');
10807                             angular.element(tooltipText).removeAttr('aria-live');
10808                             angular.element(this).removeAttr('aria-describedby');
10809                         });
10810
10811                         // TOOLTIP TRIGGERED AUTOMATICALLY INSIDE A TEXTAREA
10812                         angular.element(textAreaElm).on('focus', function (e) {
10813                             var allTooltip = $document[0].querySelectorAll('[class*="tooltip"]');
10814                             for (var i = 0; i < allTooltip.length; i++) {
10815                                 if (angular.element(allTooltip[i]).hasClass('active')) {
10816                                     angular.element(allTooltip[i]).triggerHandler('click');
10817                                 }
10818                             };
10819                             elem.addClass('active');
10820                             angular.element(tooltipText).css('display', 'block');
10821                             angular.element(tooltipText).attr({'aria-live': 'polite'});
10822                             angular.element(this).attr({'aria-describedby': angular.element(tooltipText).attr('id')});
10823                         });
10824                         angular.element(textAreaElm).on('blur', function (e) {
10825                             elem.removeClass('active');
10826                             angular.element(tooltipText).css('display', 'none');
10827                             angular.element(tooltipText).removeAttr('aria-live');
10828                             angular.element(this).removeAttr('aria-describedby');
10829                         });
10830                     }
10831                 };
10832             }]); 
10833 /**
10834  * @ngdoc directive
10835  * @name Navigation.att:TreeNavigation
10836  *
10837  *
10838  * @scope
10839  * @param {String} setRole - This value needs to be "tree". This is required to incorporate CATO requirements.
10840  * @param {Boolean} groupIt - This value needs to be "false" for top-level tree rendered.
10841  *
10842  * @description
10843  *  <file src="src/treeNav/docs/readme.md" />
10844  *
10845  * @usage
10846  *      <div class="b2b-tree">
10847  *                <b2b-tree-nav collection="treeStructure" set-role="tree" group-it="false"></b2b-tree-nav>
10848  *            </div>
10849  * @example
10850  *  <section id="code">
10851         <example module="b2b.att">
10852             <file src="src/treeNav/docs/demo.html" />
10853             <file src="src/treeNav/docs/demo.js" />
10854        </example>
10855     </section>
10856  *
10857  */
10858 angular.module('b2b.att.treeNav', ['b2b.att.utilities'])
10859     .directive('b2bTreeNav', function () {
10860         return {
10861             restrict: "E",
10862             replace: true,
10863             scope: {
10864                 collection: '=',
10865                 groupIt: '=',
10866                 setRole: '@'
10867             },
10868             templateUrl: function (element, attrs) {
10869                 if (attrs.groupIt === 'true') {
10870                     return "b2bTemplate/treeNav/groupedTree.html";
10871                 } else {
10872                     return "b2bTemplate/treeNav/ungroupedTree.html";
10873                 }
10874             },
10875             link: function (scope) {               
10876                 if (!(scope.setRole === 'tree')) {
10877                     scope.setRole = 'group';
10878                 }             
10879             }
10880         }
10881     })
10882     .directive('b2bMember', ['$compile', '$timeout', 'keymap', function ($compile, $timeout, keymap) {
10883         return {
10884             restrict: "E",
10885             replace: true,
10886             scope: {
10887                 member: '=',
10888                 groupIt: '='
10889             },
10890             templateUrl: 'b2bTemplate/treeNav/treeMember.html',
10891             link: function (scope, element, attrs) {
10892                 scope.elemArr = [];
10893                 var removeRootTabIndex = function (elem) {
10894                     if (elem.parent().parent().eq(0).hasClass('b2b-tree')) {
10895                         elem.attr('tabindex', -1);                        
10896                         return;
10897                     }
10898                     removeRootTabIndex(elem.parent());
10899                 };
10900                 scope.$watch('member.child', function(newVal, oldVal){                  
10901                     if(newVal !== oldVal){
10902                         scope.showChild();
10903                     };
10904                 });
10905                 scope.showChild = function () {
10906                         if (!element.hasClass('grouped')) {
10907                             if (angular.isArray(scope.member.child) && scope.member.child.length > 0 && (scope.member.divide === undefined || scope.member.child.length < scope.member.divide)) {
10908                                 scope.groupIt = false;
10909                                 element.addClass('grouped');
10910                                 element.append("<b2b-tree-nav collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-nav>");
10911                                 $compile(element.contents())(scope);
10912                                 if(scope.member.active && scope.member.active === true){
10913                                     element.find('i').eq(0).removeClass('icon-primary-collapsed');
10914                                 };
10915                                 if(scope.member.selected && scope.member.selected === true){
10916                                     element.attr('aria-selected', true);
10917                                     element.attr('tabindex', 0);
10918                                     removeRootTabIndex(element);
10919                                 };
10920                                 if(scope.member.active && scope.member.active == undefined){
10921                                     element.find('i').eq(0).addClass('icon-primary-collapsed');
10922                                 };
10923                             } else if (scope.member.child && scope.member.divide && scope.member.child.length > scope.member.divide) {
10924                                 element.addClass('grouped');
10925                                 scope.groupIt = true;
10926                                 // FILTER - GROUPBY - APPROACH 
10927                                 var j = 0;
10928                                 var grpName = '';
10929                                 if(scope.member.child[0].groupName !== undefined){
10930                                     grpName = scope.member.child[0].groupName;
10931                                 }
10932                                 else{
10933                                     var toSlice = scope.member.child[0].name.search(' ');
10934                                     grpName = scope.member.child[0].name.slice(0, toSlice);
10935                                 }
10936
10937                                 for (i = 0; i < scope.member.child.length; i += scope.member.divide) {
10938                                     j = 0;
10939                                     for (j = j + i; j < (i + scope.member.divide); j++) {                                        
10940                                         if (j === scope.member.child.length) {
10941                                             scope.member.child[j - 1].grpChild = grpName + ' ' + (i + 1) + ' - ' + (scope.member.child.length);
10942                                             break;
10943                                             
10944                                             if(scope.member.child[j-1].active && scope.member.child[j-1].active===true){
10945                                                 scope.member.child[j-1].activeGrp = true;
10946                                             };
10947                                             
10948                                         }
10949                                         if (i + scope.member.divide > scope.member.child.length) {
10950                                             scope.member.child[j].grpChild = grpName + ' ' + (i + 1) + ' - ' + (scope.member.child.length);
10951                                             if(scope.member.child[j].active && scope.member.child[j].active===true){
10952                                                 scope.member.child[j].activeGrp = true;
10953                                             };
10954
10955                                         } else {
10956                                             scope.member.child[j].grpChild = grpName + ' ' + (i + 1) + ' - ' + (i + scope.member.divide);
10957                                             if(scope.member.child[j].active && scope.member.child[j].active===true){
10958                                                 scope.member.child[j].activeGrp = true;
10959                                             };
10960                                         }
10961                                     }
10962                                 }
10963                                 if(scope.member.divide){
10964                                     element.append("<b2b-tree-nav collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-nav>");
10965                                 } else {
10966                                     element.append("<b2b-tree-nav collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-nav>");
10967                                 }
10968                                 $compile(element.contents())(scope);
10969                                 if(scope.member.active && scope.member.active === true){
10970                                     element.find('i').eq(0).removeClass('icon-primary-collapsed');
10971                                 };
10972                                 if(scope.member.selected && scope.member.selected === true){
10973                                     element.attr('aria-selected', true);
10974                                 };
10975                                 if( scope.member.active && scope.member.active == undefined){
10976                                     element.find('i').eq(0).addClass('icon-primary-collapsed');
10977                                 };
10978                             }
10979                         }
10980                 };
10981                 //Below condition opens node for opening on json load.
10982                 if(scope.member.active && scope.member.active == true){
10983                     scope.showChild();
10984                 };
10985                 if(scope.member.active == undefined && !element.find('a').eq(0).hasClass('active') && scope.member.child !== undefined){
10986                     element.find('i').eq(0).addClass('icon-primary-collapsed');
10987                 }
10988                 else if(scope.member.child == undefined){
10989                     element.find('i').eq(0).addClass('icon-primary-circle');
10990                 };
10991                 element.bind('keydown', function (evt) {
10992                     switch (evt.keyCode) {
10993                         case keymap.KEY.ENTER:
10994                             if (element.hasClass('bg') && scope.member.onSelect !== undefined) {
10995                                 scope.member.onSelect(scope.member);
10996                             }
10997                             evt.stopPropagation();
10998                             break;
10999                         default: 
11000                             break;                            
11001                     }
11002                     
11003                 });
11004                 //else getting true in every case .. so better use switch case .. that makes more sense you dumb.
11005                 element.bind('click', function (evt) {
11006                     scope.showChild();
11007                     var expandFunc = scope.member.onExpand;
11008                     
11009                     //onSelect
11010                         if (element.hasClass('bg') && scope.member.onSelect !== undefined) {
11011                                     scope.member.onSelect(scope.member);
11012                                 }
11013                         if (element.find('a').eq(0).hasClass('active') && scope.member.onExpand !== undefined) {
11014                            var eValue = scope.member.onExpand(scope.member);
11015                         }
11016                         if (!element.find('a').eq(0).hasClass('active') && scope.member.onCollapse !== undefined) {
11017                             scope.member.onCollapse(scope.member);
11018                         }
11019                 });
11020             }
11021         }
11022 }])
11023     .directive('b2bTreeLink', ['keymap', '$timeout', function (keymap, $timeout) {
11024         return {
11025             restrict: 'A',
11026             link: function (scope, element, attr, ctrl) {
11027                 var rootE, parentE, upE, downE;
11028                 var closeOthersUp = function (elem,isKeyPress,passiveClose) {
11029                     //For accordion functionality on sibling nodes
11030                     if (elem.find('a').eq(0).hasClass('active')) {
11031                         activeToggle(elem,isKeyPress,passiveClose);
11032                         return;
11033                     }
11034                     if (elem.hasClass('bg') && !isKeyPress) {
11035                         elem.removeClass('bg');
11036                         if (elem.attr('aria-selected')) {
11037                             elem.attr('aria-selected', 'false');
11038                         }                        
11039                     }
11040                     if (elem[0].previousElementSibling !== null) {
11041                         closeOthersUp(angular.element(elem[0].previousElementSibling),isKeyPress);
11042                     }
11043                 };
11044                 var closeOthersDown = function (elem,isKeyPress,passiveClose) {
11045                     //For accordion functionality on sibling nodes
11046                     if (elem.find('a').eq(0).hasClass('active')) {
11047                         activeToggle(elem,isKeyPress,passiveClose);
11048                         return;
11049                     }
11050                     if (elem.hasClass('bg') && !isKeyPress) {
11051                         elem.removeClass('bg');
11052                         if (elem.attr('aria-selected')) {
11053                             elem.attr('aria-selected', 'false');
11054                         }                        
11055                     }
11056                     if (elem[0].nextElementSibling !== null) {
11057                         closeOthersDown(angular.element(elem[0].nextElementSibling),isKeyPress);
11058                     }
11059                 };
11060
11061                
11062                 var removeBackground = function(elem){
11063
11064                     if(elem.hasClass('b2b-tree')){
11065                         angular.element(elem[0].getElementsByClassName('bg')).removeClass('bg');
11066                         return;
11067                     }else{
11068                         removeBackground(elem.parent().parent());
11069                     }
11070
11071                 };
11072
11073 /**
11074 * These two functions used for setting heights on parent nodes as the child node closes
11075 * Retaining this code for future reference
11076
11077                 var addParentHeight = function(e, h) {
11078                     var parentLi = e.parent().parent();
11079                     var parentUl = e.parent();
11080                     if(!parentLi.hasClass('b2b-tree')) {
11081                         var addHeight = parentUl[0].offsetHeight + h;
11082                         parentLi.find('ul').eq(0).css({
11083                             height: addHeight+'px'
11084                         })
11085                         addParentHeight(parentLi, h);
11086                     }                    
11087                 };
11088
11089                 var removeParentHeight = function(e, h) {
11090                     var parentLi = e.parent().parent();
11091                     var parentUl = e.parent();
11092                     if(!parentLi.hasClass('b2b-tree')) {
11093                         var addHeight = parentUl[0].offsetHeight - h;
11094                         parentLi.find('ul').eq(0).css({
11095                             height: addHeight+'px'
11096                         })
11097                         removeParentHeight(parentLi, h);
11098                     }
11099                 };
11100 */          
11101
11102             // isKeyPress - to notify that the function is called by Right Key press
11103             // passiveClose -  prevents firing of oncollapse events during the action
11104             // of expand function(check the function definition)
11105
11106                 var activeToggle = function (elem,isKeyPress,passiveClose) {
11107                     var element = elem.find('a').eq(0);
11108                     if (element.hasClass('active')) {
11109                         if(!isKeyPress){
11110                             elem.removeClass('bg');
11111                         }
11112                         
11113                         if (elem.attr('aria-selected') && !isKeyPress) {
11114                             elem.attr('aria-selected', 'false');
11115                         }
11116                         if (!element.find('i').eq(0).hasClass('icon-primary-circle')) {
11117                             if(isKeyPress && scope.member){
11118                                 if (scope.member.onCollapse !== undefined && !passiveClose) {
11119                                     scope.member.onCollapse(scope.member);
11120                                 }
11121                             }
11122                             element.removeClass('active');
11123                             elem.attr('aria-expanded', 'false');
11124                             element.find('i').eq(0).removeClass('icon-primary-expanded');
11125                             element.find('i').eq(0).addClass('icon-primary-collapsed');
11126                             //For Animation: below commented code is used to manually set height of UL to zero 
11127                             //retaining code for future reference
11128                             /*
11129                             var totalHeight = elem.find('ul')[0].scrollHeight;
11130                             removeParentHeight(elem, totalHeight);
11131                             elem.find('ul').eq(0).css({
11132                                 height: null
11133                             });*/
11134                         }
11135                     } else {
11136                         if(!isKeyPress){
11137                             elem.addClass('bg');
11138                             elem.attr('aria-selected', 'true');
11139                         }
11140                         
11141                         if (!element.find('i').eq(0).hasClass('icon-primary-circle')) {
11142                             if(isKeyPress){
11143                                 if(typeof scope.showChild === 'function' ){
11144                                 scope.showChild();
11145                                 }
11146                                 if(scope.member){
11147                                     if (scope.member.onExpand !== undefined) {
11148                                         scope.member.onExpand(scope.member);
11149                                     }
11150                                 }
11151                             }
11152                             element.addClass('active');
11153                             elem.attr('aria-expanded', 'true');
11154                             element.find('i').eq(0).removeClass('icon-primary-collapsed');
11155                             element.find('i').eq(0).addClass('icon-primary-expanded');
11156                             //For Animation: below commented code is used to manually set height of the ul generatedon the click of parent LI.
11157                             //retaining code for future reference
11158                             /*                            
11159                             var totalHeight = elem.find('ul')[0].scrollHeight;
11160                             addParentHeight(elem, totalHeight);
11161                             elem.find('ul').eq(0).css({
11162                                 height: totalHeight+'px'
11163                             });*/
11164                             
11165                         }
11166                     }
11167                 };
11168                 element.bind('click', function (evt) {
11169                     //first we close others and then we open the clicked element
11170                     if (element[0].previousElementSibling) {
11171                         closeOthersUp(angular.element(element[0].previousElementSibling));
11172                     }
11173                     if (element[0].nextElementSibling) {
11174                         closeOthersDown(angular.element(element[0].nextElementSibling));
11175                     }
11176                     removeBackground(element);
11177                     activeToggle(element);                    
11178                     
11179                     evt.stopPropagation();                    
11180                 });
11181                 //default root tree element tabindex set zero
11182                 if (element.parent().parent().hasClass('b2b-tree') && (element.parent()[0].previousElementSibling === null)) {
11183                     element.attr('tabindex', 0);
11184                 }
11185                 //check root via class
11186                 var isRoot = function (elem) {
11187                     if (elem.parent().parent().eq(0).hasClass('b2b-tree')) {
11188                         return true;
11189                     } else {
11190                         return false;
11191                     }
11192                 };
11193                 var findRoot = function (elem) {
11194                     if (isRoot(elem)) {
11195                         rootE = elem;
11196                         return;
11197                     }
11198                     findRoot(elem.parent());
11199                 };
11200
11201                 var findPreActive = function (elem) {
11202
11203                     if (!(elem.hasClass("active"))) {
11204                         return;
11205                     } else {
11206                         var childElems = angular.element(elem[0].nextElementSibling.children);
11207                         lastE = angular.element(childElems[childElems.length - 1]);
11208                         if (lastE.find('a').eq(0).hasClass('active')) {
11209                             findPreActive(lastE.find('a').eq(0));
11210                         }
11211                         upE = lastE;
11212                     }
11213                 };
11214
11215                 var findUp = function (elem) {
11216                     if (isRoot(elem)) {
11217                         upE = elem;
11218                         return;
11219                     }
11220                     if (elem[0].previousElementSibling !== null && !angular.element(elem[0].previousElementSibling).hasClass('tree-hide')) {
11221                         upE = angular.element(elem[0].previousElementSibling);
11222                         if (upE.find('a').eq(0).hasClass('active')) {
11223                             findPreActive(upE.find('a').eq(0));
11224                         }
11225                     } else {
11226                         upE = elem.parent().parent();
11227                     }
11228                 };
11229
11230                 var downElement = function (elem) {
11231                     if (elem.next().hasClass('tree-hide')) {
11232                         downElement(elem.next());
11233                     } else {
11234                         downE = elem.next();
11235                     }
11236                 }
11237                 var isBottomElem = false;
11238                 var downParent = function(liElem){
11239                     if(liElem.eq(0).parent().parent().eq(0).hasClass('b2b-tree')){
11240                         isBottomElem = true;
11241                         return;
11242                     }
11243                     if(liElem.next().length !== 0){
11244                         downE = liElem.next().eq(0);
11245                         return;
11246                     }
11247                     else {
11248                         downParent(liElem.parent().parent());
11249                     }
11250                 }
11251                 
11252                 var findDown = function (elem) {
11253                     if (isRoot(elem.parent()) && !elem.hasClass('active')) {
11254                         downE = elem.parent();
11255                         return;
11256                     }
11257                     if (elem.hasClass('active')) {
11258                         downE = elem.next().find('li').eq(0);
11259                         if (downE.hasClass('tree-hide')) {
11260                             downElement(downE);
11261                         }
11262
11263                     } else {
11264                         downParent(elem.parent());
11265                         if(isBottomElem === true){
11266                             downE = elem.parent();
11267                             isBottomElem = false;
11268                         }
11269                     }
11270                 };
11271
11272
11273                 var resetTabPosition = function(element){
11274                     findRoot(element);
11275                     angular.element(rootE.parent().parent()[0].querySelector("li[tabindex='0']")).attr('tabindex','-1');
11276                     var elemToFocus =  rootE.parent().parent()[0].querySelector(".bg")|| rootE;
11277
11278                     angular.element(elemToFocus).attr('tabindex','0');
11279                 };
11280                 // Function to control the expansion of nodes when the user tabs into the tree and
11281                 // the slected node is not visible
11282                 var expand = function(elemArr){
11283                     var elem= elemArr.pop();
11284                     var element = elem.find('a').eq(0);                    
11285                     var selectedNode = elem.parent().parent()[0].querySelector(".bg");
11286                     if(selectedNode != null){
11287                         while(elem){
11288                              element = elem.find('a').eq(0);
11289                     if(!element.hasClass('active') ){
11290
11291
11292                     if (elem[0].previousElementSibling) {
11293                         closeOthersUp(angular.element(elem[0].previousElementSibling),true,true);
11294                         }
11295                         if (elem[0].nextElementSibling) {
11296                             closeOthersDown(angular.element(elem[0].nextElementSibling),true,true);
11297                         }
11298
11299                          if (!element.find('i').eq(0).hasClass('icon-primary-circle')) {
11300                             if(typeof scope.showChild === 'function' ){
11301                                 scope.showChild();
11302                             }
11303                             element.addClass('active');
11304                             elem.attr('aria-expanded', 'true');
11305                             element.find('i').eq(0).removeClass('icon-primary-collapsed');
11306                             element.find('i').eq(0).addClass('icon-primary-expanded');
11307                             }
11308                           
11309                           }   
11310                           elem = elemArr.pop();
11311                         }                      
11312                         
11313                     }else{
11314                         return;
11315                     }                   
11316                 };
11317
11318                 element.find('a').eq(0).bind('mouseenter', function (evt) {
11319                     angular.forEach(document.querySelectorAll('.activeTooltip'), function(value, key) {
11320                         angular.element(value).removeClass('activeTooltip') 
11321                     });
11322                     element.addClass('activeTooltip');
11323                 });
11324                 element.find('a').eq(0).bind('mouseleave', function (evt) {
11325                     element.removeClass('activeTooltip');
11326                 });
11327                 element.bind('focus', function (evt) {
11328                     angular.forEach(document.querySelectorAll('.activeTooltip'), function(value, key) {
11329                         angular.element(value).removeClass('activeTooltip') 
11330                     });
11331                     element.addClass('activeTooltip');
11332                 });
11333                 element.bind('blur', function (evt) {
11334                     element.removeClass('activeTooltip');
11335                 });
11336                 element.bind('keydown', function (evt) {
11337                     switch (evt.keyCode) {
11338                     case keymap.KEY.HOME:
11339                         evt.preventDefault();
11340                         evt.stopPropagation();
11341                         element.attr('tabindex', -1);
11342                         findRoot(element);
11343                         rootE.eq(0).attr('tabindex', 0);
11344                         rootE[0].focus();
11345                         break;
11346                     case keymap.KEY.LEFT:
11347                         evt.preventDefault();
11348                         evt.stopPropagation(); 
11349                       
11350                         if(element.find('a').eq(0).hasClass('active')){
11351                             if (element[0].previousElementSibling) {
11352                                 closeOthersUp(angular.element(element[0].previousElementSibling),true);
11353                             }
11354                             if (element[0].nextElementSibling) {
11355                                 closeOthersDown(angular.element(element[0].nextElementSibling),true);
11356                              }
11357                              activeToggle(element,true);
11358                                 return;
11359                         }
11360                             element.attr('tabindex', -1);
11361                             parentE = element.parent().parent();
11362                             parentE.attr('tabindex', 0);
11363                             parentE[0].focus();
11364                         break;
11365                     case keymap.KEY.UP:
11366                         evt.preventDefault();
11367                         evt.stopPropagation();
11368                         element.attr('tabindex', -1);
11369                         findUp(element);
11370                         upE.eq(0).attr('tabindex', 0);
11371                         upE[0].focus();
11372                         break;
11373                     case keymap.KEY.RIGHT:
11374                         evt.preventDefault();
11375                         evt.stopPropagation();
11376                         if(element.find('i').eq(0).hasClass('icon-primary-circle')){
11377                             break;
11378                         }    
11379                         if (!element.find('a').eq(0).hasClass('active')) {
11380                             if (element[0].previousElementSibling) {
11381                         closeOthersUp(angular.element(element[0].previousElementSibling),true);
11382                         }
11383                         if (element[0].nextElementSibling) {
11384                             closeOthersDown(angular.element(element[0].nextElementSibling),true);
11385                         }
11386                         activeToggle(element,true);
11387                     
11388                         }
11389                         else {
11390                             element.attr('tabindex', -1);
11391                             findDown(element.find('a').eq(0));
11392                             downE.eq(0).attr('tabindex', 0);
11393                             downE[0].focus();                            
11394                         }                        
11395                         break;
11396                     case keymap.KEY.DOWN:
11397                         evt.preventDefault();
11398                         element.attr('tabindex', -1);
11399                         findDown(element.find('a').eq(0));
11400                         downE.eq(0).attr('tabindex', 0);
11401                         downE[0].focus();
11402                         evt.stopPropagation();
11403                         break;
11404                     case keymap.KEY.ENTER:
11405                         var isSelectedElem = element.hasClass('bg');
11406                         var enterFunc = function(element){
11407                             if (isSelectedElem) {
11408                                 element.removeClass('bg');
11409                                 if (element.attr('aria-selected')) {
11410                                     element.attr('aria-selected', 'false');
11411                                 }                        
11412                             }
11413                             else {
11414                                 element.addClass('bg');
11415                                 element.attr('aria-selected', 'true');                                   
11416                             }  
11417                         };                            
11418                         if (element[0].previousElementSibling) {
11419                             closeOthersUp(angular.element(element[0].previousElementSibling));
11420                         }
11421                         if (element[0].nextElementSibling) {
11422                             closeOthersDown(angular.element(element[0].nextElementSibling));
11423                         }                   
11424                         
11425                         removeBackground(element);
11426                         enterFunc(element);
11427                         evt.stopPropagation();                                                      
11428                         break;
11429                     case keymap.KEY.TAB:
11430                         $timeout(function(){
11431                             resetTabPosition(element);
11432                         },0);
11433                          evt.stopPropagation(); 
11434                         
11435                         break;
11436                     default:
11437                         break;
11438                     }
11439                 });
11440             element.bind('keyup',function(evt){
11441                 if(evt.keyCode === keymap.KEY.TAB){
11442                   
11443                         var tempElem = element;
11444                         var elemArr = [];
11445                         while(!tempElem.hasClass('b2b-tree')){
11446                             elemArr.push(tempElem);
11447                             tempElem = tempElem.parent().parent();
11448                         }
11449                         elemArr.push(tempElem);
11450                       
11451                         expand(elemArr);                    
11452                 }
11453                  evt.stopPropagation(); 
11454             });
11455             }
11456         };
11457     }]);
11458 /**
11459  * @ngdoc directive
11460  * @name Navigation.att:Tree nodes with checkboxes
11461  *
11462  * @param {String} setRole - The value needs to be "tree". This is required to incorporate CATO requirements.
11463  * @param {boolean} groupIt - The value needs to be "false" for top-level tree rendered. 
11464  * @param {Object} collection -  The JSON object of tree to be rendered.
11465  * @description
11466  *  <file src="src/treeNodeCheckbox/docs/readme.md" />
11467  *
11468  * @usage
11469  *      <div class="b2b-tree-checkbox">
11470  *                <b2b-tree-node-checkbox collection="treeStructure" set-role="tree" group-it="false"></b2b-tree-node-checkbox>
11471  *            </div>
11472  * @example
11473  *  <section id="code">
11474         <example module="b2b.att">
11475             <file src="src/treeNodeCheckbox/docs/demo.html" />
11476             <file src="src/treeNodeCheckbox/docs/demo.js" />
11477        </example>
11478     </section>
11479  *
11480  */
11481 angular.module('b2b.att.treeNodeCheckbox', ['b2b.att.utilities'])
11482     .directive('b2bTreeNodeCheckbox', function () {
11483         return {
11484             restrict: "E",
11485             replace: true,
11486             scope: {
11487                 collection: '=',
11488                 groupIt: '=',
11489                 setRole: '@'
11490             },
11491             templateUrl: function (element, attrs) {
11492                 if (attrs.groupIt === 'true') {
11493                     return "b2bTemplate/treeNodeCheckbox/groupedTree.html";
11494                 } else {
11495                     return "b2bTemplate/treeNodeCheckbox/ungroupedTree.html";
11496                 }
11497             },
11498             link: function (scope) {
11499                 if (!(scope.setRole === 'tree')) {
11500                     scope.setRole = 'group';
11501                 }
11502             }
11503         }
11504     })
11505     .directive('b2bTreeMember', ['$compile', '$timeout', 'keymap', function ($compile, $timeout, keymap) {
11506         return {
11507             restrict: "E",
11508             replace: true,
11509             scope: {
11510                 member: '=',
11511                 groupIt: '='
11512             },
11513             templateUrl: 'b2bTemplate/treeNodeCheckbox/treeMember.html',
11514             link: function (scope, element, attrs) {
11515                 scope.elemArr = [];
11516                 var removeRootTabIndex = function (elem) {
11517                     if (elem.parent().parent().eq(0).hasClass('b2b-tree-checkbox')) {
11518                         elem.attr('tabindex', -1);                        
11519                         return;
11520                     }
11521                     removeRootTabIndex(elem.parent());
11522                 };
11523                 scope.$watch('member.child', function(newVal, oldVal){                  
11524                     if(newVal !== oldVal){
11525                         scope.showChild();
11526                     };
11527                 });
11528
11529                 var checkedCount = 0;
11530                 var nonCheckedCount = 0;
11531                 var checkBoxesCount = 0;
11532
11533                 if(element.find('a').eq(0).find('input')){
11534                     if(scope.member.indeterminate){
11535                         element.find('a').eq(0).find('input').prop('indeterminate', true);
11536                         element.attr('aria-checked',"mixed");
11537                     }
11538                     element.attr('aria-checked',scope.member.isSelected);
11539                 }
11540
11541                 element.find('a').eq(0).find('input').bind('change',function(){
11542                     scope.member.indeterminate = false;
11543                     downwardModalUpdate(scope.member);
11544                     downwardSelection(element);
11545                     upwardSelection(element);
11546                     element.attr('aria-checked',scope.member.isSelected);
11547                      if (scope.member.onSelect !== undefined) {
11548                         scope.member.onSelect(scope.member);
11549                     }
11550                 });
11551
11552                 element.find('a').eq(0).find('input').bind('click',function(){
11553                     var elem = angular.element(this);
11554                     if(scope.member.indeterminate){
11555                         scope.member.indeterminate = false;
11556                         scope.member.isSelected = true;
11557                         elem.prop('indeterminate', false);
11558                         elem.prop('checked', true);
11559                         elem.triggerHandler('change');
11560                     }
11561                 });
11562
11563                 var groupNode = false;
11564                 var checkedTreeNode = false;
11565
11566                 var isCheckboxSelected = function(elem){
11567                     checkedTreeNode = false;
11568                     checkedTreeNode = angular.element(angular.element(elem).find('a').eq(0))[0].querySelector('input.treeCheckBox').checked;
11569                 }
11570
11571                 var findCheckbox = function(elem){
11572                     return angular.element(angular.element(elem).find('a').eq(0))[0].querySelector('input.treeCheckBox');
11573                 }
11574
11575                 var updateGrpNodeCheckboxes = function(elem, checked){
11576                     angular.element(angular.element(elem).find('a').eq(0))[0].querySelector('input.treeCheckBox').checked = checked;
11577                 }
11578
11579                 
11580                 var isGroupNode = function(elem){
11581                     groupNode = false;
11582                     if(angular.element(angular.element(elem).find('a').eq(0))[0].querySelector('input.grpTreeCheckbox')){
11583                         groupNode = true;
11584                     }
11585                 }
11586
11587                 var downwardModalUpdate = function(curMember){
11588                     angular.forEach(curMember.child, function(childMember, key) {
11589                         childMember.isSelected = curMember.isSelected;
11590                         childMember.indeterminate = false;
11591                         if(angular.isArray(childMember.child) && scope.member.child.length > 0){
11592                             downwardModalUpdate(childMember);
11593                         }
11594                     });
11595                 }
11596
11597                 var downwardSelection = function(elem){
11598                     if(findCheckbox(elem)){
11599                         isCheckboxSelected(elem)
11600                     } 
11601                     if(angular.element(elem).find('ul').length > 0){
11602                         var childNodes = angular.element(elem).find('ul').eq(0).children('li');
11603                         for(var i=0; i<childNodes.length; i++){
11604                             if(findCheckbox(childNodes[i])){
11605                                 isGroupNode(childNodes[i]);
11606                                 angular.element(findCheckbox(childNodes[i])).prop('indeterminate', false);
11607                                 angular.element(childNodes[i]).attr('aria-checked',checkedTreeNode);
11608                                 if(groupNode){
11609                                     updateGrpNodeCheckboxes(childNodes[i],checkedTreeNode);
11610                                 }else{
11611                                     angular.element(childNodes[i]).scope().member.isSelected = checkedTreeNode;
11612                                     angular.element(childNodes[i]).scope().member.indeterminate = false
11613                                     angular.element(childNodes[i]).scope().$apply();
11614                                 }
11615                                 downwardSelection(childNodes[i]);
11616                             }
11617                         }
11618
11619                     }
11620                 }
11621                 var upwardSelection = function(elem){
11622                     var childNodes = elem.parent().parent().find('ul').eq(0).children('li');
11623                     checkedCount = 0;
11624                     nonCheckedCount = 0;
11625                     checkBoxesCount = 0;    
11626                     for(i=0; i<childNodes.length; i++){
11627                         if(findCheckbox(childNodes[i])){
11628                             isGroupNode(childNodes[i]);
11629                             isCheckboxSelected(childNodes[i]);
11630                             checkBoxesCount++;
11631                             if(checkedTreeNode){
11632                                 checkedCount++;
11633                             }else if(!angular.element(angular.element(angular.element(childNodes[i]).find('a').eq(0))[0].querySelector('input.treeCheckBox')).prop('indeterminate')){
11634                                 nonCheckedCount++;
11635                             }
11636                         }
11637                     }
11638                     var parentNodeScope;
11639                     parentNodeScope = angular.element(elem.parent().parent()).scope();
11640                     if(findCheckbox(elem.parent().parent())){
11641                         if(nonCheckedCount == checkBoxesCount){
11642                             angular.element(findCheckbox(elem.parent().parent())).prop('indeterminate', false);
11643                             if(parentNodeScope &&  parentNodeScope.member){
11644                                 parentNodeScope.member.isSelected = false;
11645                                 parentNodeScope.member.indeterminate = false;
11646                             }else{
11647                                 updateGrpNodeCheckboxes(elem.parent().parent(),false);
11648                             }
11649                             angular.element(elem.parent().parent()).attr('aria-checked',false);
11650                         }else if(checkedCount == checkBoxesCount){
11651                             angular.element(findCheckbox(elem.parent().parent())).prop('indeterminate', false);
11652                             if(parentNodeScope &&  parentNodeScope.member){
11653                                 parentNodeScope.member.isSelected = true;
11654                                 parentNodeScope.member.indeterminate = false;
11655                             }else{
11656                                 updateGrpNodeCheckboxes(elem.parent().parent(),true);
11657                             }
11658                             angular.element(elem.parent().parent()).attr('aria-checked',true);
11659                         }else{
11660                             angular.element(findCheckbox(elem.parent().parent())).prop('indeterminate', true);
11661                             if(parentNodeScope &&  parentNodeScope.member){
11662                                 parentNodeScope.member.isSelected = false;
11663                                 parentNodeScope.member.indeterminate = true;
11664                             }else{
11665                                 updateGrpNodeCheckboxes(elem.parent().parent(),false);
11666                             }
11667                             angular.element(elem.parent().parent()).attr('aria-checked',"mixed");
11668                         }
11669                         if(parentNodeScope &&  parentNodeScope.member){
11670                             parentNodeScope.$apply();
11671                         }        
11672                     }
11673                     
11674                     
11675                     
11676                     if(elem.parent().parent().attr('role') == "treeitem"){
11677                         upwardSelection(elem.parent().parent());
11678                     }
11679                 }
11680
11681                 scope.showChild = function () {
11682                         if (!element.hasClass('grouped')) {
11683                             if (angular.isArray(scope.member.child) && scope.member.child.length > 0 && (scope.member.divide === undefined || scope.member.child.length < scope.member.divide)) {
11684                                 scope.groupIt = false;
11685                                 element.addClass('grouped');
11686                                 element.append("<b2b-tree-node-checkbox collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-node-checkbox>");
11687                                 $compile(element.contents())(scope);
11688                                 if(scope.member.active && scope.member.active === true){
11689                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-collapsed');
11690                                 };
11691                                 if(scope.member.selected && scope.member.selected === true){
11692                                     element.attr('tabindex', 0);
11693                                     removeRootTabIndex(element);
11694                                 };
11695                                 if(scope.member.active && scope.member.active == undefined){
11696                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');
11697                                 };
11698                             } else if (scope.member.child && scope.member.divide && scope.member.child.length > scope.member.divide) {
11699                                 element.addClass('grouped');
11700                                 scope.groupIt = true;
11701                                 var j = 0;
11702                                 var grpName = '';
11703                                 if(scope.member.child[0].groupName !== undefined){
11704                                     grpName = scope.member.child[0].groupName;
11705                                 }
11706                                 else{
11707                                     var toSlice = scope.member.child[0].name.search(' ');
11708                                     grpName = scope.member.child[0].name.slice(0, toSlice);
11709                                 }
11710
11711                                 for (i = 0; i < scope.member.child.length; i += scope.member.divide) {
11712                                     j = 0;
11713                                     for (j = j + i; j < (i + scope.member.divide); j++) {                                        
11714                                         if (j === scope.member.child.length) {
11715                                             scope.member.child[j - 1].grpChild = grpName + ' ' + (i + 1) + ' - ' + (scope.member.child.length);
11716                                             break;
11717                                             
11718                                             if(scope.member.child[j-1].active && scope.member.child[j-1].active===true){
11719                                                 scope.member.child[j-1].activeGrp = true;
11720                                             };
11721                                             
11722                                         }
11723                                         if (i + scope.member.divide > scope.member.child.length) {
11724                                             scope.member.child[j].grpChild = grpName + ' ' + (i + 1) + ' - ' + (scope.member.child.length);
11725                                             if(scope.member.child[j].active && scope.member.child[j].active===true){
11726                                                 scope.member.child[j].activeGrp = true;
11727                                             };
11728
11729                                         } else {
11730                                             scope.member.child[j].grpChild = grpName + ' ' + (i + 1) + ' - ' + (i + scope.member.divide);
11731                                             if(scope.member.child[j].active && scope.member.child[j].active===true){
11732                                                 scope.member.child[j].activeGrp = true;
11733                                             };
11734                                         }
11735                                     }
11736                                 }
11737                                 if(scope.member.divide){
11738                                     element.append("<b2b-tree-node-checkbox collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-node-checkbox>");
11739                                 } else {
11740                                     element.append("<b2b-tree-node-checkbox collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-node-checkbox>");
11741                                 }
11742                                 $compile(element.contents())(scope);
11743                                 if(scope.member.active && scope.member.active === true){
11744                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-collapsed');
11745                                 };
11746                                 
11747                                 if( scope.member.active && scope.member.active == undefined){
11748                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');
11749                                 };
11750                             }
11751                         }
11752                         $timeout(function () {
11753                             if(!scope.member.indeterminate){
11754                                 downwardSelection(element);
11755                             }    
11756                         });  
11757
11758                 };
11759                 
11760                 if(scope.member.active && scope.member.active == true){
11761                     scope.showChild();
11762                 };
11763                 if(scope.member.active == undefined && !element.find('a').eq(0).hasClass('active') && scope.member.child !== undefined){
11764                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');
11765                 }
11766                 else if(scope.member.child == undefined){
11767                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-circle');
11768                     if(scope.$parent.$index === 0) {
11769                         element.find('a').eq(0).append('<span class="first-link"></span>');
11770                     };
11771                 };
11772                 
11773                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).bind('click', function (evt) {
11774                     scope.showChild();
11775                     var expandFunc = scope.member.onExpand;
11776                     if (element.find('a').eq(0).hasClass('active') && scope.member.onExpand !== undefined) {
11777                        var eValue = scope.member.onExpand(scope.member);
11778                     }
11779                     if (!element.find('a').eq(0).hasClass('active') && scope.member.onCollapse !== undefined) {
11780                         scope.member.onCollapse(scope.member);
11781                     }
11782                 });
11783
11784                 angular.element(element[0].querySelectorAll('.treeNodeName')).eq(0).bind('click', function (evt) {
11785
11786                 });
11787                 
11788             }
11789         }
11790 }])
11791     .directive('b2bTreeNodeLink', ['keymap', '$timeout', function (keymap, $timeout) {
11792         return {
11793             restrict: 'A',
11794             link: function (scope, element, attr, ctrl) {
11795                 var rootE, parentE, upE, downE;
11796                 var closeOthersUp = function (elem) {
11797                     
11798                     if (elem.find('a').eq(0).hasClass('active')) {
11799                         activeToggle(elem);
11800                         return;
11801                     }
11802                     if (elem.hasClass('bg')) {
11803                         elem.removeClass('bg');
11804                     }
11805                     if (elem[0].previousElementSibling !== null) {
11806                         closeOthersUp(angular.element(elem[0].previousElementSibling));
11807                     }
11808                 };
11809                 var closeOthersDown = function (elem) {
11810                     
11811                     if (elem.find('a').eq(0).hasClass('active')) {
11812                         activeToggle(elem);
11813                         return;
11814                     }
11815                     if (elem.hasClass('bg')) {
11816                         elem.removeClass('bg');
11817                     }
11818                     if (elem[0].nextElementSibling !== null) {
11819                         closeOthersDown(angular.element(elem[0].nextElementSibling));
11820                     }
11821                 };
11822
11823                 var removeBackgroundUp = function (elem) {
11824                     
11825                     if (elem.hasClass('b2b-tree-checkbox')) {
11826                         return;
11827                     } else {
11828                         elem.parent().parent().removeClass('bg');
11829                         removeBackgroundUp(elem.parent().parent());
11830                     }
11831                 };
11832
11833                 var removeBackgroundDown = function (elem) {
11834                     
11835                     angular.element(elem[0].querySelector('.bg')).removeClass('bg');
11836                 };
11837
11838
11839
11840                 var activeToggle = function (elem) {
11841                     var element = elem.find('a').eq(0);
11842                     if (element.hasClass('active')) {
11843                         elem.removeClass('bg');
11844                         if (!angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).hasClass('icon-primary-circle')) {
11845                             element.removeClass('active');
11846                             elem.attr('aria-expanded', 'false');
11847                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-expanded');
11848                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');
11849                         }
11850                     } else {
11851                         elem.addClass('bg');
11852                         if (!angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).hasClass('icon-primary-circle')) {
11853                             element.addClass('active');
11854                             elem.attr('aria-expanded', 'true');
11855                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-collapsed');
11856                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-expanded');
11857                         }
11858                     }
11859                 };
11860                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).bind('click', function (evt) {
11861                     
11862                         if (element[0].previousElementSibling) {
11863                             closeOthersUp(angular.element(element[0].previousElementSibling));
11864                         }
11865                         if (element[0].nextElementSibling) {
11866                             closeOthersDown(angular.element(element[0].nextElementSibling));
11867                         }
11868
11869                         activeToggle(element);
11870
11871                     removeBackgroundDown(element);
11872                     removeBackgroundUp(element);
11873                     evt.stopPropagation();                    
11874                 });
11875                 
11876                 if (element.parent().parent().hasClass('b2b-tree-checkbox') && (element.parent()[0].previousElementSibling === null)) {
11877                     element.attr('tabindex', 0);
11878                 }
11879                 
11880                 var isRoot = function (elem) {
11881                     if (elem.parent().parent().eq(0).hasClass('b2b-tree-checkbox')) {
11882                         return true;
11883                     } else {
11884                         return false;
11885                     }
11886                 };
11887                 var findRoot = function (elem) {
11888                     if (isRoot(elem)) {
11889                         rootE = elem;
11890                         return;
11891                     }
11892                     findRoot(elem.parent());
11893                 };
11894
11895                 var findPreActive = function (elem) {
11896
11897                     if (!(elem.hasClass("active"))) {
11898                         return;
11899                     } else {
11900                         var childElems = angular.element(elem[0].nextElementSibling.children);
11901                         lastE = angular.element(childElems[childElems.length - 1]);
11902                         if (lastE.find('a').eq(0).hasClass('active')) {
11903                             findPreActive(lastE.find('a').eq(0));
11904                         }
11905                         upE = lastE;
11906                     }
11907                 };
11908
11909                 var findUp = function (elem) {
11910                     if (isRoot(elem)) {
11911                         upE = elem;
11912                         return;
11913                     }
11914                     if (elem[0].previousElementSibling !== null && !angular.element(elem[0].previousElementSibling).hasClass('tree-hide')) {
11915                         upE = angular.element(elem[0].previousElementSibling);
11916                         if (upE.find('a').eq(0).hasClass('active')) {
11917                             findPreActive(upE.find('a').eq(0));
11918                         }
11919                     } else {
11920                         upE = elem.parent().parent();
11921                     }
11922                 };
11923
11924                 var downElement = function (elem) {
11925                     if (elem.next().hasClass('tree-hide')) {
11926                         downElement(elem.next());
11927                     } else {
11928                         downE = elem.next();
11929                     }
11930                 }
11931                 var isBottomElem = false;
11932                 var downParent = function(liElem){
11933                     if(liElem.eq(0).parent().parent().eq(0).hasClass('b2b-tree-checkbox')){
11934                         isBottomElem = true;
11935                         return;
11936                     }
11937                     if(liElem.next().length !== 0){
11938                         downE = liElem.next().eq(0);
11939                         return;
11940                     }
11941                     else {
11942                         downParent(liElem.parent().parent());
11943                     }
11944                 }
11945                 
11946                 var findDown = function (elem) {
11947                     if (isRoot(elem.parent()) && !elem.hasClass('active')) {
11948                         downE = elem.parent();
11949                         return;
11950                     }
11951                     if (elem.hasClass('active')) {
11952                         downE = elem.next().find('li').eq(0);
11953                         if (downE.hasClass('tree-hide')) {
11954                             downElement(downE);
11955                         }
11956
11957                     } else {
11958                         downParent(elem.parent());
11959                         if(isBottomElem === true){
11960                             downE = elem.parent();
11961                             isBottomElem = false;
11962                         }
11963                     }
11964                 };
11965                 element.bind('keydown', function (evt) {
11966                     switch (evt.keyCode) {
11967                     case keymap.KEY.HOME:
11968                         evt.preventDefault();
11969                         evt.stopPropagation();
11970                         element.attr('tabindex', -1);
11971                         findRoot(element);
11972                         rootE.eq(0).attr('tabindex', 0);
11973                         rootE[0].focus();
11974                         break;
11975                     case keymap.KEY.LEFT:
11976                         evt.preventDefault();
11977                         evt.stopPropagation();
11978                         if (!isRoot(element)) {
11979                             if(element.find('a').eq(0).hasClass('active')){
11980                                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).triggerHandler('click');
11981                                 return;
11982                             }
11983                             element.attr('tabindex', -1);
11984                             parentE = element.parent().parent();
11985                             parentE.attr('tabindex', 0);
11986                             parentE[0].focus();
11987                         } else {
11988                             if (element.find('a').eq(0).hasClass('active')) {
11989                                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).triggerHandler('click');
11990                             }
11991                         };
11992                         break;
11993                     case keymap.KEY.UP:
11994                         evt.preventDefault();
11995                         evt.stopPropagation();
11996                         element.attr('tabindex', -1);
11997                         findUp(element);
11998                         upE.eq(0).attr('tabindex', 0);
11999                         upE[0].focus();
12000                         break;
12001                     case keymap.KEY.RIGHT:
12002                         evt.preventDefault();
12003                         evt.stopPropagation();
12004                         if(angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).hasClass('icon-primary-circle')){
12005                             break;
12006                         }    
12007                         if (!element.find('a').eq(0).hasClass('active')) {
12008                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).triggerHandler('click');
12009                         }
12010                         else {
12011                             element.attr('tabindex', -1);
12012                             findDown(element.find('a').eq(0));
12013                             downE.eq(0).attr('tabindex', 0);
12014                             downE[0].focus();                            
12015                         }                        
12016                         break;
12017                     case keymap.KEY.DOWN:
12018                         evt.preventDefault();
12019                         element.attr('tabindex', -1);
12020                         findDown(element.find('a').eq(0));
12021                         downE.eq(0).attr('tabindex', 0);
12022                         downE[0].focus();
12023                         evt.stopPropagation();
12024                         break;
12025                     case keymap.KEY.SPACE:
12026                     case keymap.KEY.ENTER:
12027                         evt.preventDefault();
12028                         evt.stopPropagation();
12029                         if(angular.isDefined(element.scope().member.isSelected)){
12030                             element.scope().member.isSelected = !element.scope().member.isSelected;
12031                             element.scope().member.indeterminate = false;
12032                             element.scope().$apply();
12033                             element.find('a').eq(0).find('input').prop('indeterminate', false);
12034                             element.find('a').eq(0).find('input').triggerHandler('change');
12035                         }
12036                         break;    
12037                     default:
12038                         break;
12039                     }
12040                 });
12041             }
12042         };
12043     }]);
12044 /*!
12045  * VERSION: 1.7.3
12046  * DATE: 2014-01-14
12047  * UPDATES AND DOCS AT: http://www.greensock.com
12048  *
12049  * @license Copyright (c) 2008-2014, GreenSock. All rights reserved.
12050  * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
12051  * Club GreenSock members, the software agreement that was issued with your membership.
12052  * 
12053  * @author: Jack Doyle, jack@greensock.com
12054  **/
12055 (window._gsQueue || (window._gsQueue = [])).push( function() {
12056
12057     "use strict";
12058
12059     var _doc = document.documentElement,
12060         _window = window,
12061         _max = function(element, axis) {
12062             var dim = (axis === "x") ? "Width" : "Height",
12063                 scroll = "scroll" + dim,
12064                 client = "client" + dim,
12065                 body = document.body;
12066             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];
12067         },
12068
12069         ScrollToPlugin = window._gsDefine.plugin({
12070             propName: "scrollTo",
12071             API: 2,
12072             version:"1.7.3",
12073
12074             //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
12075             init: function(target, value, tween) {
12076                 this._wdw = (target === _window);
12077                 this._target = target;
12078                 this._tween = tween;
12079                 if (typeof(value) !== "object") {
12080                     value = {y:value}; //if we don't receive an object as the parameter, assume the user intends "y".
12081                 }
12082                 this._autoKill = (value.autoKill !== false);
12083                 this.x = this.xPrev = this.getX();
12084                 this.y = this.yPrev = this.getY();
12085                 if (value.x != null) {
12086                     this._addTween(this, "x", this.x, (value.x === "max") ? _max(target, "x") : value.x, "scrollTo_x", true);
12087                     this._overwriteProps.push("scrollTo_x");
12088                 } else {
12089                     this.skipX = true;
12090                 }
12091                 if (value.y != null) {
12092                     this._addTween(this, "y", this.y, (value.y === "max") ? _max(target, "y") : value.y, "scrollTo_y", true);
12093                     this._overwriteProps.push("scrollTo_y");
12094                 } else {
12095                     this.skipY = true;
12096                 }
12097                 return true;
12098             },
12099
12100             //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.)
12101             set: function(v) {
12102                 this._super.setRatio.call(this, v);
12103
12104                 var x = (this._wdw || !this.skipX) ? this.getX() : this.xPrev,
12105                     y = (this._wdw || !this.skipY) ? this.getY() : this.yPrev,
12106                     yDif = y - this.yPrev,
12107                     xDif = x - this.xPrev;
12108
12109                 if (this._autoKill) {
12110                     //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.
12111                     if (!this.skipX && (xDif > 7 || xDif < -7) && x < _max(this._target, "x")) {
12112                         this.skipX = true; //if the user scrolls separately, we should stop tweening!
12113                     }
12114                     if (!this.skipY && (yDif > 7 || yDif < -7) && y < _max(this._target, "y")) {
12115                         this.skipY = true; //if the user scrolls separately, we should stop tweening!
12116                     }
12117                     if (this.skipX && this.skipY) {
12118                         this._tween.kill();
12119                     }
12120                 }
12121                 if (this._wdw) {
12122                     _window.scrollTo((!this.skipX) ? this.x : x, (!this.skipY) ? this.y : y);
12123                 } else {
12124                     if (!this.skipY) {
12125                         this._target.scrollTop = this.y;
12126                     }
12127                     if (!this.skipX) {
12128                         this._target.scrollLeft = this.x;
12129                     }
12130                 }
12131                 this.xPrev = this.x;
12132                 this.yPrev = this.y;
12133             }
12134
12135         }),
12136         p = ScrollToPlugin.prototype;
12137
12138     ScrollToPlugin.max = _max;
12139
12140     p.getX = function() {
12141         return (!this._wdw) ? this._target.scrollLeft : (_window.pageXOffset != null) ? _window.pageXOffset : (_doc.scrollLeft != null) ? _doc.scrollLeft : document.body.scrollLeft;
12142     };
12143
12144     p.getY = function() {
12145         return (!this._wdw) ? this._target.scrollTop : (_window.pageYOffset != null) ? _window.pageYOffset : (_doc.scrollTop != null) ? _doc.scrollTop : document.body.scrollTop;
12146     };
12147
12148     p._kill = function(lookup) {
12149         if (lookup.scrollTo_x) {
12150             this.skipX = true;
12151         }
12152         if (lookup.scrollTo_y) {
12153             this.skipY = true;
12154         }
12155         return this._super._kill.call(this, lookup);
12156     };
12157
12158 }); if (window._gsDefine) { window._gsQueue.pop()(); }
12159 /*!
12160  * VERSION: 1.12.1
12161  * DATE: 2014-06-26
12162  * UPDATES AND DOCS AT: http://www.greensock.com
12163  * 
12164  * Includes all of the following: TweenLite, TweenMax, TimelineLite, TimelineMax, EasePack, CSSPlugin, RoundPropsPlugin, BezierPlugin, AttrPlugin, DirectionalRotationPlugin
12165  *
12166  * @license Copyright (c) 2008-2014, GreenSock. All rights reserved.
12167  * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
12168  * Club GreenSock members, the software agreement that was issued with your membership.
12169  * 
12170  * @author: Jack Doyle, jack@greensock.com
12171  **/
12172
12173 (window._gsQueue || (window._gsQueue = [])).push( function() {
12174
12175     "use strict";
12176
12177     window._gsDefine("TweenMax", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {
12178
12179         var _slice = [].slice,
12180             TweenMax = function(target, duration, vars) {
12181                 TweenLite.call(this, target, duration, vars);
12182                 this._cycle = 0;
12183                 this._yoyo = (this.vars.yoyo === true);
12184                 this._repeat = this.vars.repeat || 0;
12185                 this._repeatDelay = this.vars.repeatDelay || 0;
12186                 this._dirty = true; //ensures that if there is any repeat, the totalDuration will get recalculated to accurately report it.
12187                 this.render = TweenMax.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method)
12188             },
12189             _tinyNum = 0.0000000001,
12190             TweenLiteInternals = TweenLite._internals,
12191             _isSelector = TweenLiteInternals.isSelector,
12192             _isArray = TweenLiteInternals.isArray,
12193             p = TweenMax.prototype = TweenLite.to({}, 0.1, {}),
12194             _blankArray = [];
12195
12196         TweenMax.version = "1.12.1";
12197         p.constructor = TweenMax;
12198         p.kill()._gc = false;
12199         TweenMax.killTweensOf = TweenMax.killDelayedCallsTo = TweenLite.killTweensOf;
12200         TweenMax.getTweensOf = TweenLite.getTweensOf;
12201         TweenMax.lagSmoothing = TweenLite.lagSmoothing;
12202         TweenMax.ticker = TweenLite.ticker;
12203         TweenMax.render = TweenLite.render;
12204
12205         p.invalidate = function() {
12206             this._yoyo = (this.vars.yoyo === true);
12207             this._repeat = this.vars.repeat || 0;
12208             this._repeatDelay = this.vars.repeatDelay || 0;
12209             this._uncache(true);
12210             return TweenLite.prototype.invalidate.call(this);
12211         };
12212         
12213         p.updateTo = function(vars, resetDuration) {
12214             var curRatio = this.ratio, p;
12215             if (resetDuration && this._startTime < this._timeline._time) {
12216                 this._startTime = this._timeline._time;
12217                 this._uncache(false);
12218                 if (this._gc) {
12219                     this._enabled(true, false);
12220                 } else {
12221                     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.
12222                 }
12223             }
12224             for (p in vars) {
12225                 this.vars[p] = vars[p];
12226             }
12227             if (this._initted) {
12228                 if (resetDuration) {
12229                     this._initted = false;
12230                 } else {
12231                     if (this._gc) {
12232                         this._enabled(true, false);
12233                     }
12234                     if (this._notifyPluginsOfEnabled && this._firstPT) {
12235                         TweenLite._onPluginEvent("_onDisable", this); //in case a plugin like MotionBlur must perform some cleanup tasks
12236                     }
12237                     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. 
12238                         var prevTime = this._time;
12239                         this.render(0, true, false);
12240                         this._initted = false;
12241                         this.render(prevTime, true, false);
12242                     } else if (this._time > 0) {
12243                         this._initted = false;
12244                         this._init();
12245                         var inv = 1 / (1 - curRatio),
12246                             pt = this._firstPT, endValue;
12247                         while (pt) {
12248                             endValue = pt.s + pt.c; 
12249                             pt.c *= inv;
12250                             pt.s = endValue - pt.c;
12251                             pt = pt._next;
12252                         }
12253                     }
12254                 }
12255             }
12256             return this;
12257         };
12258                 
12259         p.render = function(time, suppressEvents, force) {
12260             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.
12261                 this.invalidate();
12262             }
12263             var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
12264                 prevTime = this._time,
12265                 prevTotalTime = this._totalTime, 
12266                 prevCycle = this._cycle,
12267                 duration = this._duration,
12268                 prevRawPrevTime = this._rawPrevTime,
12269                 isComplete, callback, pt, cycleDuration, r, type, pow, rawPrevTime, i;
12270             if (time >= totalDur) {
12271                 this._totalTime = totalDur;
12272                 this._cycle = this._repeat;
12273                 if (this._yoyo && (this._cycle & 1) !== 0) {
12274                     this._time = 0;
12275                     this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
12276                 } else {
12277                     this._time = duration;
12278                     this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1;
12279                 }
12280                 if (!this._reversed) {
12281                     isComplete = true;
12282                     callback = "onComplete";
12283                 }
12284                 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.
12285                     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.
12286                         time = 0;
12287                     }
12288                     if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time) {
12289                         force = true;
12290                         if (prevRawPrevTime > _tinyNum) {
12291                             callback = "onReverseComplete";
12292                         }
12293                     }
12294                     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.
12295                 }
12296                 
12297             } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
12298                 this._totalTime = this._time = this._cycle = 0;
12299                 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
12300                 if (prevTotalTime !== 0 || (duration === 0 && prevRawPrevTime > 0 && prevRawPrevTime !== _tinyNum)) {
12301                     callback = "onReverseComplete";
12302                     isComplete = this._reversed;
12303                 }
12304                 if (time < 0) {
12305                     this._active = false;
12306                     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.
12307                         if (prevRawPrevTime >= 0) {
12308                             force = true;
12309                         }
12310                         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.
12311                     }
12312                 } 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.
12313                     force = true;
12314                 }
12315             } else {
12316                 this._totalTime = this._time = time;
12317                 
12318                 if (this._repeat !== 0) {
12319                     cycleDuration = duration + this._repeatDelay;
12320                     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!)
12321                     if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) {
12322                         this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning)
12323                     }
12324                     this._time = this._totalTime - (this._cycle * cycleDuration);
12325                     if (this._yoyo) if ((this._cycle & 1) !== 0) {
12326                         this._time = duration - this._time;
12327                     }
12328                     if (this._time > duration) {
12329                         this._time = duration;
12330                     } else if (this._time < 0) {
12331                         this._time = 0;
12332                     }
12333                 }
12334
12335                 if (this._easeType) {
12336                     r = this._time / duration;
12337                     type = this._easeType;
12338                     pow = this._easePower;
12339                     if (type === 1 || (type === 3 && r >= 0.5)) {
12340                         r = 1 - r;
12341                     }
12342                     if (type === 3) {
12343                         r *= 2;
12344                     }
12345                     if (pow === 1) {
12346                         r *= r;
12347                     } else if (pow === 2) {
12348                         r *= r * r;
12349                     } else if (pow === 3) {
12350                         r *= r * r * r;
12351                     } else if (pow === 4) {
12352                         r *= r * r * r * r;
12353                     }
12354
12355                     if (type === 1) {
12356                         this.ratio = 1 - r;
12357                     } else if (type === 2) {
12358                         this.ratio = r;
12359                     } else if (this._time / duration < 0.5) {
12360                         this.ratio = r / 2;
12361                     } else {
12362                         this.ratio = 1 - (r / 2);
12363                     }
12364
12365                 } else {
12366                     this.ratio = this._ease.getRatio(this._time / duration);
12367                 }
12368                 
12369             }
12370                 
12371             if (prevTime === this._time && !force && prevCycle === this._cycle) {
12372                 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.
12373                     this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
12374                 }
12375                 return;
12376             } else if (!this._initted) {
12377                 this._init();
12378                 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.
12379                     return;
12380                 } 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.
12381                     this._time = prevTime;
12382                     this._totalTime = prevTotalTime;
12383                     this._rawPrevTime = prevRawPrevTime;
12384                     this._cycle = prevCycle;
12385                     TweenLiteInternals.lazyTweens.push(this);
12386                     this._lazy = time;
12387                     return;
12388                 }
12389                 //_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.
12390                 if (this._time && !isComplete) {
12391                     this.ratio = this._ease.getRatio(this._time / duration);
12392                 } else if (isComplete && this._ease._calcEnd) {
12393                     this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1);
12394                 }
12395             }
12396             if (this._lazy !== false) {
12397                 this._lazy = false;
12398             }
12399
12400             if (!this._active) if (!this._paused && this._time !== prevTime && time >= 0) {
12401                 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.
12402             }
12403             if (prevTotalTime === 0) {
12404                 if (this._initted === 2 && time > 0) {
12405                     //this.invalidate();
12406                     this._init(); //will just apply overwriting since _initted of (2) means it was a from() tween that had immediateRender:true
12407                 }
12408                 if (this._startAt) {
12409                     if (time >= 0) {
12410                         this._startAt.render(time, suppressEvents, force);
12411                     } else if (!callback) {
12412                         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.
12413                     }
12414                 }
12415                 if (this.vars.onStart) if (this._totalTime !== 0 || duration === 0) if (!suppressEvents) {
12416                     this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
12417                 }
12418             }
12419             
12420             pt = this._firstPT;
12421             while (pt) {
12422                 if (pt.f) {
12423                     pt.t[pt.p](pt.c * this.ratio + pt.s);
12424                 } else {
12425                     pt.t[pt.p] = pt.c * this.ratio + pt.s;
12426                 }
12427                 pt = pt._next;
12428             }
12429             
12430             if (this._onUpdate) {
12431                 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.
12432                     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.
12433                 }
12434                 if (!suppressEvents) if (this._totalTime !== prevTotalTime || isComplete) {
12435                     this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
12436                 }
12437             }
12438             if (this._cycle !== prevCycle) if (!suppressEvents) if (!this._gc) if (this.vars.onRepeat) {
12439                 this.vars.onRepeat.apply(this.vars.onRepeatScope || this, this.vars.onRepeatParams || _blankArray);
12440             }
12441             if (callback) if (!this._gc) { //check gc because there's a chance that kill() could be called in an onUpdate
12442                 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.
12443                     this._startAt.render(time, suppressEvents, force);
12444                 }
12445                 if (isComplete) {
12446                     if (this._timeline.autoRemoveChildren) {
12447                         this._enabled(false, false);
12448                     }
12449                     this._active = false;
12450                 }
12451                 if (!suppressEvents && this.vars[callback]) {
12452                     this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
12453                 }
12454                 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.
12455                     this._rawPrevTime = 0;
12456                 }
12457             }
12458         };
12459         
12460 //---- STATIC FUNCTIONS -----------------------------------------------------------------------------------------------------------
12461         
12462         TweenMax.to = function(target, duration, vars) {
12463             return new TweenMax(target, duration, vars);
12464         };
12465         
12466         TweenMax.from = function(target, duration, vars) {
12467             vars.runBackwards = true;
12468             vars.immediateRender = (vars.immediateRender != false);
12469             return new TweenMax(target, duration, vars);
12470         };
12471         
12472         TweenMax.fromTo = function(target, duration, fromVars, toVars) {
12473             toVars.startAt = fromVars;
12474             toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
12475             return new TweenMax(target, duration, toVars);
12476         };
12477         
12478         TweenMax.staggerTo = TweenMax.allTo = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
12479             stagger = stagger || 0;
12480             var delay = vars.delay || 0,
12481                 a = [],
12482                 finalComplete = function() {
12483                     if (vars.onComplete) {
12484                         vars.onComplete.apply(vars.onCompleteScope || this, arguments);
12485                     }
12486                     onCompleteAll.apply(onCompleteAllScope || this, onCompleteAllParams || _blankArray);
12487                 },
12488                 l, copy, i, p;
12489             if (!_isArray(targets)) {
12490                 if (typeof(targets) === "string") {
12491                     targets = TweenLite.selector(targets) || targets;
12492                 }
12493                 if (_isSelector(targets)) {
12494                     targets = _slice.call(targets, 0);
12495                 }
12496             }
12497             l = targets.length;
12498             for (i = 0; i < l; i++) {
12499                 copy = {};
12500                 for (p in vars) {
12501                     copy[p] = vars[p];
12502                 }
12503                 copy.delay = delay;
12504                 if (i === l - 1 && onCompleteAll) {
12505                     copy.onComplete = finalComplete;
12506                 }
12507                 a[i] = new TweenMax(targets[i], duration, copy);
12508                 delay += stagger;
12509             }
12510             return a;
12511         };
12512         
12513         TweenMax.staggerFrom = TweenMax.allFrom = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
12514             vars.runBackwards = true;
12515             vars.immediateRender = (vars.immediateRender != false);
12516             return TweenMax.staggerTo(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
12517         };
12518         
12519         TweenMax.staggerFromTo = TweenMax.allFromTo = function(targets, duration, fromVars, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
12520             toVars.startAt = fromVars;
12521             toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
12522             return TweenMax.staggerTo(targets, duration, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
12523         };
12524                 
12525         TweenMax.delayedCall = function(delay, callback, params, scope, useFrames) {
12526             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});
12527         };
12528         
12529         TweenMax.set = function(target, vars) {
12530             return new TweenMax(target, 0, vars);
12531         };
12532         
12533         TweenMax.isTweening = function(target) {
12534             return (TweenLite.getTweensOf(target, true).length > 0);
12535         };
12536         
12537         var _getChildrenOf = function(timeline, includeTimelines) {
12538                 var a = [],
12539                     cnt = 0,
12540                     tween = timeline._first;
12541                 while (tween) {
12542                     if (tween instanceof TweenLite) {
12543                         a[cnt++] = tween;
12544                     } else {
12545                         if (includeTimelines) {
12546                             a[cnt++] = tween;
12547                         }
12548                         a = a.concat(_getChildrenOf(tween, includeTimelines));
12549                         cnt = a.length;
12550                     }
12551                     tween = tween._next;
12552                 }
12553                 return a;
12554             }, 
12555             getAllTweens = TweenMax.getAllTweens = function(includeTimelines) {
12556                 return _getChildrenOf(Animation._rootTimeline, includeTimelines).concat( _getChildrenOf(Animation._rootFramesTimeline, includeTimelines) );
12557             };
12558         
12559         TweenMax.killAll = function(complete, tweens, delayedCalls, timelines) {
12560             if (tweens == null) {
12561                 tweens = true;
12562             }
12563             if (delayedCalls == null) {
12564                 delayedCalls = true;
12565             }
12566             var a = getAllTweens((timelines != false)),
12567                 l = a.length,
12568                 allTrue = (tweens && delayedCalls && timelines),
12569                 isDC, tween, i;
12570             for (i = 0; i < l; i++) {
12571                 tween = a[i];
12572                 if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) {
12573                     if (complete) {
12574                         tween.totalTime(tween._reversed ? 0 : tween.totalDuration());
12575                     } else {
12576                         tween._enabled(false, false);
12577                     }
12578                 }
12579             }
12580         };
12581         
12582         TweenMax.killChildTweensOf = function(parent, complete) {
12583             if (parent == null) {
12584                 return;
12585             }
12586             var tl = TweenLiteInternals.tweenLookup,
12587                 a, curParent, p, i, l;
12588             if (typeof(parent) === "string") {
12589                 parent = TweenLite.selector(parent) || parent;
12590             }
12591             if (_isSelector(parent)) {
12592                 parent = _slice.call(parent, 0);
12593             }
12594             if (_isArray(parent)) {
12595                 i = parent.length;
12596                 while (--i > -1) {
12597                     TweenMax.killChildTweensOf(parent[i], complete);
12598                 }
12599                 return;
12600             }
12601             a = [];
12602             for (p in tl) {
12603                 curParent = tl[p].target.parentNode;
12604                 while (curParent) {
12605                     if (curParent === parent) {
12606                         a = a.concat(tl[p].tweens);
12607                     }
12608                     curParent = curParent.parentNode;
12609                 }
12610             }
12611             l = a.length;
12612             for (i = 0; i < l; i++) {
12613                 if (complete) {
12614                     a[i].totalTime(a[i].totalDuration());
12615                 }
12616                 a[i]._enabled(false, false);
12617             }
12618         };
12619
12620         var _changePause = function(pause, tweens, delayedCalls, timelines) {
12621             tweens = (tweens !== false);
12622             delayedCalls = (delayedCalls !== false);
12623             timelines = (timelines !== false);
12624             var a = getAllTweens(timelines),
12625                 allTrue = (tweens && delayedCalls && timelines),
12626                 i = a.length,
12627                 isDC, tween;
12628             while (--i > -1) {
12629                 tween = a[i];
12630                 if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) {
12631                     tween.paused(pause);
12632                 }
12633             }
12634         };
12635         
12636         TweenMax.pauseAll = function(tweens, delayedCalls, timelines) {
12637             _changePause(true, tweens, delayedCalls, timelines);
12638         };
12639         
12640         TweenMax.resumeAll = function(tweens, delayedCalls, timelines) {
12641             _changePause(false, tweens, delayedCalls, timelines);
12642         };
12643
12644         TweenMax.globalTimeScale = function(value) {
12645             var tl = Animation._rootTimeline,
12646                 t = TweenLite.ticker.time;
12647             if (!arguments.length) {
12648                 return tl._timeScale;
12649             }
12650             value = value || _tinyNum; //can't allow zero because it'll throw the math off
12651             tl._startTime = t - ((t - tl._startTime) * tl._timeScale / value);
12652             tl = Animation._rootFramesTimeline;
12653             t = TweenLite.ticker.frame;
12654             tl._startTime = t - ((t - tl._startTime) * tl._timeScale / value);
12655             tl._timeScale = Animation._rootTimeline._timeScale = value;
12656             return value;
12657         };
12658         
12659     
12660 //---- GETTERS / SETTERS ----------------------------------------------------------------------------------------------------------
12661         
12662         p.progress = function(value) {
12663             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);
12664         };
12665         
12666         p.totalProgress = function(value) {
12667             return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, false);
12668         };
12669         
12670         p.time = function(value, suppressEvents) {
12671             if (!arguments.length) {
12672                 return this._time;
12673             }
12674             if (this._dirty) {
12675                 this.totalDuration();
12676             }
12677             if (value > this._duration) {
12678                 value = this._duration;
12679             }
12680             if (this._yoyo && (this._cycle & 1) !== 0) {
12681                 value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay));
12682             } else if (this._repeat !== 0) {
12683                 value += this._cycle * (this._duration + this._repeatDelay);
12684             }
12685             return this.totalTime(value, suppressEvents);
12686         };
12687
12688         p.duration = function(value) {
12689             if (!arguments.length) {
12690                 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.
12691             }
12692             return Animation.prototype.duration.call(this, value);
12693         };
12694
12695         p.totalDuration = function(value) {
12696             if (!arguments.length) {
12697                 if (this._dirty) {
12698                     //instead of Infinity, we use 999999999999 so that we can accommodate reverses
12699                     this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat);
12700                     this._dirty = false;
12701                 }
12702                 return this._totalDuration;
12703             }
12704             return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) );
12705         };
12706         
12707         p.repeat = function(value) {
12708             if (!arguments.length) {
12709                 return this._repeat;
12710             }
12711             this._repeat = value;
12712             return this._uncache(true);
12713         };
12714         
12715         p.repeatDelay = function(value) {
12716             if (!arguments.length) {
12717                 return this._repeatDelay;
12718             }
12719             this._repeatDelay = value;
12720             return this._uncache(true);
12721         };
12722         
12723         p.yoyo = function(value) {
12724             if (!arguments.length) {
12725                 return this._yoyo;
12726             }
12727             this._yoyo = value;
12728             return this;
12729         };
12730         
12731         
12732         return TweenMax;
12733         
12734     }, true);
12735
12736
12737
12738
12739
12740
12741
12742
12743 /*
12744  * ----------------------------------------------------------------
12745  * TimelineLite
12746  * ----------------------------------------------------------------
12747  */
12748     window._gsDefine("TimelineLite", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {
12749
12750         var TimelineLite = function(vars) {
12751                 SimpleTimeline.call(this, vars);
12752                 this._labels = {};
12753                 this.autoRemoveChildren = (this.vars.autoRemoveChildren === true);
12754                 this.smoothChildTiming = (this.vars.smoothChildTiming === true);
12755                 this._sortChildren = true;
12756                 this._onUpdate = this.vars.onUpdate;
12757                 var v = this.vars,
12758                     val, p;
12759                 for (p in v) {
12760                     val = v[p];
12761                     if (_isArray(val)) if (val.join("").indexOf("{self}") !== -1) {
12762                         v[p] = this._swapSelfInParams(val);
12763                     }
12764                 }
12765                 if (_isArray(v.tweens)) {
12766                     this.add(v.tweens, 0, v.align, v.stagger);
12767                 }
12768             },
12769             _tinyNum = 0.0000000001,
12770             _isSelector = TweenLite._internals.isSelector,
12771             _isArray = TweenLite._internals.isArray,
12772             _blankArray = [],
12773             _globals = window._gsDefine.globals,
12774             _copy = function(vars) {
12775                 var copy = {}, p;
12776                 for (p in vars) {
12777                     copy[p] = vars[p];
12778                 }
12779                 return copy;
12780             },
12781             _pauseCallback = function(tween, callback, params, scope) {
12782                 tween._timeline.pause(tween._startTime);
12783                 if (callback) {
12784                     callback.apply(scope || tween._timeline, params || _blankArray);
12785                 }
12786             },
12787             _slice = _blankArray.slice,
12788             p = TimelineLite.prototype = new SimpleTimeline();
12789
12790         TimelineLite.version = "1.12.1";
12791         p.constructor = TimelineLite;
12792         p.kill()._gc = false;
12793
12794         p.to = function(target, duration, vars, position) {
12795             var Engine = (vars.repeat && _globals.TweenMax) || TweenLite;
12796             return duration ? this.add( new Engine(target, duration, vars), position) : this.set(target, vars, position);
12797         };
12798
12799         p.from = function(target, duration, vars, position) {
12800             return this.add( ((vars.repeat && _globals.TweenMax) || TweenLite).from(target, duration, vars), position);
12801         };
12802
12803         p.fromTo = function(target, duration, fromVars, toVars, position) {
12804             var Engine = (toVars.repeat && _globals.TweenMax) || TweenLite;
12805             return duration ? this.add( Engine.fromTo(target, duration, fromVars, toVars), position) : this.set(target, toVars, position);
12806         };
12807
12808         p.staggerTo = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
12809             var tl = new TimelineLite({onComplete:onCompleteAll, onCompleteParams:onCompleteAllParams, onCompleteScope:onCompleteAllScope, smoothChildTiming:this.smoothChildTiming}),
12810                 i;
12811             if (typeof(targets) === "string") {
12812                 targets = TweenLite.selector(targets) || targets;
12813             }
12814             if (_isSelector(targets)) { //senses if the targets object is a selector. If it is, we should translate it into an array.
12815                 targets = _slice.call(targets, 0);
12816             }
12817             stagger = stagger || 0;
12818             for (i = 0; i < targets.length; i++) {
12819                 if (vars.startAt) {
12820                     vars.startAt = _copy(vars.startAt);
12821                 }
12822                 tl.to(targets[i], duration, _copy(vars), i * stagger);
12823             }
12824             return this.add(tl, position);
12825         };
12826
12827         p.staggerFrom = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
12828             vars.immediateRender = (vars.immediateRender != false);
12829             vars.runBackwards = true;
12830             return this.staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
12831         };
12832
12833         p.staggerFromTo = function(targets, duration, fromVars, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
12834             toVars.startAt = fromVars;
12835             toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
12836             return this.staggerTo(targets, duration, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
12837         };
12838
12839         p.call = function(callback, params, scope, position) {
12840             return this.add( TweenLite.delayedCall(0, callback, params, scope), position);
12841         };
12842
12843         p.set = function(target, vars, position) {
12844             position = this._parseTimeOrLabel(position, 0, true);
12845             if (vars.immediateRender == null) {
12846                 vars.immediateRender = (position === this._time && !this._paused);
12847             }
12848             return this.add( new TweenLite(target, 0, vars), position);
12849         };
12850
12851         TimelineLite.exportRoot = function(vars, ignoreDelayedCalls) {
12852             vars = vars || {};
12853             if (vars.smoothChildTiming == null) {
12854                 vars.smoothChildTiming = true;
12855             }
12856             var tl = new TimelineLite(vars),
12857                 root = tl._timeline,
12858                 tween, next;
12859             if (ignoreDelayedCalls == null) {
12860                 ignoreDelayedCalls = true;
12861             }
12862             root._remove(tl, true);
12863             tl._startTime = 0;
12864             tl._rawPrevTime = tl._time = tl._totalTime = root._time;
12865             tween = root._first;
12866             while (tween) {
12867                 next = tween._next;
12868                 if (!ignoreDelayedCalls || !(tween instanceof TweenLite && tween.target === tween.vars.onComplete)) {
12869                     tl.add(tween, tween._startTime - tween._delay);
12870                 }
12871                 tween = next;
12872             }
12873             root.add(tl, 0);
12874             return tl;
12875         };
12876
12877         p.add = function(value, position, align, stagger) {
12878             var curTime, l, i, child, tl, beforeRawTime;
12879             if (typeof(position) !== "number") {
12880                 position = this._parseTimeOrLabel(position, 0, true, value);
12881             }
12882             if (!(value instanceof Animation)) {
12883                 if ((value instanceof Array) || (value && value.push && _isArray(value))) {
12884                     align = align || "normal";
12885                     stagger = stagger || 0;
12886                     curTime = position;
12887                     l = value.length;
12888                     for (i = 0; i < l; i++) {
12889                         if (_isArray(child = value[i])) {
12890                             child = new TimelineLite({tweens:child});
12891                         }
12892                         this.add(child, curTime);
12893                         if (typeof(child) !== "string" && typeof(child) !== "function") {
12894                             if (align === "sequence") {
12895                                 curTime = child._startTime + (child.totalDuration() / child._timeScale);
12896                             } else if (align === "start") {
12897                                 child._startTime -= child.delay();
12898                             }
12899                         }
12900                         curTime += stagger;
12901                     }
12902                     return this._uncache(true);
12903                 } else if (typeof(value) === "string") {
12904                     return this.addLabel(value, position);
12905                 } else if (typeof(value) === "function") {
12906                     value = TweenLite.delayedCall(0, value);
12907                 } else {
12908                     throw("Cannot add " + value + " into the timeline; it is not a tween, timeline, function, or string.");
12909                 }
12910             }
12911
12912             SimpleTimeline.prototype.add.call(this, value, position);
12913
12914             //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.
12915             if (this._gc || this._time === this._duration) if (!this._paused) if (this._duration < this.duration()) {
12916                 //in case any of the ancestors had completed but should now be enabled...
12917                 tl = this;
12918                 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.
12919                 while (tl._timeline) {
12920                     if (beforeRawTime && tl._timeline.smoothChildTiming) {
12921                         tl.totalTime(tl._totalTime, true); //moves the timeline (shifts its startTime) if necessary, and also enables it.
12922                     } else if (tl._gc) {
12923                         tl._enabled(true, false);
12924                     }
12925                     tl = tl._timeline;
12926                 }
12927             }
12928
12929             return this;
12930         };
12931
12932         p.remove = function(value) {
12933             if (value instanceof Animation) {
12934                 return this._remove(value, false);
12935             } else if (value instanceof Array || (value && value.push && _isArray(value))) {
12936                 var i = value.length;
12937                 while (--i > -1) {
12938                     this.remove(value[i]);
12939                 }
12940                 return this;
12941             } else if (typeof(value) === "string") {
12942                 return this.removeLabel(value);
12943             }
12944             return this.kill(null, value);
12945         };
12946
12947         p._remove = function(tween, skipDisable) {
12948             SimpleTimeline.prototype._remove.call(this, tween, skipDisable);
12949             var last = this._last;
12950             if (!last) {
12951                 this._time = this._totalTime = this._duration = this._totalDuration = 0;
12952             } else if (this._time > last._startTime + last._totalDuration / last._timeScale) {
12953                 this._time = this.duration();
12954                 this._totalTime = this._totalDuration;
12955             }
12956             return this;
12957         };
12958
12959         p.append = function(value, offsetOrLabel) {
12960             return this.add(value, this._parseTimeOrLabel(null, offsetOrLabel, true, value));
12961         };
12962
12963         p.insert = p.insertMultiple = function(value, position, align, stagger) {
12964             return this.add(value, position || 0, align, stagger);
12965         };
12966
12967         p.appendMultiple = function(tweens, offsetOrLabel, align, stagger) {
12968             return this.add(tweens, this._parseTimeOrLabel(null, offsetOrLabel, true, tweens), align, stagger);
12969         };
12970
12971         p.addLabel = function(label, position) {
12972             this._labels[label] = this._parseTimeOrLabel(position);
12973             return this;
12974         };
12975
12976         p.addPause = function(position, callback, params, scope) {
12977             return this.call(_pauseCallback, ["{self}", callback, params, scope], this, position);
12978         };
12979
12980         p.removeLabel = function(label) {
12981             delete this._labels[label];
12982             return this;
12983         };
12984
12985         p.getLabelTime = function(label) {
12986             return (this._labels[label] != null) ? this._labels[label] : -1;
12987         };
12988
12989         p._parseTimeOrLabel = function(timeOrLabel, offsetOrLabel, appendIfAbsent, ignore) {
12990             var i;
12991             //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().
12992             if (ignore instanceof Animation && ignore.timeline === this) {
12993                 this.remove(ignore);
12994             } else if (ignore && ((ignore instanceof Array) || (ignore.push && _isArray(ignore)))) {
12995                 i = ignore.length;
12996                 while (--i > -1) {
12997                     if (ignore[i] instanceof Animation && ignore[i].timeline === this) {
12998                         this.remove(ignore[i]);
12999                     }
13000                 }
13001             }
13002             if (typeof(offsetOrLabel) === "string") {
13003                 return this._parseTimeOrLabel(offsetOrLabel, (appendIfAbsent && typeof(timeOrLabel) === "number" && this._labels[offsetOrLabel] == null) ? timeOrLabel - this.duration() : 0, appendIfAbsent);
13004             }
13005             offsetOrLabel = offsetOrLabel || 0;
13006             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).
13007                 i = timeOrLabel.indexOf("=");
13008                 if (i === -1) {
13009                     if (this._labels[timeOrLabel] == null) {
13010                         return appendIfAbsent ? (this._labels[timeOrLabel] = this.duration() + offsetOrLabel) : offsetOrLabel;
13011                     }
13012                     return this._labels[timeOrLabel] + offsetOrLabel;
13013                 }
13014                 offsetOrLabel = parseInt(timeOrLabel.charAt(i-1) + "1", 10) * Number(timeOrLabel.substr(i+1));
13015                 timeOrLabel = (i > 1) ? this._parseTimeOrLabel(timeOrLabel.substr(0, i-1), 0, appendIfAbsent) : this.duration();
13016             } else if (timeOrLabel == null) {
13017                 timeOrLabel = this.duration();
13018             }
13019             return Number(timeOrLabel) + offsetOrLabel;
13020         };
13021
13022         p.seek = function(position, suppressEvents) {
13023             return this.totalTime((typeof(position) === "number") ? position : this._parseTimeOrLabel(position), (suppressEvents !== false));
13024         };
13025
13026         p.stop = function() {
13027             return this.paused(true);
13028         };
13029
13030         p.gotoAndPlay = function(position, suppressEvents) {
13031             return this.play(position, suppressEvents);
13032         };
13033
13034         p.gotoAndStop = function(position, suppressEvents) {
13035             return this.pause(position, suppressEvents);
13036         };
13037
13038         p.render = function(time, suppressEvents, force) {
13039             if (this._gc) {
13040                 this._enabled(true, false);
13041             }
13042             var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
13043                 prevTime = this._time,
13044                 prevStart = this._startTime,
13045                 prevTimeScale = this._timeScale,
13046                 prevPaused = this._paused,
13047                 tween, isComplete, next, callback, internalForce;
13048             if (time >= totalDur) {
13049                 this._totalTime = this._time = totalDur;
13050                 if (!this._reversed) if (!this._hasPausedChild()) {
13051                     isComplete = true;
13052                     callback = "onComplete";
13053                     if (this._duration === 0) if (time === 0 || this._rawPrevTime < 0 || this._rawPrevTime === _tinyNum) if (this._rawPrevTime !== time && this._first) {
13054                         internalForce = true;
13055                         if (this._rawPrevTime > _tinyNum) {
13056                             callback = "onReverseComplete";
13057                         }
13058                     }
13059                 }
13060                 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.
13061                 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.
13062
13063             } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
13064                 this._totalTime = this._time = 0;
13065                 if (prevTime !== 0 || (this._duration === 0 && this._rawPrevTime !== _tinyNum && (this._rawPrevTime > 0 || (time < 0 && this._rawPrevTime >= 0)))) {
13066                     callback = "onReverseComplete";
13067                     isComplete = this._reversed;
13068                 }
13069                 if (time < 0) {
13070                     this._active = false;
13071                     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.
13072                         internalForce = true;
13073                     }
13074                     this._rawPrevTime = time;
13075                 } else {
13076                     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.
13077
13078                     time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline)
13079                     if (!this._initted) {
13080                         internalForce = true;
13081                     }
13082                 }
13083
13084             } else {
13085                 this._totalTime = this._time = this._rawPrevTime = time;
13086             }
13087             if ((this._time === prevTime || !this._first) && !force && !internalForce) {
13088                 return;
13089             } else if (!this._initted) {
13090                 this._initted = true;
13091             }
13092
13093             if (!this._active) if (!this._paused && this._time !== prevTime && time > 0) {
13094                 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.
13095             }
13096
13097             if (prevTime === 0) if (this.vars.onStart) if (this._time !== 0) if (!suppressEvents) {
13098                 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
13099             }
13100
13101             if (this._time >= prevTime) {
13102                 tween = this._first;
13103                 while (tween) {
13104                     next = tween._next; //record it here because the value could change after rendering...
13105                     if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
13106                         break;
13107                     } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) {
13108                         if (!tween._reversed) {
13109                             tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
13110                         } else {
13111                             tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
13112                         }
13113                     }
13114                     tween = next;
13115                 }
13116             } else {
13117                 tween = this._last;
13118                 while (tween) {
13119                     next = tween._prev; //record it here because the value could change after rendering...
13120                     if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
13121                         break;
13122                     } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) {
13123                         if (!tween._reversed) {
13124                             tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
13125                         } else {
13126                             tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
13127                         }
13128                     }
13129                     tween = next;
13130                 }
13131             }
13132
13133             if (this._onUpdate) if (!suppressEvents) {
13134                 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
13135             }
13136
13137             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
13138                 if (isComplete) {
13139                     if (this._timeline.autoRemoveChildren) {
13140                         this._enabled(false, false);
13141                     }
13142                     this._active = false;
13143                 }
13144                 if (!suppressEvents && this.vars[callback]) {
13145                     this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
13146                 }
13147             }
13148         };
13149
13150         p._hasPausedChild = function() {
13151             var tween = this._first;
13152             while (tween) {
13153                 if (tween._paused || ((tween instanceof TimelineLite) && tween._hasPausedChild())) {
13154                     return true;
13155                 }
13156                 tween = tween._next;
13157             }
13158             return false;
13159         };
13160
13161         p.getChildren = function(nested, tweens, timelines, ignoreBeforeTime) {
13162             ignoreBeforeTime = ignoreBeforeTime || -9999999999;
13163             var a = [],
13164                 tween = this._first,
13165                 cnt = 0;
13166             while (tween) {
13167                 if (tween._startTime < ignoreBeforeTime) {
13168                     //do nothing
13169                 } else if (tween instanceof TweenLite) {
13170                     if (tweens !== false) {
13171                         a[cnt++] = tween;
13172                     }
13173                 } else {
13174                     if (timelines !== false) {
13175                         a[cnt++] = tween;
13176                     }
13177                     if (nested !== false) {
13178                         a = a.concat(tween.getChildren(true, tweens, timelines));
13179                         cnt = a.length;
13180                     }
13181                 }
13182                 tween = tween._next;
13183             }
13184             return a;
13185         };
13186
13187         p.getTweensOf = function(target, nested) {
13188             var disabled = this._gc,
13189                 a = [],
13190                 cnt = 0,
13191                 tweens, i;
13192             if (disabled) {
13193                 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.
13194             }
13195             tweens = TweenLite.getTweensOf(target);
13196             i = tweens.length;
13197             while (--i > -1) {
13198                 if (tweens[i].timeline === this || (nested && this._contains(tweens[i]))) {
13199                     a[cnt++] = tweens[i];
13200                 }
13201             }
13202             if (disabled) {
13203                 this._enabled(false, true);
13204             }
13205             return a;
13206         };
13207
13208         p._contains = function(tween) {
13209             var tl = tween.timeline;
13210             while (tl) {
13211                 if (tl === this) {
13212                     return true;
13213                 }
13214                 tl = tl.timeline;
13215             }
13216             return false;
13217         };
13218
13219         p.shiftChildren = function(amount, adjustLabels, ignoreBeforeTime) {
13220             ignoreBeforeTime = ignoreBeforeTime || 0;
13221             var tween = this._first,
13222                 labels = this._labels,
13223                 p;
13224             while (tween) {
13225                 if (tween._startTime >= ignoreBeforeTime) {
13226                     tween._startTime += amount;
13227                 }
13228                 tween = tween._next;
13229             }
13230             if (adjustLabels) {
13231                 for (p in labels) {
13232                     if (labels[p] >= ignoreBeforeTime) {
13233                         labels[p] += amount;
13234                     }
13235                 }
13236             }
13237             return this._uncache(true);
13238         };
13239
13240         p._kill = function(vars, target) {
13241             if (!vars && !target) {
13242                 return this._enabled(false, false);
13243             }
13244             var tweens = (!target) ? this.getChildren(true, true, false) : this.getTweensOf(target),
13245                 i = tweens.length,
13246                 changed = false;
13247             while (--i > -1) {
13248                 if (tweens[i]._kill(vars, target)) {
13249                     changed = true;
13250                 }
13251             }
13252             return changed;
13253         };
13254
13255         p.clear = function(labels) {
13256             var tweens = this.getChildren(false, true, true),
13257                 i = tweens.length;
13258             this._time = this._totalTime = 0;
13259             while (--i > -1) {
13260                 tweens[i]._enabled(false, false);
13261             }
13262             if (labels !== false) {
13263                 this._labels = {};
13264             }
13265             return this._uncache(true);
13266         };
13267
13268         p.invalidate = function() {
13269             var tween = this._first;
13270             while (tween) {
13271                 tween.invalidate();
13272                 tween = tween._next;
13273             }
13274             return this;
13275         };
13276
13277         p._enabled = function(enabled, ignoreTimeline) {
13278             if (enabled === this._gc) {
13279                 var tween = this._first;
13280                 while (tween) {
13281                     tween._enabled(enabled, true);
13282                     tween = tween._next;
13283                 }
13284             }
13285             return SimpleTimeline.prototype._enabled.call(this, enabled, ignoreTimeline);
13286         };
13287
13288         p.duration = function(value) {
13289             if (!arguments.length) {
13290                 if (this._dirty) {
13291                     this.totalDuration(); //just triggers recalculation
13292                 }
13293                 return this._duration;
13294             }
13295             if (this.duration() !== 0 && value !== 0) {
13296                 this.timeScale(this._duration / value);
13297             }
13298             return this;
13299         };
13300
13301         p.totalDuration = function(value) {
13302             if (!arguments.length) {
13303                 if (this._dirty) {
13304                     var max = 0,
13305                         tween = this._last,
13306                         prevStart = 999999999999,
13307                         prev, end;
13308                     while (tween) {
13309                         prev = tween._prev; //record it here in case the tween changes position in the sequence...
13310                         if (tween._dirty) {
13311                             tween.totalDuration(); //could change the tween._startTime, so make sure the tween's cache is clean before analyzing it.
13312                         }
13313                         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
13314                             this.add(tween, tween._startTime - tween._delay);
13315                         } else {
13316                             prevStart = tween._startTime;
13317                         }
13318                         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.
13319                             max -= tween._startTime;
13320                             if (this._timeline.smoothChildTiming) {
13321                                 this._startTime += tween._startTime / this._timeScale;
13322                             }
13323                             this.shiftChildren(-tween._startTime, false, -9999999999);
13324                             prevStart = 0;
13325                         }
13326                         end = tween._startTime + (tween._totalDuration / tween._timeScale);
13327                         if (end > max) {
13328                             max = end;
13329                         }
13330                         tween = prev;
13331                     }
13332                     this._duration = this._totalDuration = max;
13333                     this._dirty = false;
13334                 }
13335                 return this._totalDuration;
13336             }
13337             if (this.totalDuration() !== 0) if (value !== 0) {
13338                 this.timeScale(this._totalDuration / value);
13339             }
13340             return this;
13341         };
13342
13343         p.usesFrames = function() {
13344             var tl = this._timeline;
13345             while (tl._timeline) {
13346                 tl = tl._timeline;
13347             }
13348             return (tl === Animation._rootFramesTimeline);
13349         };
13350
13351         p.rawTime = function() {
13352             return this._paused ? this._totalTime : (this._timeline.rawTime() - this._startTime) * this._timeScale;
13353         };
13354
13355         return TimelineLite;
13356
13357     }, true);
13358     
13359
13360
13361
13362
13363
13364
13365
13366     
13367     
13368     
13369     
13370     
13371 /*
13372  * ----------------------------------------------------------------
13373  * TimelineMax
13374  * ----------------------------------------------------------------
13375  */
13376     window._gsDefine("TimelineMax", ["TimelineLite","TweenLite","easing.Ease"], function(TimelineLite, TweenLite, Ease) {
13377
13378         var TimelineMax = function(vars) {
13379                 TimelineLite.call(this, vars);
13380                 this._repeat = this.vars.repeat || 0;
13381                 this._repeatDelay = this.vars.repeatDelay || 0;
13382                 this._cycle = 0;
13383                 this._yoyo = (this.vars.yoyo === true);
13384                 this._dirty = true;
13385             },
13386             _tinyNum = 0.0000000001,
13387             _blankArray = [],
13388             _easeNone = new Ease(null, null, 1, 0),
13389             p = TimelineMax.prototype = new TimelineLite();
13390
13391         p.constructor = TimelineMax;
13392         p.kill()._gc = false;
13393         TimelineMax.version = "1.12.1";
13394
13395         p.invalidate = function() {
13396             this._yoyo = (this.vars.yoyo === true);
13397             this._repeat = this.vars.repeat || 0;
13398             this._repeatDelay = this.vars.repeatDelay || 0;
13399             this._uncache(true);
13400             return TimelineLite.prototype.invalidate.call(this);
13401         };
13402
13403         p.addCallback = function(callback, position, params, scope) {
13404             return this.add( TweenLite.delayedCall(0, callback, params, scope), position);
13405         };
13406
13407         p.removeCallback = function(callback, position) {
13408             if (callback) {
13409                 if (position == null) {
13410                     this._kill(null, callback);
13411                 } else {
13412                     var a = this.getTweensOf(callback, false),
13413                         i = a.length,
13414                         time = this._parseTimeOrLabel(position);
13415                     while (--i > -1) {
13416                         if (a[i]._startTime === time) {
13417                             a[i]._enabled(false, false);
13418                         }
13419                     }
13420                 }
13421             }
13422             return this;
13423         };
13424
13425         p.tweenTo = function(position, vars) {
13426             vars = vars || {};
13427             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.
13428                 duration, p, t;
13429             for (p in vars) {
13430                 copy[p] = vars[p];
13431             }
13432             copy.time = this._parseTimeOrLabel(position);
13433             duration = (Math.abs(Number(copy.time) - this._time) / this._timeScale) || 0.001;
13434             t = new TweenLite(this, duration, copy);
13435             copy.onStart = function() {
13436                 t.target.paused(true);
13437                 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.
13438                     t.duration( Math.abs( t.vars.time - t.target.time()) / t.target._timeScale );
13439                 }
13440                 if (vars.onStart) { //in case the user had an onStart in the vars - we don't want to overwrite it.
13441                     vars.onStart.apply(vars.onStartScope || t, vars.onStartParams || _blankArray);
13442                 }
13443             };
13444             return t;
13445         };
13446
13447         p.tweenFromTo = function(fromPosition, toPosition, vars) {
13448             vars = vars || {};
13449             fromPosition = this._parseTimeOrLabel(fromPosition);
13450             vars.startAt = {onComplete:this.seek, onCompleteParams:[fromPosition], onCompleteScope:this};
13451             vars.immediateRender = (vars.immediateRender !== false);
13452             var t = this.tweenTo(toPosition, vars);
13453             return t.duration((Math.abs( t.vars.time - fromPosition) / this._timeScale) || 0.001);
13454         };
13455
13456         p.render = function(time, suppressEvents, force) {
13457             if (this._gc) {
13458                 this._enabled(true, false);
13459             }
13460             var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
13461                 dur = this._duration,
13462                 prevTime = this._time,
13463                 prevTotalTime = this._totalTime,
13464                 prevStart = this._startTime,
13465                 prevTimeScale = this._timeScale,
13466                 prevRawPrevTime = this._rawPrevTime,
13467                 prevPaused = this._paused,
13468                 prevCycle = this._cycle,
13469                 tween, isComplete, next, callback, internalForce, cycleDuration;
13470             if (time >= totalDur) {
13471                 if (!this._locked) {
13472                     this._totalTime = totalDur;
13473                     this._cycle = this._repeat;
13474                 }
13475                 if (!this._reversed) if (!this._hasPausedChild()) {
13476                     isComplete = true;
13477                     callback = "onComplete";
13478                     if (this._duration === 0) if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time && this._first) {
13479                         internalForce = true;
13480                         if (prevRawPrevTime > _tinyNum) {
13481                             callback = "onReverseComplete";
13482                         }
13483                     }
13484                 }
13485                 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.
13486                 if (this._yoyo && (this._cycle & 1) !== 0) {
13487                     this._time = time = 0;
13488                 } else {
13489                     this._time = dur;
13490                     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.
13491                 }
13492
13493             } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
13494                 if (!this._locked) {
13495                     this._totalTime = this._cycle = 0;
13496                 }
13497                 this._time = 0;
13498                 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)
13499                     callback = "onReverseComplete";
13500                     isComplete = this._reversed;
13501                 }
13502                 if (time < 0) {
13503                     this._active = false;
13504                     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.
13505                         internalForce = true;
13506                     }
13507                     this._rawPrevTime = time;
13508                 } else {
13509                     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.
13510                     time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline)
13511                     if (!this._initted) {
13512                         internalForce = true;
13513                     }
13514                 }
13515
13516             } else {
13517                 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.
13518                     internalForce = true;
13519                 }
13520                 this._time = this._rawPrevTime = time;
13521                 if (!this._locked) {
13522                     this._totalTime = time;
13523                     if (this._repeat !== 0) {
13524                         cycleDuration = dur + this._repeatDelay;
13525                         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!)
13526                         if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) {
13527                             this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning)
13528                         }
13529                         this._time = this._totalTime - (this._cycle * cycleDuration);
13530                         if (this._yoyo) if ((this._cycle & 1) !== 0) {
13531                             this._time = dur - this._time;
13532                         }
13533                         if (this._time > dur) {
13534                             this._time = dur;
13535                             time = dur + 0.0001; //to avoid occasional floating point rounding error
13536                         } else if (this._time < 0) {
13537                             this._time = time = 0;
13538                         } else {
13539                             time = this._time;
13540                         }
13541                     }
13542                 }
13543             }
13544
13545             if (this._cycle !== prevCycle) if (!this._locked) {
13546                 /*
13547                 make sure children at the end/beginning of the timeline are rendered properly. If, for example,
13548                 a 3-second long timeline rendered at 2.9 seconds previously, and now renders at 3.2 seconds (which
13549                 would get transated to 2.8 seconds if the timeline yoyos or 0.2 seconds if it just repeats), there
13550                 could be a callback or a short tween that's at 2.95 or 3 seconds in which wouldn't render. So
13551                 we need to push the timeline to the end (and/or beginning depending on its yoyo value). Also we must
13552                 ensure that zero-duration tweens at the very beginning or end of the TimelineMax work.
13553                 */
13554                 var backwards = (this._yoyo && (prevCycle & 1) !== 0),
13555                     wrap = (backwards === (this._yoyo && (this._cycle & 1) !== 0)),
13556                     recTotalTime = this._totalTime,
13557                     recCycle = this._cycle,
13558                     recRawPrevTime = this._rawPrevTime,
13559                     recTime = this._time;
13560
13561                 this._totalTime = prevCycle * dur;
13562                 if (this._cycle < prevCycle) {
13563                     backwards = !backwards;
13564                 } else {
13565                     this._totalTime += dur;
13566                 }
13567                 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.
13568
13569                 this._rawPrevTime = (dur === 0) ? prevRawPrevTime - 0.0001 : prevRawPrevTime;
13570                 this._cycle = prevCycle;
13571                 this._locked = true; //prevents changes to totalTime and skips repeat/yoyo behavior when we recursively call render()
13572                 prevTime = (backwards) ? 0 : dur;
13573                 this.render(prevTime, suppressEvents, (dur === 0));
13574                 if (!suppressEvents) if (!this._gc) {
13575                     if (this.vars.onRepeat) {
13576                         this.vars.onRepeat.apply(this.vars.onRepeatScope || this, this.vars.onRepeatParams || _blankArray);
13577                     }
13578                 }
13579                 if (wrap) {
13580                     prevTime = (backwards) ? dur + 0.0001 : -0.0001;
13581                     this.render(prevTime, true, false);
13582                 }
13583                 this._locked = false;
13584                 if (this._paused && !prevPaused) { //if the render() triggered callback that paused this timeline, we should abort (very rare, but possible)
13585                     return;
13586                 }
13587                 this._time = recTime;
13588                 this._totalTime = recTotalTime;
13589                 this._cycle = recCycle;
13590                 this._rawPrevTime = recRawPrevTime;
13591             }
13592
13593             if ((this._time === prevTime || !this._first) && !force && !internalForce) {
13594                 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.
13595                     this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
13596                 }
13597                 return;
13598             } else if (!this._initted) {
13599                 this._initted = true;
13600             }
13601
13602             if (!this._active) if (!this._paused && this._totalTime !== prevTotalTime && time > 0) {
13603                 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.
13604             }
13605
13606             if (prevTotalTime === 0) if (this.vars.onStart) if (this._totalTime !== 0) if (!suppressEvents) {
13607                 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
13608             }
13609
13610             if (this._time >= prevTime) {
13611                 tween = this._first;
13612                 while (tween) {
13613                     next = tween._next; //record it here because the value could change after rendering...
13614                     if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
13615                         break;
13616                     } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) {
13617                         if (!tween._reversed) {
13618                             tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
13619                         } else {
13620                             tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
13621                         }
13622
13623                     }
13624                     tween = next;
13625                 }
13626             } else {
13627                 tween = this._last;
13628                 while (tween) {
13629                     next = tween._prev; //record it here because the value could change after rendering...
13630                     if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
13631                         break;
13632                     } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) {
13633                         if (!tween._reversed) {
13634                             tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
13635                         } else {
13636                             tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
13637                         }
13638                     }
13639                     tween = next;
13640                 }
13641             }
13642
13643             if (this._onUpdate) if (!suppressEvents) {
13644                 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
13645             }
13646             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
13647                 if (isComplete) {
13648                     if (this._timeline.autoRemoveChildren) {
13649                         this._enabled(false, false);
13650                     }
13651                     this._active = false;
13652                 }
13653                 if (!suppressEvents && this.vars[callback]) {
13654                     this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
13655                 }
13656             }
13657         };
13658
13659         p.getActive = function(nested, tweens, timelines) {
13660             if (nested == null) {
13661                 nested = true;
13662             }
13663             if (tweens == null) {
13664                 tweens = true;
13665             }
13666             if (timelines == null) {
13667                 timelines = false;
13668             }
13669             var a = [],
13670                 all = this.getChildren(nested, tweens, timelines),
13671                 cnt = 0,
13672                 l = all.length,
13673                 i, tween;
13674             for (i = 0; i < l; i++) {
13675                 tween = all[i];
13676                 if (tween.isActive()) {
13677                     a[cnt++] = tween;
13678                 }
13679             }
13680             return a;
13681         };
13682
13683
13684         p.getLabelAfter = function(time) {
13685             if (!time) if (time !== 0) { //faster than isNan()
13686                 time = this._time;
13687             }
13688             var labels = this.getLabelsArray(),
13689                 l = labels.length,
13690                 i;
13691             for (i = 0; i < l; i++) {
13692                 if (labels[i].time > time) {
13693                     return labels[i].name;
13694                 }
13695             }
13696             return null;
13697         };
13698
13699         p.getLabelBefore = function(time) {
13700             if (time == null) {
13701                 time = this._time;
13702             }
13703             var labels = this.getLabelsArray(),
13704                 i = labels.length;
13705             while (--i > -1) {
13706                 if (labels[i].time < time) {
13707                     return labels[i].name;
13708                 }
13709             }
13710             return null;
13711         };
13712
13713         p.getLabelsArray = function() {
13714             var a = [],
13715                 cnt = 0,
13716                 p;
13717             for (p in this._labels) {
13718                 a[cnt++] = {time:this._labels[p], name:p};
13719             }
13720             a.sort(function(a,b) {
13721                 return a.time - b.time;
13722             });
13723             return a;
13724         };
13725
13726
13727 //---- GETTERS / SETTERS -------------------------------------------------------------------------------------------------------
13728
13729         p.progress = function(value) {
13730             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);
13731         };
13732
13733         p.totalProgress = function(value) {
13734             return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, false);
13735         };
13736
13737         p.totalDuration = function(value) {
13738             if (!arguments.length) {
13739                 if (this._dirty) {
13740                     TimelineLite.prototype.totalDuration.call(this); //just forces refresh
13741                     //Instead of Infinity, we use 999999999999 so that we can accommodate reverses.
13742                     this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat);
13743                 }
13744                 return this._totalDuration;
13745             }
13746             return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) );
13747         };
13748
13749         p.time = function(value, suppressEvents) {
13750             if (!arguments.length) {
13751                 return this._time;
13752             }
13753             if (this._dirty) {
13754                 this.totalDuration();
13755             }
13756             if (value > this._duration) {
13757                 value = this._duration;
13758             }
13759             if (this._yoyo && (this._cycle & 1) !== 0) {
13760                 value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay));
13761             } else if (this._repeat !== 0) {
13762                 value += this._cycle * (this._duration + this._repeatDelay);
13763             }
13764             return this.totalTime(value, suppressEvents);
13765         };
13766
13767         p.repeat = function(value) {
13768             if (!arguments.length) {
13769                 return this._repeat;
13770             }
13771             this._repeat = value;
13772             return this._uncache(true);
13773         };
13774
13775         p.repeatDelay = function(value) {
13776             if (!arguments.length) {
13777                 return this._repeatDelay;
13778             }
13779             this._repeatDelay = value;
13780             return this._uncache(true);
13781         };
13782
13783         p.yoyo = function(value) {
13784             if (!arguments.length) {
13785                 return this._yoyo;
13786             }
13787             this._yoyo = value;
13788             return this;
13789         };
13790
13791         p.currentLabel = function(value) {
13792             if (!arguments.length) {
13793                 return this.getLabelBefore(this._time + 0.00000001);
13794             }
13795             return this.seek(value, true);
13796         };
13797
13798         return TimelineMax;
13799
13800     }, true);
13801     
13802
13803
13804
13805
13806     
13807     
13808     
13809     
13810     
13811     
13812     
13813 /*
13814  * ----------------------------------------------------------------
13815  * BezierPlugin
13816  * ----------------------------------------------------------------
13817  */
13818     (function() {
13819
13820         var _RAD2DEG = 180 / Math.PI,
13821             _r1 = [],
13822             _r2 = [],
13823             _r3 = [],
13824             _corProps = {},
13825             Segment = function(a, b, c, d) {
13826                 this.a = a;
13827                 this.b = b;
13828                 this.c = c;
13829                 this.d = d;
13830                 this.da = d - a;
13831                 this.ca = c - a;
13832                 this.ba = b - a;
13833             },
13834             _correlate = ",x,y,z,left,top,right,bottom,marginTop,marginLeft,marginRight,marginBottom,paddingLeft,paddingTop,paddingRight,paddingBottom,backgroundPosition,backgroundPosition_y,",
13835             cubicToQuadratic = function(a, b, c, d) {
13836                 var q1 = {a:a},
13837                     q2 = {},
13838                     q3 = {},
13839                     q4 = {c:d},
13840                     mab = (a + b) / 2,
13841                     mbc = (b + c) / 2,
13842                     mcd = (c + d) / 2,
13843                     mabc = (mab + mbc) / 2,
13844                     mbcd = (mbc + mcd) / 2,
13845                     m8 = (mbcd - mabc) / 8;
13846                 q1.b = mab + (a - mab) / 4;
13847                 q2.b = mabc + m8;
13848                 q1.c = q2.a = (q1.b + q2.b) / 2;
13849                 q2.c = q3.a = (mabc + mbcd) / 2;
13850                 q3.b = mbcd - m8;
13851                 q4.b = mcd + (d - mcd) / 4;
13852                 q3.c = q4.a = (q3.b + q4.b) / 2;
13853                 return [q1, q2, q3, q4];
13854             },
13855             _calculateControlPoints = function(a, curviness, quad, basic, correlate) {
13856                 var l = a.length - 1,
13857                     ii = 0,
13858                     cp1 = a[0].a,
13859                     i, p1, p2, p3, seg, m1, m2, mm, cp2, qb, r1, r2, tl;
13860                 for (i = 0; i < l; i++) {
13861                     seg = a[ii];
13862                     p1 = seg.a;
13863                     p2 = seg.d;
13864                     p3 = a[ii+1].d;
13865
13866                     if (correlate) {
13867                         r1 = _r1[i];
13868                         r2 = _r2[i];
13869                         tl = ((r2 + r1) * curviness * 0.25) / (basic ? 0.5 : _r3[i] || 0.5);
13870                         m1 = p2 - (p2 - p1) * (basic ? curviness * 0.5 : (r1 !== 0 ? tl / r1 : 0));
13871                         m2 = p2 + (p3 - p2) * (basic ? curviness * 0.5 : (r2 !== 0 ? tl / r2 : 0));
13872                         mm = p2 - (m1 + (((m2 - m1) * ((r1 * 3 / (r1 + r2)) + 0.5) / 4) || 0));
13873                     } else {
13874                         m1 = p2 - (p2 - p1) * curviness * 0.5;
13875                         m2 = p2 + (p3 - p2) * curviness * 0.5;
13876                         mm = p2 - (m1 + m2) / 2;
13877                     }
13878                     m1 += mm;
13879                     m2 += mm;
13880
13881                     seg.c = cp2 = m1;
13882                     if (i !== 0) {
13883                         seg.b = cp1;
13884                     } else {
13885                         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.
13886                     }
13887
13888                     seg.da = p2 - p1;
13889                     seg.ca = cp2 - p1;
13890                     seg.ba = cp1 - p1;
13891
13892                     if (quad) {
13893                         qb = cubicToQuadratic(p1, cp1, cp2, p2);
13894                         a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]);
13895                         ii += 4;
13896                     } else {
13897                         ii++;
13898                     }
13899
13900                     cp1 = m2;
13901                 }
13902                 seg = a[ii];
13903                 seg.b = cp1;
13904                 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.
13905                 seg.da = seg.d - seg.a;
13906                 seg.ca = seg.c - seg.a;
13907                 seg.ba = cp1 - seg.a;
13908                 if (quad) {
13909                     qb = cubicToQuadratic(seg.a, cp1, seg.c, seg.d);
13910                     a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]);
13911                 }
13912             },
13913             _parseAnchors = function(values, p, correlate, prepend) {
13914                 var a = [],
13915                     l, i, p1, p2, p3, tmp;
13916                 if (prepend) {
13917                     values = [prepend].concat(values);
13918                     i = values.length;
13919                     while (--i > -1) {
13920                         if (typeof( (tmp = values[i][p]) ) === "string") if (tmp.charAt(1) === "=") {
13921                             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
13922                         }
13923                     }
13924                 }
13925                 l = values.length - 2;
13926                 if (l < 0) {
13927                     a[0] = new Segment(values[0][p], 0, 0, values[(l < -1) ? 0 : 1][p]);
13928                     return a;
13929                 }
13930                 for (i = 0; i < l; i++) {
13931                     p1 = values[i][p];
13932                     p2 = values[i+1][p];
13933                     a[i] = new Segment(p1, 0, 0, p2);
13934                     if (correlate) {
13935                         p3 = values[i+2][p];
13936                         _r1[i] = (_r1[i] || 0) + (p2 - p1) * (p2 - p1);
13937                         _r2[i] = (_r2[i] || 0) + (p3 - p2) * (p3 - p2);
13938                     }
13939                 }
13940                 a[i] = new Segment(values[i][p], 0, 0, values[i+1][p]);
13941                 return a;
13942             },
13943             bezierThrough = function(values, curviness, quadratic, basic, correlate, prepend) {
13944                 var obj = {},
13945                     props = [],
13946                     first = prepend || values[0],
13947                     i, p, a, j, r, l, seamless, last;
13948                 correlate = (typeof(correlate) === "string") ? ","+correlate+"," : _correlate;
13949                 if (curviness == null) {
13950                     curviness = 1;
13951                 }
13952                 for (p in values[0]) {
13953                     props.push(p);
13954                 }
13955                 //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)
13956                 if (values.length > 1) {
13957                     last = values[values.length - 1];
13958                     seamless = true;
13959                     i = props.length;
13960                     while (--i > -1) {
13961                         p = props[i];
13962                         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
13963                             seamless = false;
13964                             break;
13965                         }
13966                     }
13967                     if (seamless) {
13968                         values = values.concat(); //duplicate the array to avoid contaminating the original which the user may be reusing for other tweens
13969                         if (prepend) {
13970                             values.unshift(prepend);
13971                         }
13972                         values.push(values[1]);
13973                         prepend = values[values.length - 3];
13974                     }
13975                 }
13976                 _r1.length = _r2.length = _r3.length = 0;
13977                 i = props.length;
13978                 while (--i > -1) {
13979                     p = props[i];
13980                     _corProps[p] = (correlate.indexOf(","+p+",") !== -1);
13981                     obj[p] = _parseAnchors(values, p, _corProps[p], prepend);
13982                 }
13983                 i = _r1.length;
13984                 while (--i > -1) {
13985                     _r1[i] = Math.sqrt(_r1[i]);
13986                     _r2[i] = Math.sqrt(_r2[i]);
13987                 }
13988                 if (!basic) {
13989                     i = props.length;
13990                     while (--i > -1) {
13991                         if (_corProps[p]) {
13992                             a = obj[props[i]];
13993                             l = a.length - 1;
13994                             for (j = 0; j < l; j++) {
13995                                 r = a[j+1].da / _r2[j] + a[j].da / _r1[j];
13996                                 _r3[j] = (_r3[j] || 0) + r * r;
13997                             }
13998                         }
13999                     }
14000                     i = _r3.length;
14001                     while (--i > -1) {
14002                         _r3[i] = Math.sqrt(_r3[i]);
14003                     }
14004                 }
14005                 i = props.length;
14006                 j = quadratic ? 4 : 1;
14007                 while (--i > -1) {
14008                     p = props[i];
14009                     a = obj[p];
14010                     _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
14011                     if (seamless) {
14012                         a.splice(0, j);
14013                         a.splice(a.length - j, j);
14014                     }
14015                 }
14016                 return obj;
14017             },
14018             _parseBezierData = function(values, type, prepend) {
14019                 type = type || "soft";
14020                 var obj = {},
14021                     inc = (type === "cubic") ? 3 : 2,
14022                     soft = (type === "soft"),
14023                     props = [],
14024                     a, b, c, d, cur, i, j, l, p, cnt, tmp;
14025                 if (soft && prepend) {
14026                     values = [prepend].concat(values);
14027                 }
14028                 if (values == null || values.length < inc + 1) { throw "invalid Bezier data"; }
14029                 for (p in values[0]) {
14030                     props.push(p);
14031                 }
14032                 i = props.length;
14033                 while (--i > -1) {
14034                     p = props[i];
14035                     obj[p] = cur = [];
14036                     cnt = 0;
14037                     l = values.length;
14038                     for (j = 0; j < l; j++) {
14039                         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);
14040                         if (soft) if (j > 1) if (j < l - 1) {
14041                             cur[cnt++] = (a + cur[cnt-2]) / 2;
14042                         }
14043                         cur[cnt++] = a;
14044                     }
14045                     l = cnt - inc + 1;
14046                     cnt = 0;
14047                     for (j = 0; j < l; j += inc) {
14048                         a = cur[j];
14049                         b = cur[j+1];
14050                         c = cur[j+2];
14051                         d = (inc === 2) ? 0 : cur[j+3];
14052                         cur[cnt++] = tmp = (inc === 3) ? new Segment(a, b, c, d) : new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c);
14053                     }
14054                     cur.length = cnt;
14055                 }
14056                 return obj;
14057             },
14058             _addCubicLengths = function(a, steps, resolution) {
14059                 var inc = 1 / resolution,
14060                     j = a.length,
14061                     d, d1, s, da, ca, ba, p, i, inv, bez, index;
14062                 while (--j > -1) {
14063                     bez = a[j];
14064                     s = bez.a;
14065                     da = bez.d - s;
14066                     ca = bez.c - s;
14067                     ba = bez.b - s;
14068                     d = d1 = 0;
14069                     for (i = 1; i <= resolution; i++) {
14070                         p = inc * i;
14071                         inv = 1 - p;
14072                         d = d1 - (d1 = (p * p * da + 3 * inv * (p * ca + inv * ba)) * p);
14073                         index = j * resolution + i - 1;
14074                         steps[index] = (steps[index] || 0) + d * d;
14075                     }
14076                 }
14077             },
14078             _parseLengthData = function(obj, resolution) {
14079                 resolution = resolution >> 0 || 6;
14080                 var a = [],
14081                     lengths = [],
14082                     d = 0,
14083                     total = 0,
14084                     threshold = resolution - 1,
14085                     segments = [],
14086                     curLS = [], //current length segments array
14087                     p, i, l, index;
14088                 for (p in obj) {
14089                     _addCubicLengths(obj[p], a, resolution);
14090                 }
14091                 l = a.length;
14092                 for (i = 0; i < l; i++) {
14093                     d += Math.sqrt(a[i]);
14094                     index = i % resolution;
14095                     curLS[index] = d;
14096                     if (index === threshold) {
14097                         total += d;
14098                         index = (i / resolution) >> 0;
14099                         segments[index] = curLS;
14100                         lengths[index] = total;
14101                         d = 0;
14102                         curLS = [];
14103                     }
14104                 }
14105                 return {length:total, lengths:lengths, segments:segments};
14106             },
14107
14108
14109
14110             BezierPlugin = window._gsDefine.plugin({
14111                     propName: "bezier",
14112                     priority: -1,
14113                     version: "1.3.2",
14114                     API: 2,
14115                     global:true,
14116
14117                     //gets called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
14118                     init: function(target, vars, tween) {
14119                         this._target = target;
14120                         if (vars instanceof Array) {
14121                             vars = {values:vars};
14122                         }
14123                         this._func = {};
14124                         this._round = {};
14125                         this._props = [];
14126                         this._timeRes = (vars.timeResolution == null) ? 6 : parseInt(vars.timeResolution, 10);
14127                         var values = vars.values || [],
14128                             first = {},
14129                             second = values[0],
14130                             autoRotate = vars.autoRotate || tween.vars.orientToBezier,
14131                             p, isFunc, i, j, prepend;
14132
14133                         this._autoRotate = autoRotate ? (autoRotate instanceof Array) ? autoRotate : [["x","y","rotation",((autoRotate === true) ? 0 : Number(autoRotate) || 0)]] : null;
14134                         for (p in second) {
14135                             this._props.push(p);
14136                         }
14137
14138                         i = this._props.length;
14139                         while (--i > -1) {
14140                             p = this._props[i];
14141
14142                             this._overwriteProps.push(p);
14143                             isFunc = this._func[p] = (typeof(target[p]) === "function");
14144                             first[p] = (!isFunc) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();
14145                             if (!prepend) if (first[p] !== values[0][p]) {
14146                                 prepend = first;
14147                             }
14148                         }
14149                         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);
14150                         this._segCount = this._beziers[p].length;
14151
14152                         if (this._timeRes) {
14153                             var ld = _parseLengthData(this._beziers, this._timeRes);
14154                             this._length = ld.length;
14155                             this._lengths = ld.lengths;
14156                             this._segments = ld.segments;
14157                             this._l1 = this._li = this._s1 = this._si = 0;
14158                             this._l2 = this._lengths[0];
14159                             this._curSeg = this._segments[0];
14160                             this._s2 = this._curSeg[0];
14161                             this._prec = 1 / this._curSeg.length;
14162                         }
14163
14164                         if ((autoRotate = this._autoRotate)) {
14165                             this._initialRotations = [];
14166                             if (!(autoRotate[0] instanceof Array)) {
14167                                 this._autoRotate = autoRotate = [autoRotate];
14168                             }
14169                             i = autoRotate.length;
14170                             while (--i > -1) {
14171                                 for (j = 0; j < 3; j++) {
14172                                     p = autoRotate[i][j];
14173                                     this._func[p] = (typeof(target[p]) === "function") ? target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ] : false;
14174                                 }
14175                                 p = autoRotate[i][2];
14176                                 this._initialRotations[i] = this._func[p] ? this._func[p].call(this._target) : this._target[p];
14177                             }
14178                         }
14179                         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.
14180                         return true;
14181                     },
14182
14183                     //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.)
14184                     set: function(v) {
14185                         var segments = this._segCount,
14186                             func = this._func,
14187                             target = this._target,
14188                             notStart = (v !== this._startRatio),
14189                             curIndex, inv, i, p, b, t, val, l, lengths, curSeg;
14190                         if (!this._timeRes) {
14191                             curIndex = (v < 0) ? 0 : (v >= 1) ? segments - 1 : (segments * v) >> 0;
14192                             t = (v - (curIndex * (1 / segments))) * segments;
14193                         } else {
14194                             lengths = this._lengths;
14195                             curSeg = this._curSeg;
14196                             v *= this._length;
14197                             i = this._li;
14198                             //find the appropriate segment (if the currently cached one isn't correct)
14199                             if (v > this._l2 && i < segments - 1) {
14200                                 l = segments - 1;
14201                                 while (i < l && (this._l2 = lengths[++i]) <= v) {   }
14202                                 this._l1 = lengths[i-1];
14203                                 this._li = i;
14204                                 this._curSeg = curSeg = this._segments[i];
14205                                 this._s2 = curSeg[(this._s1 = this._si = 0)];
14206                             } else if (v < this._l1 && i > 0) {
14207                                 while (i > 0 && (this._l1 = lengths[--i]) >= v) { }
14208                                 if (i === 0 && v < this._l1) {
14209                                     this._l1 = 0;
14210                                 } else {
14211                                     i++;
14212                                 }
14213                                 this._l2 = lengths[i];
14214                                 this._li = i;
14215                                 this._curSeg = curSeg = this._segments[i];
14216                                 this._s1 = curSeg[(this._si = curSeg.length - 1) - 1] || 0;
14217                                 this._s2 = curSeg[this._si];
14218                             }
14219                             curIndex = i;
14220                             //now find the appropriate sub-segment (we split it into the number of pieces that was defined by "precision" and measured each one)
14221                             v -= this._l1;
14222                             i = this._si;
14223                             if (v > this._s2 && i < curSeg.length - 1) {
14224                                 l = curSeg.length - 1;
14225                                 while (i < l && (this._s2 = curSeg[++i]) <= v) {    }
14226                                 this._s1 = curSeg[i-1];
14227                                 this._si = i;
14228                             } else if (v < this._s1 && i > 0) {
14229                                 while (i > 0 && (this._s1 = curSeg[--i]) >= v) {    }
14230                                 if (i === 0 && v < this._s1) {
14231                                     this._s1 = 0;
14232                                 } else {
14233                                     i++;
14234                                 }
14235                                 this._s2 = curSeg[i];
14236                                 this._si = i;
14237                             }
14238                             t = (i + (v - this._s1) / (this._s2 - this._s1)) * this._prec;
14239                         }
14240                         inv = 1 - t;
14241
14242                         i = this._props.length;
14243                         while (--i > -1) {
14244                             p = this._props[i];
14245                             b = this._beziers[p][curIndex];
14246                             val = (t * t * b.da + 3 * inv * (t * b.ca + inv * b.ba)) * t + b.a;
14247                             if (this._round[p]) {
14248                                 val = Math.round(val);
14249                             }
14250                             if (func[p]) {
14251                                 target[p](val);
14252                             } else {
14253                                 target[p] = val;
14254                             }
14255                         }
14256
14257                         if (this._autoRotate) {
14258                             var ar = this._autoRotate,
14259                                 b2, x1, y1, x2, y2, add, conv;
14260                             i = ar.length;
14261                             while (--i > -1) {
14262                                 p = ar[i][2];
14263                                 add = ar[i][3] || 0;
14264                                 conv = (ar[i][4] === true) ? 1 : _RAD2DEG;
14265                                 b = this._beziers[ar[i][0]];
14266                                 b2 = this._beziers[ar[i][1]];
14267
14268                                 if (b && b2) { //in case one of the properties got overwritten.
14269                                     b = b[curIndex];
14270                                     b2 = b2[curIndex];
14271
14272                                     x1 = b.a + (b.b - b.a) * t;
14273                                     x2 = b.b + (b.c - b.b) * t;
14274                                     x1 += (x2 - x1) * t;
14275                                     x2 += ((b.c + (b.d - b.c) * t) - x2) * t;
14276
14277                                     y1 = b2.a + (b2.b - b2.a) * t;
14278                                     y2 = b2.b + (b2.c - b2.b) * t;
14279                                     y1 += (y2 - y1) * t;
14280                                     y2 += ((b2.c + (b2.d - b2.c) * t) - y2) * t;
14281
14282                                     val = notStart ? Math.atan2(y2 - y1, x2 - x1) * conv + add : this._initialRotations[i];
14283
14284                                     if (func[p]) {
14285                                         target[p](val);
14286                                     } else {
14287                                         target[p] = val;
14288                                     }
14289                                 }
14290                             }
14291                         }
14292                     }
14293             }),
14294             p = BezierPlugin.prototype;
14295
14296
14297         BezierPlugin.bezierThrough = bezierThrough;
14298         BezierPlugin.cubicToQuadratic = cubicToQuadratic;
14299         BezierPlugin._autoCSS = true; //indicates that this plugin can be inserted into the "css" object using the autoCSS feature of TweenLite
14300         BezierPlugin.quadraticToCubic = function(a, b, c) {
14301             return new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c);
14302         };
14303
14304         BezierPlugin._cssRegister = function() {
14305             var CSSPlugin = window._gsDefine.globals.CSSPlugin;
14306             if (!CSSPlugin) {
14307                 return;
14308             }
14309             var _internals = CSSPlugin._internals,
14310                 _parseToProxy = _internals._parseToProxy,
14311                 _setPluginRatio = _internals._setPluginRatio,
14312                 CSSPropTween = _internals.CSSPropTween;
14313             _internals._registerComplexSpecialProp("bezier", {parser:function(t, e, prop, cssp, pt, plugin) {
14314                 if (e instanceof Array) {
14315                     e = {values:e};
14316                 }
14317                 plugin = new BezierPlugin();
14318                 var values = e.values,
14319                     l = values.length - 1,
14320                     pluginValues = [],
14321                     v = {},
14322                     i, p, data;
14323                 if (l < 0) {
14324                     return pt;
14325                 }
14326                 for (i = 0; i <= l; i++) {
14327                     data = _parseToProxy(t, values[i], cssp, pt, plugin, (l !== i));
14328                     pluginValues[i] = data.end;
14329                 }
14330                 for (p in e) {
14331                     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.
14332                 }
14333                 v.values = pluginValues;
14334                 pt = new CSSPropTween(t, "bezier", 0, 0, data.pt, 2);
14335                 pt.data = data;
14336                 pt.plugin = plugin;
14337                 pt.setRatio = _setPluginRatio;
14338                 if (v.autoRotate === 0) {
14339                     v.autoRotate = true;
14340                 }
14341                 if (v.autoRotate && !(v.autoRotate instanceof Array)) {
14342                     i = (v.autoRotate === true) ? 0 : Number(v.autoRotate);
14343                     v.autoRotate = (data.end.left != null) ? [["left","top","rotation",i,false]] : (data.end.x != null) ? [["x","y","rotation",i,false]] : false;
14344                 }
14345                 if (v.autoRotate) {
14346                     if (!cssp._transform) {
14347                         cssp._enableTransforms(false);
14348                     }
14349                     data.autoRotate = cssp._target._gsTransform;
14350                 }
14351                 plugin._onInitTween(data.proxy, v, cssp._tween);
14352                 return pt;
14353             }});
14354         };
14355
14356         p._roundProps = function(lookup, value) {
14357             var op = this._overwriteProps,
14358                 i = op.length;
14359             while (--i > -1) {
14360                 if (lookup[op[i]] || lookup.bezier || lookup.bezierThrough) {
14361                     this._round[op[i]] = value;
14362                 }
14363             }
14364         };
14365
14366         p._kill = function(lookup) {
14367             var a = this._props,
14368                 p, i;
14369             for (p in this._beziers) {
14370                 if (p in lookup) {
14371                     delete this._beziers[p];
14372                     delete this._func[p];
14373                     i = a.length;
14374                     while (--i > -1) {
14375                         if (a[i] === p) {
14376                             a.splice(i, 1);
14377                         }
14378                     }
14379                 }
14380             }
14381             return this._super._kill.call(this, lookup);
14382         };
14383
14384     }());
14385
14386
14387
14388
14389
14390
14391     
14392     
14393     
14394     
14395     
14396     
14397     
14398     
14399 /*
14400  * ----------------------------------------------------------------
14401  * CSSPlugin
14402  * ----------------------------------------------------------------
14403  */
14404     window._gsDefine("plugins.CSSPlugin", ["plugins.TweenPlugin","TweenLite"], function(TweenPlugin, TweenLite) {
14405
14406         /** @constructor **/
14407         var CSSPlugin = function() {
14408                 TweenPlugin.call(this, "css");
14409                 this._overwriteProps.length = 0;
14410                 this.setRatio = CSSPlugin.prototype.setRatio; //speed optimization (avoid prototype lookup on this "hot" method)
14411             },
14412             _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.
14413             _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
14414             _cs, //computed style (we store this in a shared variable to conserve memory and make minification tighter
14415             _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.
14416             _specialProps = {},
14417             p = CSSPlugin.prototype = new TweenPlugin("css");
14418
14419         p.constructor = CSSPlugin;
14420         CSSPlugin.version = "1.12.1";
14421         CSSPlugin.API = 2;
14422         CSSPlugin.defaultTransformPerspective = 0;
14423         CSSPlugin.defaultSkewType = "compensated";
14424         p = "px"; //we'll reuse the "p" variable to keep file size down
14425         CSSPlugin.suffixMap = {top:p, right:p, bottom:p, left:p, width:p, height:p, fontSize:p, padding:p, margin:p, perspective:p, lineHeight:""};
14426
14427
14428         var _numExp = /(?:\d|\-\d|\.\d|\-\.\d)+/g,
14429             _relNumExp = /(?:\d|\-\d|\.\d|\-\.\d|\+=\d|\-=\d|\+=.\d|\-=\.\d)+/g,
14430             _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)"
14431             _NaNExp = /[^\d\-\.]/g,
14432             _suffixExp = /(?:\d|\-|\+|=|#|\.)*/g,
14433             _opacityExp = /opacity *= *([^)]*)/i,
14434             _opacityValExp = /opacity:([^;]*)/i,
14435             _alphaFilterExp = /alpha\(opacity *=.+?\)/i,
14436             _rgbhslExp = /^(rgb|hsl)/,
14437             _capsExp = /([A-Z])/g,
14438             _camelExp = /-([a-z])/gi,
14439             _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)
14440             _camelFunc = function(s, g) { return g.toUpperCase(); },
14441             _horizExp = /(?:Left|Right|Width)/i,
14442             _ieGetMatrixExp = /(M11|M12|M21|M22)=[\d\-\.e]+/gi,
14443             _ieSetMatrixExp = /progid\:DXImageTransform\.Microsoft\.Matrix\(.+?\)/i,
14444             _commasOutsideParenExp = /,(?=[^\)]*(?:\(|$))/gi, //finds any commas that are not within parenthesis
14445             _DEG2RAD = Math.PI / 180,
14446             _RAD2DEG = 180 / Math.PI,
14447             _forcePT = {},
14448             _doc = document,
14449             _tempDiv = _doc.createElement("div"),
14450             _tempImg = _doc.createElement("img"),
14451             _internals = CSSPlugin._internals = {_specialProps:_specialProps}, //provides a hook to a few internal methods that we need to access from inside other plugins
14452             _agent = navigator.userAgent,
14453             _autoRound,
14454             _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).
14455
14456             _isSafari,
14457             _isFirefox, //Firefox has a bug that causes 3D transformed elements to randomly disappear unless a repaint is forced after each update on each element.
14458             _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!)
14459             _ieVers,
14460             _supportsOpacity = (function() { //we set _isSafari, _ieVers, _isFirefox, and _supportsOpacity all in one function here to reduce file size slightly, especially in the minified version.
14461                 var i = _agent.indexOf("Android"),
14462                     d = _doc.createElement("div"), a;
14463
14464                 _isSafari = (_agent.indexOf("Safari") !== -1 && _agent.indexOf("Chrome") === -1 && (i === -1 || Number(_agent.substr(i+8, 1)) > 3));
14465                 _isSafariLT6 = (_isSafari && (Number(_agent.substr(_agent.indexOf("Version/")+8, 1)) < 6));
14466                 _isFirefox = (_agent.indexOf("Firefox") !== -1);
14467
14468                 if ((/MSIE ([0-9]{1,}[\.0-9]{0,})/).exec(_agent)) {
14469                     _ieVers = parseFloat( RegExp.$1 );
14470                 }
14471
14472                 d.innerHTML = "<a title='' style='top:1px;opacity:.55;'>a</a>";
14473                 a = d.getElementsByTagName("a")[0];
14474                 return a ? /^0.55/.test(a.style.opacity) : false;
14475             }()),
14476             _getIEOpacity = function(v) {
14477                 return (_opacityExp.test( ((typeof(v) === "string") ? v : (v.currentStyle ? v.currentStyle.filter : v.style.filter) || "") ) ? ( parseFloat( RegExp.$1 ) / 100 ) : 1);
14478             },
14479             _log = function(s) {//for logging messages, but in a way that won't throw errors in old versions of IE.
14480                 if (window.console) {
14481                     //console.log(s);
14482                 }
14483             },
14484             _prefixCSS = "", //the non-camelCase vendor prefix like "-o-", "-moz-", "-ms-", or "-webkit-"
14485             _prefix = "", //camelCase vendor prefix like "O", "ms", "Webkit", or "Moz".
14486
14487             // @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)
14488             _checkPropPrefix = function(p, e) {
14489                 e = e || _tempDiv;
14490                 var s = e.style,
14491                     a, i;
14492                 if (s[p] !== undefined) {
14493                     return p;
14494                 }
14495                 p = p.charAt(0).toUpperCase() + p.substr(1);
14496                 a = ["O","Moz","ms","Ms","Webkit"];
14497                 i = 5;
14498                 while (--i > -1 && s[a[i]+p] === undefined) { }
14499                 if (i >= 0) {
14500                     _prefix = (i === 3) ? "ms" : a[i];
14501                     _prefixCSS = "-" + _prefix.toLowerCase() + "-";
14502                     return _prefix + p;
14503                 }
14504                 return null;
14505             },
14506
14507             _getComputedStyle = _doc.defaultView ? _doc.defaultView.getComputedStyle : function() {},
14508
14509             /**
14510              * @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:
14511              * var currentLeft = CSSPlugin.getStyle( document.getElementById("myElement"), "left");
14512              *
14513              * @param {!Object} t Target element whose style property you want to query
14514              * @param {!string} p Property name (like "left" or "top" or "marginTop", etc.)
14515              * @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.
14516              * @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.
14517              * @param {string=} dflt Default value that should be returned in the place of null, "none", "auto" or "auto auto".
14518              * @return {?string} The current property value
14519              */
14520             _getStyle = CSSPlugin.getStyle = function(t, p, cs, calc, dflt) {
14521                 var rv;
14522                 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.
14523                     return _getIEOpacity(t);
14524                 }
14525                 if (!calc && t.style[p]) {
14526                     rv = t.style[p];
14527                 } else if ((cs = cs || _getComputedStyle(t))) {
14528                     rv = cs[p] || cs.getPropertyValue(p) || cs.getPropertyValue(p.replace(_capsExp, "-$1").toLowerCase());
14529                 } else if (t.currentStyle) {
14530                     rv = t.currentStyle[p];
14531                 }
14532                 return (dflt != null && (!rv || rv === "none" || rv === "auto" || rv === "auto auto")) ? dflt : rv;
14533             },
14534
14535             /**
14536              * @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.
14537              * @param {!Object} t Target element
14538              * @param {!string} p Property name (like "left", "top", "marginLeft", etc.)
14539              * @param {!number} v Value
14540              * @param {string=} sfx Suffix (like "px" or "%" or "em")
14541              * @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.
14542              * @return {number} value in pixels
14543              */
14544             _convertToPixels = _internals.convertToPixels = function(t, p, v, sfx, recurse) {
14545                 if (sfx === "px" || !sfx) { return v; }
14546                 if (sfx === "auto" || !v) { return 0; }
14547                 var horiz = _horizExp.test(p),
14548                     node = t,
14549                     style = _tempDiv.style,
14550                     neg = (v < 0),
14551                     pix, cache, time;
14552                 if (neg) {
14553                     v = -v;
14554                 }
14555                 if (sfx === "%" && p.indexOf("border") !== -1) {
14556                     pix = (v / 100) * (horiz ? t.clientWidth : t.clientHeight);
14557                 } else {
14558                     style.cssText = "border:0 solid red;position:" + _getStyle(t, "position") + ";line-height:0;";
14559                     if (sfx === "%" || !node.appendChild) {
14560                         node = t.parentNode || _doc.body;
14561                         cache = node._gsCache;
14562                         time = TweenLite.ticker.frame;
14563                         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)
14564                             return cache.width * v / 100;
14565                         }
14566                         style[(horiz ? "width" : "height")] = v + sfx;
14567                     } else {
14568                         style[(horiz ? "borderLeftWidth" : "borderTopWidth")] = v + sfx;
14569                     }
14570                     node.appendChild(_tempDiv);
14571                     pix = parseFloat(_tempDiv[(horiz ? "offsetWidth" : "offsetHeight")]);
14572                     node.removeChild(_tempDiv);
14573                     if (horiz && sfx === "%" && CSSPlugin.cacheWidths !== false) {
14574                         cache = node._gsCache = node._gsCache || {};
14575                         cache.time = time;
14576                         cache.width = pix / v * 100;
14577                     }
14578                     if (pix === 0 && !recurse) {
14579                         pix = _convertToPixels(t, p, v, sfx, true);
14580                     }
14581                 }
14582                 return neg ? -pix : pix;
14583             },
14584             _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
14585                 if (_getStyle(t, "position", cs) !== "absolute") { return 0; }
14586                 var dim = ((p === "left") ? "Left" : "Top"),
14587                     v = _getStyle(t, "margin" + dim, cs);
14588                 return t["offset" + dim] - (_convertToPixels(t, p, parseFloat(v), v.replace(_suffixExp, "")) || 0);
14589             },
14590
14591             // @private returns at object containing ALL of the style properties in camelCase and their associated values.
14592             _getAllStyles = function(t, cs) {
14593                 var s = {},
14594                     i, tr;
14595                 if ((cs = cs || _getComputedStyle(t, null))) {
14596                     if ((i = cs.length)) {
14597                         while (--i > -1) {
14598                             s[cs[i].replace(_camelExp, _camelFunc)] = cs.getPropertyValue(cs[i]);
14599                         }
14600                     } else { //Opera behaves differently - cs.length is always 0, so we must do a for...in loop.
14601                         for (i in cs) {
14602                             s[i] = cs[i];
14603                         }
14604                     }
14605                 } else if ((cs = t.currentStyle || t.style)) {
14606                     for (i in cs) {
14607                         if (typeof(i) === "string" && s[i] === undefined) {
14608                             s[i.replace(_camelExp, _camelFunc)] = cs[i];
14609                         }
14610                     }
14611                 }
14612                 if (!_supportsOpacity) {
14613                     s.opacity = _getIEOpacity(t);
14614                 }
14615                 tr = _getTransform(t, cs, false);
14616                 s.rotation = tr.rotation;
14617                 s.skewX = tr.skewX;
14618                 s.scaleX = tr.scaleX;
14619                 s.scaleY = tr.scaleY;
14620                 s.x = tr.x;
14621                 s.y = tr.y;
14622                 if (_supports3D) {
14623                     s.z = tr.z;
14624                     s.rotationX = tr.rotationX;
14625                     s.rotationY = tr.rotationY;
14626                     s.scaleZ = tr.scaleZ;
14627                 }
14628                 if (s.filters) {
14629                     delete s.filters;
14630                 }
14631                 return s;
14632             },
14633
14634             // @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.
14635             _cssDif = function(t, s1, s2, vars, forceLookup) {
14636                 var difs = {},
14637                     style = t.style,
14638                     val, p, mpt;
14639                 for (p in s2) {
14640                     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") {
14641                         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.
14642                         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.
14643                             mpt = new MiniPropTween(style, p, style[p], mpt);
14644                         }
14645                     }
14646                 }
14647                 if (vars) {
14648                     for (p in vars) { //copy properties (except className)
14649                         if (p !== "className") {
14650                             difs[p] = vars[p];
14651                         }
14652                     }
14653                 }
14654                 return {difs:difs, firstMPT:mpt};
14655             },
14656             _dimensions = {width:["Left","Right"], height:["Top","Bottom"]},
14657             _margins = ["marginLeft","marginRight","marginTop","marginBottom"],
14658
14659             /**
14660              * @private Gets the width or height of an element
14661              * @param {!Object} t Target element
14662              * @param {!string} p Property name ("width" or "height")
14663              * @param {Object=} cs Computed style object (if one exists). Just a speed optimization.
14664              * @return {number} Dimension (in pixels)
14665              */
14666             _getDimension = function(t, p, cs) {
14667                 var v = parseFloat((p === "width") ? t.offsetWidth : t.offsetHeight),
14668                     a = _dimensions[p],
14669                     i = a.length;
14670                 cs = cs || _getComputedStyle(t, null);
14671                 while (--i > -1) {
14672                     v -= parseFloat( _getStyle(t, "padding" + a[i], cs, true) ) || 0;
14673                     v -= parseFloat( _getStyle(t, "border" + a[i] + "Width", cs, true) ) || 0;
14674                 }
14675                 return v;
14676             },
14677
14678             // @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)
14679             _parsePosition = function(v, recObj) {
14680                 if (v == null || v === "" || v === "auto" || v === "auto auto") { //note: Firefox uses "auto auto" as default whereas Chrome uses "auto".
14681                     v = "0 0";
14682                 }
14683                 var a = v.split(" "),
14684                     x = (v.indexOf("left") !== -1) ? "0%" : (v.indexOf("right") !== -1) ? "100%" : a[0],
14685                     y = (v.indexOf("top") !== -1) ? "0%" : (v.indexOf("bottom") !== -1) ? "100%" : a[1];
14686                 if (y == null) {
14687                     y = "0";
14688                 } else if (y === "center") {
14689                     y = "50%";
14690                 }
14691                 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.
14692                     x = "50%";
14693                 }
14694                 if (recObj) {
14695                     recObj.oxp = (x.indexOf("%") !== -1);
14696                     recObj.oyp = (y.indexOf("%") !== -1);
14697                     recObj.oxr = (x.charAt(1) === "=");
14698                     recObj.oyr = (y.charAt(1) === "=");
14699                     recObj.ox = parseFloat(x.replace(_NaNExp, ""));
14700                     recObj.oy = parseFloat(y.replace(_NaNExp, ""));
14701                 }
14702                 return x + " " + y + ((a.length > 2) ? " " + a[2] : "");
14703             },
14704
14705             /**
14706              * @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!)
14707              * @param {(number|string)} e End value which is typically a string, but could be a number
14708              * @param {(number|string)} b Beginning value which is typically a string but could be a number
14709              * @return {number} Amount of change between the beginning and ending values (relative values that have a "+=" or "-=" are recognized)
14710              */
14711             _parseChange = function(e, b) {
14712                 return (typeof(e) === "string" && e.charAt(1) === "=") ? parseInt(e.charAt(0) + "1", 10) * parseFloat(e.substr(2)) : parseFloat(e) - parseFloat(b);
14713             },
14714
14715             /**
14716              * @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.
14717              * @param {Object} v Value to be parsed
14718              * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter)
14719              * @return {number} Parsed value
14720              */
14721             _parseVal = function(v, d) {
14722                 return (v == null) ? d : (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) + d : parseFloat(v);
14723             },
14724
14725             /**
14726              * @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.
14727              * @param {Object} v Value to be parsed
14728              * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter)
14729              * @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"
14730              * @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.
14731              * @return {number} parsed angle in radians
14732              */
14733             _parseAngle = function(v, d, p, directionalEnd) {
14734                 var min = 0.000001,
14735                     cap, split, dif, result;
14736                 if (v == null) {
14737                     result = d;
14738                 } else if (typeof(v) === "number") {
14739                     result = v;
14740                 } else {
14741                     cap = 360;
14742                     split = v.split("_");
14743                     dif = Number(split[0].replace(_NaNExp, "")) * ((v.indexOf("rad") === -1) ? 1 : _RAD2DEG) - ((v.charAt(1) === "=") ? 0 : d);
14744                     if (split.length) {
14745                         if (directionalEnd) {
14746                             directionalEnd[p] = d + dif;
14747                         }
14748                         if (v.indexOf("short") !== -1) {
14749                             dif = dif % cap;
14750                             if (dif !== dif % (cap / 2)) {
14751                                 dif = (dif < 0) ? dif + cap : dif - cap;
14752                             }
14753                         }
14754                         if (v.indexOf("_cw") !== -1 && dif < 0) {
14755                             dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
14756                         } else if (v.indexOf("ccw") !== -1 && dif > 0) {
14757                             dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
14758                         }
14759                     }
14760                     result = d + dif;
14761                 }
14762                 if (result < min && result > -min) {
14763                     result = 0;
14764                 }
14765                 return result;
14766             },
14767
14768             _colorLookup = {aqua:[0,255,255],
14769                 lime:[0,255,0],
14770                 silver:[192,192,192],
14771                 black:[0,0,0],
14772                 maroon:[128,0,0],
14773                 teal:[0,128,128],
14774                 blue:[0,0,255],
14775                 navy:[0,0,128],
14776                 white:[255,255,255],
14777                 fuchsia:[255,0,255],
14778                 olive:[128,128,0],
14779                 yellow:[255,255,0],
14780                 orange:[255,165,0],
14781                 gray:[128,128,128],
14782                 purple:[128,0,128],
14783                 green:[0,128,0],
14784                 red:[255,0,0],
14785                 pink:[255,192,203],
14786                 cyan:[0,255,255],
14787                 transparent:[255,255,255,0]},
14788
14789             _hue = function(h, m1, m2) {
14790                 h = (h < 0) ? h + 1 : (h > 1) ? h - 1 : h;
14791                 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;
14792             },
14793
14794             /**
14795              * @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)
14796              * @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.
14797              * @return {Array.<number>} An array containing red, green, and blue (and optionally alpha) in that order.
14798              */
14799             _parseColor = function(v) {
14800                 var c1, c2, c3, h, s, l;
14801                 if (!v || v === "") {
14802                     return _colorLookup.black;
14803                 }
14804                 if (typeof(v) === "number") {
14805                     return [v >> 16, (v >> 8) & 255, v & 255];
14806                 }
14807                 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.
14808                     v = v.substr(0, v.length - 1);
14809                 }
14810                 if (_colorLookup[v]) {
14811                     return _colorLookup[v];
14812                 }
14813                 if (v.charAt(0) === "#") {
14814                     if (v.length === 4) { //for shorthand like #9F0
14815                         c1 = v.charAt(1),
14816                         c2 = v.charAt(2),
14817                         c3 = v.charAt(3);
14818                         v = "#" + c1 + c1 + c2 + c2 + c3 + c3;
14819                     }
14820                     v = parseInt(v.substr(1), 16);
14821                     return [v >> 16, (v >> 8) & 255, v & 255];
14822                 }
14823                 if (v.substr(0, 3) === "hsl") {
14824                     v = v.match(_numExp);
14825                     h = (Number(v[0]) % 360) / 360;
14826                     s = Number(v[1]) / 100;
14827                     l = Number(v[2]) / 100;
14828                     c2 = (l <= 0.5) ? l * (s + 1) : l + s - l * s;
14829                     c1 = l * 2 - c2;
14830                     if (v.length > 3) {
14831                         v[3] = Number(v[3]);
14832                     }
14833                     v[0] = _hue(h + 1 / 3, c1, c2);
14834                     v[1] = _hue(h, c1, c2);
14835                     v[2] = _hue(h - 1 / 3, c1, c2);
14836                     return v;
14837                 }
14838                 v = v.match(_numExp) || _colorLookup.transparent;
14839                 v[0] = Number(v[0]);
14840                 v[1] = Number(v[1]);
14841                 v[2] = Number(v[2]);
14842                 if (v.length > 3) {
14843                     v[3] = Number(v[3]);
14844                 }
14845                 return v;
14846             },
14847             _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.
14848
14849         for (p in _colorLookup) {
14850             _colorExp += "|" + p + "\\b";
14851         }
14852         _colorExp = new RegExp(_colorExp+")", "gi");
14853
14854         /**
14855          * @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.
14856          * @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.
14857          * @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.
14858          * @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.
14859          * @return {Function} formatter function
14860          */
14861         var _getFormatter = function(dflt, clr, collapsible, multi) {
14862                 if (dflt == null) {
14863                     return function(v) {return v;};
14864                 }
14865                 var dColor = clr ? (dflt.match(_colorExp) || [""])[0] : "",
14866                     dVals = dflt.split(dColor).join("").match(_valuesExp) || [],
14867                     pfx = dflt.substr(0, dflt.indexOf(dVals[0])),
14868                     sfx = (dflt.charAt(dflt.length - 1) === ")") ? ")" : "",
14869                     delim = (dflt.indexOf(" ") !== -1) ? " " : ",",
14870                     numVals = dVals.length,
14871                     dSfx = (numVals > 0) ? dVals[0].replace(_numExp, "") : "",
14872                     formatter;
14873                 if (!numVals) {
14874                     return function(v) {return v;};
14875                 }
14876                 if (clr) {
14877                     formatter = function(v) {
14878                         var color, vals, i, a;
14879                         if (typeof(v) === "number") {
14880                             v += dSfx;
14881                         } else if (multi && _commasOutsideParenExp.test(v)) {
14882                             a = v.replace(_commasOutsideParenExp, "|").split("|");
14883                             for (i = 0; i < a.length; i++) {
14884                                 a[i] = formatter(a[i]);
14885                             }
14886                             return a.join(",");
14887                         }
14888                         color = (v.match(_colorExp) || [dColor])[0];
14889                         vals = v.split(color).join("").match(_valuesExp) || [];
14890                         i = vals.length;
14891                         if (numVals > i--) {
14892                             while (++i < numVals) {
14893                                 vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];
14894                             }
14895                         }
14896                         return pfx + vals.join(delim) + delim + color + sfx + (v.indexOf("inset") !== -1 ? " inset" : "");
14897                     };
14898                     return formatter;
14899
14900                 }
14901                 formatter = function(v) {
14902                     var vals, a, i;
14903                     if (typeof(v) === "number") {
14904                         v += dSfx;
14905                     } else if (multi && _commasOutsideParenExp.test(v)) {
14906                         a = v.replace(_commasOutsideParenExp, "|").split("|");
14907                         for (i = 0; i < a.length; i++) {
14908                             a[i] = formatter(a[i]);
14909                         }
14910                         return a.join(",");
14911                     }
14912                     vals = v.match(_valuesExp) || [];
14913                     i = vals.length;
14914                     if (numVals > i--) {
14915                         while (++i < numVals) {
14916                             vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];
14917                         }
14918                     }
14919                     return pfx + vals.join(delim) + sfx;
14920                 };
14921                 return formatter;
14922             },
14923
14924             /**
14925              * @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.
14926              * @param {!string} props a comma-delimited list of property names in order from top to left, like "marginTop,marginRight,marginBottom,marginLeft"
14927              * @return {Function} a formatter function
14928              */
14929             _getEdgeParser = function(props) {
14930                 props = props.split(",");
14931                 return function(t, e, p, cssp, pt, plugin, vars) {
14932                     var a = (e + "").split(" "),
14933                         i;
14934                     vars = {};
14935                     for (i = 0; i < 4; i++) {
14936                         vars[props[i]] = a[i] = a[i] || a[(((i - 1) / 2) >> 0)];
14937                     }
14938                     return cssp.parse(t, vars, pt, plugin);
14939                 };
14940             },
14941
14942             // @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.
14943             _setPluginRatio = _internals._setPluginRatio = function(v) {
14944                 this.plugin.setRatio(v);
14945                 var d = this.data,
14946                     proxy = d.proxy,
14947                     mpt = d.firstMPT,
14948                     min = 0.000001,
14949                     val, pt, i, str;
14950                 while (mpt) {
14951                     val = proxy[mpt.v];
14952                     if (mpt.r) {
14953                         val = Math.round(val);
14954                     } else if (val < min && val > -min) {
14955                         val = 0;
14956                     }
14957                     mpt.t[mpt.p] = val;
14958                     mpt = mpt._next;
14959                 }
14960                 if (d.autoRotate) {
14961                     d.autoRotate.rotation = proxy.rotation;
14962                 }
14963                 //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.
14964                 if (v === 1) {
14965                     mpt = d.firstMPT;
14966                     while (mpt) {
14967                         pt = mpt.t;
14968                         if (!pt.type) {
14969                             pt.e = pt.s + pt.xs0;
14970                         } else if (pt.type === 1) {
14971                             str = pt.xs0 + pt.s + pt.xs1;
14972                             for (i = 1; i < pt.l; i++) {
14973                                 str += pt["xn"+i] + pt["xs"+(i+1)];
14974                             }
14975                             pt.e = str;
14976                         }
14977                         mpt = mpt._next;
14978                     }
14979                 }
14980             },
14981
14982             /**
14983              * @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.
14984              * @param {!Object} t target object whose property we're tweening (often a CSSPropTween)
14985              * @param {!string} p property name
14986              * @param {(number|string|object)} v value
14987              * @param {MiniPropTween=} next next MiniPropTween in the linked list
14988              * @param {boolean=} r if true, the tweened value should be rounded to the nearest integer
14989              */
14990             MiniPropTween = function(t, p, v, next, r) {
14991                 this.t = t;
14992                 this.p = p;
14993                 this.v = v;
14994                 this.r = r;
14995                 if (next) {
14996                     next._prev = this;
14997                     this._next = next;
14998                 }
14999             },
15000
15001             /**
15002              * @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.
15003              * This method returns an object that has the following properties:
15004              *  - 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
15005              *  - 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
15006              *  - firstMPT: the first MiniPropTween in the linked list
15007              *  - 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.
15008              * @param {!Object} t target object to be tweened
15009              * @param {!(Object|string)} vars the object containing the information about the tweening values (typically the end/destination values) that should be parsed
15010              * @param {!CSSPlugin} cssp The CSSPlugin instance
15011              * @param {CSSPropTween=} pt the next CSSPropTween in the linked list
15012              * @param {TweenPlugin=} plugin the external TweenPlugin instance that will be handling tweening the numeric values
15013              * @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.
15014              * @return An object containing the following properties: proxy, end, firstMPT, and pt (see above for descriptions)
15015              */
15016             _parseToProxy = _internals._parseToProxy = function(t, vars, cssp, pt, plugin, shallow) {
15017                 var bpt = pt,
15018                     start = {},
15019                     end = {},
15020                     transform = cssp._transform,
15021                     oldForce = _forcePT,
15022                     i, p, xp, mpt, firstPT;
15023                 cssp._transform = null;
15024                 _forcePT = vars;
15025                 pt = firstPT = cssp.parse(t, vars, pt, plugin);
15026                 _forcePT = oldForce;
15027                 //break off from the linked list so the new ones are isolated.
15028                 if (shallow) {
15029                     cssp._transform = transform;
15030                     if (bpt) {
15031                         bpt._prev = null;
15032                         if (bpt._prev) {
15033                             bpt._prev._next = null;
15034                         }
15035                     }
15036                 }
15037                 while (pt && pt !== bpt) {
15038                     if (pt.type <= 1) {
15039                         p = pt.p;
15040                         end[p] = pt.s + pt.c;
15041                         start[p] = pt.s;
15042                         if (!shallow) {
15043                             mpt = new MiniPropTween(pt, "s", p, mpt, pt.r);
15044                             pt.c = 0;
15045                         }
15046                         if (pt.type === 1) {
15047                             i = pt.l;
15048                             while (--i > 0) {
15049                                 xp = "xn" + i;
15050                                 p = pt.p + "_" + xp;
15051                                 end[p] = pt.data[xp];
15052                                 start[p] = pt[xp];
15053                                 if (!shallow) {
15054                                     mpt = new MiniPropTween(pt, xp, p, mpt, pt.rxp[xp]);
15055                                 }
15056                             }
15057                         }
15058                     }
15059                     pt = pt._next;
15060                 }
15061                 return {proxy:start, end:end, firstMPT:mpt, pt:firstPT};
15062             },
15063
15064
15065
15066             /**
15067              * @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.
15068              * CSSPropTweens have the following optional properties as well (not defined through the constructor):
15069              *  - 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.
15070              *  - 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)
15071              *  - 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.
15072              *  - 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.
15073              *  - 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.
15074              * @param {!Object} t Target object whose property will be tweened. Often a DOM element, but not always. It could be anything.
15075              * @param {string} p Property to tween (name). For example, to tween element.width, p would be "width".
15076              * @param {number} s Starting numeric value
15077              * @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.
15078              * @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.
15079              * @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.
15080              * @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"
15081              * @param {boolean=} r If true, the value(s) should be rounded
15082              * @param {number=} pr Priority in the linked list order. Higher priority CSSPropTweens will be updated before lower priority ones. The default priority is 0.
15083              * @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.
15084              * @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.
15085              */
15086             CSSPropTween = _internals.CSSPropTween = function(t, p, s, c, next, type, n, r, pr, b, e) {
15087                 this.t = t; //target
15088                 this.p = p; //property
15089                 this.s = s; //starting value
15090                 this.c = c; //change value
15091                 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)
15092                 if (!(t instanceof CSSPropTween)) {
15093                     _overwriteProps.push(this.n);
15094                 }
15095                 this.r = r; //round (boolean)
15096                 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
15097                 if (pr) {
15098                     this.pr = pr;
15099                     _hasPriority = true;
15100                 }
15101                 this.b = (b === undefined) ? s : b;
15102                 this.e = (e === undefined) ? s + c : e;
15103                 if (next) {
15104                     this._next = next;
15105                     next._prev = this;
15106                 }
15107             },
15108
15109             /**
15110              * 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:
15111              * 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);
15112              * 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().
15113              * 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.
15114              *
15115              * @param {!Object} t Target whose property will be tweened
15116              * @param {!string} p Property that will be tweened (its name, like "left" or "backgroundColor" or "boxShadow")
15117              * @param {string} b Beginning value
15118              * @param {string} e Ending value
15119              * @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)
15120              * @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
15121              * @param {?CSSPropTween} pt CSSPropTween instance that is the current head of the linked list (we'll prepend to this).
15122              * @param {number=} pr Priority in the linked list order. Higher priority properties will be updated before lower priority ones. The default priority is 0.
15123              * @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}
15124              * @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.
15125              * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parseComplex() call.
15126              */
15127             _parseComplex = CSSPlugin.parseComplex = function(t, p, b, e, clrs, dflt, pt, pr, plugin, setRatio) {
15128                 //DEBUG: _log("parseComplex: "+p+", b: "+b+", e: "+e);
15129                 b = b || dflt || "";
15130                 pt = new CSSPropTween(t, p, 0, 0, pt, (setRatio ? 2 : 1), null, false, pr, b, e);
15131                 e += ""; //ensures it's a string
15132                 var ba = b.split(", ").join(",").split(" "), //beginning array
15133                     ea = e.split(", ").join(",").split(" "), //ending array
15134                     l = ba.length,
15135                     autoRound = (_autoRound !== false),
15136                     i, xi, ni, bv, ev, bnums, enums, bn, rgba, temp, cv, str;
15137                 if (e.indexOf(",") !== -1 || b.indexOf(",") !== -1) {
15138                     ba = ba.join(" ").replace(_commasOutsideParenExp, ", ").split(" ");
15139                     ea = ea.join(" ").replace(_commasOutsideParenExp, ", ").split(" ");
15140                     l = ba.length;
15141                 }
15142                 if (l !== ea.length) {
15143                     //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")");
15144                     ba = (dflt || "").split(" ");
15145                     l = ba.length;
15146                 }
15147                 pt.plugin = plugin;
15148                 pt.setRatio = setRatio;
15149                 for (i = 0; i < l; i++) {
15150                     bv = ba[i];
15151                     ev = ea[i];
15152                     bn = parseFloat(bv);
15153
15154                     //if the value begins with a number (most common). It's fine if it has a suffix like px
15155                     if (bn || bn === 0) {
15156                         pt.appendXtra("", bn, _parseChange(ev, bn), ev.replace(_relNumExp, ""), (autoRound && ev.indexOf("px") !== -1), true);
15157
15158                     //if the value is a color
15159                     } else if (clrs && (bv.charAt(0) === "#" || _colorLookup[bv] || _rgbhslExp.test(bv))) {
15160                         str = ev.charAt(ev.length - 1) === "," ? ")," : ")"; //if there's a comma at the end, retain it.
15161                         bv = _parseColor(bv);
15162                         ev = _parseColor(ev);
15163                         rgba = (bv.length + ev.length > 6);
15164                         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
15165                             pt["xs" + pt.l] += pt.l ? " transparent" : "transparent";
15166                             pt.e = pt.e.split(ea[i]).join("transparent");
15167                         } else {
15168                             if (!_supportsOpacity) { //old versions of IE don't support rgba().
15169                                 rgba = false;
15170                             }
15171                             pt.appendXtra((rgba ? "rgba(" : "rgb("), bv[0], ev[0] - bv[0], ",", true, true)
15172                                 .appendXtra("", bv[1], ev[1] - bv[1], ",", true)
15173                                 .appendXtra("", bv[2], ev[2] - bv[2], (rgba ? "," : str), true);
15174                             if (rgba) {
15175                                 bv = (bv.length < 4) ? 1 : bv[3];
15176                                 pt.appendXtra("", bv, ((ev.length < 4) ? 1 : ev[3]) - bv, str, false);
15177                             }
15178                         }
15179
15180                     } else {
15181                         bnums = bv.match(_numExp); //gets each group of numbers in the beginning value string and drops them into an array
15182
15183                         //if no number is found, treat it as a non-tweening value and just append the string to the current xs.
15184                         if (!bnums) {
15185                             pt["xs" + pt.l] += pt.l ? " " + bv : bv;
15186
15187                         //loop through all the numbers that are found and construct the extra values on the pt.
15188                         } else {
15189                             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
15190                             if (!enums || enums.length !== bnums.length) {
15191                                 //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")");
15192                                 return pt;
15193                             }
15194                             ni = 0;
15195                             for (xi = 0; xi < bnums.length; xi++) {
15196                                 cv = bnums[xi];
15197                                 temp = bv.indexOf(cv, ni);
15198                                 pt.appendXtra(bv.substr(ni, temp - ni), Number(cv), _parseChange(enums[xi], cv), "", (autoRound && bv.substr(temp + cv.length, 2) === "px"), (xi === 0));
15199                                 ni = temp + cv.length;
15200                             }
15201                             pt["xs" + pt.l] += bv.substr(ni);
15202                         }
15203                     }
15204                 }
15205                 //if there are relative values ("+=" or "-=" prefix), we need to adjust the ending value to eliminate the prefixes and combine the values properly.
15206                 if (e.indexOf("=") !== -1) if (pt.data) {
15207                     str = pt.xs0 + pt.data.s;
15208                     for (i = 1; i < pt.l; i++) {
15209                         str += pt["xs" + i] + pt.data["xn" + i];
15210                     }
15211                     pt.e = str + pt["xs" + i];
15212                 }
15213                 if (!pt.l) {
15214                     pt.type = -1;
15215                     pt.xs0 = pt.e;
15216                 }
15217                 return pt.xfirst || pt;
15218             },
15219             i = 9;
15220
15221
15222         p = CSSPropTween.prototype;
15223         p.l = p.pr = 0; //length (number of extra properties like xn1, xn2, xn3, etc.
15224         while (--i > 0) {
15225             p["xn" + i] = 0;
15226             p["xs" + i] = "";
15227         }
15228         p.xs0 = "";
15229         p._next = p._prev = p.xfirst = p.data = p.plugin = p.setRatio = p.rxp = null;
15230
15231
15232         /**
15233          * 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:
15234          * xs0:"rect(", s:10, xs1:"px, ", xn1:5, xs2:"px, ", xn2:0, xs3:"px, ", xn3:20, xn4:"px)"
15235          * And they'd all get joined together when the CSSPlugin renders (in the setRatio() method).
15236          * @param {string=} pfx Prefix (if any)
15237          * @param {!number} s Starting value
15238          * @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.
15239          * @param {string=} sfx Suffix (if any)
15240          * @param {boolean=} r Round (if true).
15241          * @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.
15242          * @return {CSSPropTween} returns itself so that multiple methods can be chained together.
15243          */
15244         p.appendXtra = function(pfx, s, c, sfx, r, pad) {
15245             var pt = this,
15246                 l = pt.l;
15247             pt["xs" + l] += (pad && l) ? " " + pfx : pfx || "";
15248             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!
15249                 pt["xs" + l] += s + (sfx || "");
15250                 return pt;
15251             }
15252             pt.l++;
15253             pt.type = pt.setRatio ? 2 : 1;
15254             pt["xs" + pt.l] = sfx || "";
15255             if (l > 0) {
15256                 pt.data["xn" + l] = s + c;
15257                 pt.rxp["xn" + l] = r; //round extra property (we need to tap into this in the _parseToProxy() method)
15258                 pt["xn" + l] = s;
15259                 if (!pt.plugin) {
15260                     pt.xfirst = new CSSPropTween(pt, "xn" + l, s, c, pt.xfirst || pt, 0, pt.n, r, pt.pr);
15261                     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.
15262                 }
15263                 return pt;
15264             }
15265             pt.data = {s:s + c};
15266             pt.rxp = {};
15267             pt.s = s;
15268             pt.c = c;
15269             pt.r = r;
15270             return pt;
15271         };
15272
15273         /**
15274          * @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.
15275          * @param {!string} p Property name (like "boxShadow" or "throwProps")
15276          * @param {Object=} options An object containing any of the following configuration options:
15277          *                      - defaultValue: the default value
15278          *                      - 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)
15279          *                      - 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.)
15280          *                      - prefix: if true, we'll determine whether or not this property requires a vendor prefix (like Webkit or Moz or ms or O)
15281          *                      - color: set this to true if the value for this SpecialProp may contain color-related values like rgb(), rgba(), etc.
15282          *                      - priority: priority in the linked list order. Higher priority SpecialProps will be updated before lower priority ones. The default priority is 0.
15283          *                      - multi: if true, the formatter should accommodate a comma-delimited list of values, like boxShadow could have multiple boxShadows listed out.
15284          *                      - 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.
15285          *                      - 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).
15286          */
15287         var SpecialProp = function(p, options) {
15288                 options = options || {};
15289                 this.p = options.prefix ? _checkPropPrefix(p) || p : p;
15290                 _specialProps[p] = _specialProps[this.p] = this;
15291                 this.format = options.formatter || _getFormatter(options.defaultValue, options.color, options.collapsible, options.multi);
15292                 if (options.parser) {
15293                     this.parse = options.parser;
15294                 }
15295                 this.clrs = options.color;
15296                 this.multi = options.multi;
15297                 this.keyword = options.keyword;
15298                 this.dflt = options.defaultValue;
15299                 this.pr = options.priority || 0;
15300             },
15301
15302             //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.
15303             _registerComplexSpecialProp = _internals._registerComplexSpecialProp = function(p, options, defaults) {
15304                 if (typeof(options) !== "object") {
15305                     options = {parser:defaults}; //to make backwards compatible with older versions of BezierPlugin and ThrowPropsPlugin
15306                 }
15307                 var a = p.split(","),
15308                     d = options.defaultValue,
15309                     i, temp;
15310                 defaults = defaults || [d];
15311                 for (i = 0; i < a.length; i++) {
15312                     options.prefix = (i === 0 && options.prefix);
15313                     options.defaultValue = defaults[i] || d;
15314                     temp = new SpecialProp(a[i], options);
15315                 }
15316             },
15317
15318             //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.
15319             _registerPluginProp = function(p) {
15320                 if (!_specialProps[p]) {
15321                     var pluginName = p.charAt(0).toUpperCase() + p.substr(1) + "Plugin";
15322                     _registerComplexSpecialProp(p, {parser:function(t, e, p, cssp, pt, plugin, vars) {
15323                         var pluginClass = (window.GreenSockGlobals || window).com.greensock.plugins[pluginName];
15324                         if (!pluginClass) {
15325                             _log("Error: " + pluginName + " js file not loaded.");
15326                             return pt;
15327                         }
15328                         pluginClass._cssRegister();
15329                         return _specialProps[p].parse(t, e, p, cssp, pt, plugin, vars);
15330                     }});
15331                 }
15332             };
15333
15334
15335         p = SpecialProp.prototype;
15336
15337         /**
15338          * 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)
15339          * @param {!Object} t target element
15340          * @param {(string|number|object)} b beginning value
15341          * @param {(string|number|object)} e ending (destination) value
15342          * @param {CSSPropTween=} pt next CSSPropTween in the linked list
15343          * @param {TweenPlugin=} plugin If another plugin will be tweening the complex value, that TweenPlugin instance goes here.
15344          * @param {function=} setRatio If a custom setRatio() method should be used to handle this complex value, that goes here.
15345          * @return {CSSPropTween=} First CSSPropTween in the linked list
15346          */
15347         p.parseComplex = function(t, b, e, pt, plugin, setRatio) {
15348             var kwd = this.keyword,
15349                 i, ba, ea, l, bi, ei;
15350             //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)
15351             if (this.multi) if (_commasOutsideParenExp.test(e) || _commasOutsideParenExp.test(b)) {
15352                 ba = b.replace(_commasOutsideParenExp, "|").split("|");
15353                 ea = e.replace(_commasOutsideParenExp, "|").split("|");
15354             } else if (kwd) {
15355                 ba = [b];
15356                 ea = [e];
15357             }
15358             if (ea) {
15359                 l = (ea.length > ba.length) ? ea.length : ba.length;
15360                 for (i = 0; i < l; i++) {
15361                     b = ba[i] = ba[i] || this.dflt;
15362                     e = ea[i] = ea[i] || this.dflt;
15363                     if (kwd) {
15364                         bi = b.indexOf(kwd);
15365                         ei = e.indexOf(kwd);
15366                         if (bi !== ei) {
15367                             e = (ei === -1) ? ea : ba;
15368                             e[i] += " " + kwd;
15369                         }
15370                     }
15371                 }
15372                 b = ba.join(", ");
15373                 e = ea.join(", ");
15374             }
15375             return _parseComplex(t, this.p, b, e, this.clrs, this.dflt, pt, this.pr, plugin, setRatio);
15376         };
15377
15378         /**
15379          * 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:
15380          * this._firstPT = sp.parse(element, "5px 10px 20px rgb(2550,102,51)", "boxShadow", this);
15381          * 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).
15382          * @param {!Object} t Target object whose property is being tweened
15383          * @param {Object} e End value as provided in the vars object (typically a string, but not always - like a throwProps would be an object).
15384          * @param {!string} p Property name
15385          * @param {!CSSPlugin} cssp The CSSPlugin instance that should be associated with this tween.
15386          * @param {?CSSPropTween} pt The CSSPropTween that is the current head of the linked list (we'll prepend to it)
15387          * @param {TweenPlugin=} plugin If a plugin will be used to tween the parsed value, this is the plugin instance.
15388          * @param {Object=} vars Original vars object that contains the data for parsing.
15389          * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parse() call.
15390          */
15391         p.parse = function(t, e, p, cssp, pt, plugin, vars) {
15392             return this.parseComplex(t.style, this.format(_getStyle(t, this.p, _cs, false, this.dflt)), this.format(e), pt, plugin);
15393         };
15394
15395         /**
15396          * 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:
15397          *  1) Target object whose property should be tweened (typically a DOM element)
15398          *  2) The end/destination value (could be a string, number, object, or whatever you want)
15399          *  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)
15400          *
15401          * 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:
15402          *
15403          * CSSPlugin.registerSpecialProp("myCustomProp", function(target, value, tween) {
15404          *      var start = target.style.width;
15405          *      return function(ratio) {
15406          *              target.style.width = (start + value * ratio) + "px";
15407          *              console.log("set width to " + target.style.width);
15408          *          }
15409          * }, 0);
15410          *
15411          * Then, when I do this tween, it will trigger my special property:
15412          *
15413          * TweenLite.to(element, 1, {css:{myCustomProp:100}});
15414          *
15415          * In the example, of course, we're just changing the width, but you can do anything you want.
15416          *
15417          * @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}})
15418          * @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.
15419          * @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.
15420          */
15421         CSSPlugin.registerSpecialProp = function(name, onInitTween, priority) {
15422             _registerComplexSpecialProp(name, {parser:function(t, e, p, cssp, pt, plugin, vars) {
15423                 var rv = new CSSPropTween(t, p, 0, 0, pt, 2, p, false, priority);
15424                 rv.plugin = plugin;
15425                 rv.setRatio = onInitTween(t, e, cssp._tween, p);
15426                 return rv;
15427             }, priority:priority});
15428         };
15429
15430
15431
15432
15433
15434
15435
15436
15437         //transform-related methods and properties
15438         var _transformProps = ("scaleX,scaleY,scaleZ,x,y,z,skewX,skewY,rotation,rotationX,rotationY,perspective").split(","),
15439             _transformProp = _checkPropPrefix("transform"), //the Javascript (camelCase) transform property, like msTransform, WebkitTransform, MozTransform, or OTransform.
15440             _transformPropCSS = _prefixCSS + "transform",
15441             _transformOriginProp = _checkPropPrefix("transformOrigin"),
15442             _supports3D = (_checkPropPrefix("perspective") !== null),
15443             Transform = _internals.Transform = function() {
15444                 this.skewY = 0;
15445             },
15446
15447             /**
15448              * 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.
15449              * @param {!Object} t target element
15450              * @param {Object=} cs computed style object (optional)
15451              * @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...}
15452              * @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)
15453              * @return {object} object containing all of the transform properties/values like {x:0, y:0, z:0, scaleX:1...}
15454              */
15455             _getTransform = _internals.getTransform = function(t, cs, rec, parse) {
15456                 if (t._gsTransform && rec && !parse) {
15457                     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.
15458                 }
15459                 var tm = rec ? t._gsTransform || new Transform() : new Transform(),
15460                     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.
15461                     min = 0.00002,
15462                     rnd = 100000,
15463                     minAngle = 179.99,
15464                     minPI = minAngle * _DEG2RAD,
15465                     zOrigin = _supports3D ? parseFloat(_getStyle(t, _transformOriginProp, cs, false, "0 0 0").split(" ")[2]) || tm.zOrigin  || 0 : 0,
15466                     s, m, i, n, dec, scaleX, scaleY, rotation, skewX, difX, difY, difR, difS;
15467                 if (_transformProp) {
15468                     s = _getStyle(t, _transformPropCSS, cs, true);
15469                 } else if (t.currentStyle) {
15470                     //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.
15471                     s = t.currentStyle.filter.match(_ieGetMatrixExp);
15472                     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(",") : "";
15473                 }
15474                 //split the matrix values out into an array (m for matrix)
15475                 m = (s || "").match(/(?:\-|\b)[\d\-\.e]+\b/gi) || [];
15476                 i = m.length;
15477                 while (--i > -1) {
15478                     n = Number(m[i]);
15479                     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).
15480                 }
15481                 if (m.length === 16) {
15482
15483                     //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)
15484                     var a13 = m[8], a23 = m[9], a33 = m[10],
15485                         a14 = m[12], a24 = m[13], a34 = m[14];
15486
15487                     //we manually compensate for non-zero z component of transformOrigin to work around bugs in Safari
15488                     if (tm.zOrigin) {
15489                         a34 = -tm.zOrigin;
15490                         a14 = a13*a34-m[12];
15491                         a24 = a23*a34-m[13];
15492                         a34 = a33*a34+tm.zOrigin-m[14];
15493                     }
15494
15495                     //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.
15496                     if (!rec || parse || tm.rotationX == null) {
15497                         var a11 = m[0], a21 = m[1], a31 = m[2], a41 = m[3],
15498                             a12 = m[4], a22 = m[5], a32 = m[6], a42 = m[7],
15499                             a43 = m[11],
15500                             angle = Math.atan2(a32, a33),
15501                             xFlip = (angle < -minPI || angle > minPI),
15502                             t1, t2, t3, cos, sin, yFlip, zFlip;
15503                         tm.rotationX = angle * _RAD2DEG;
15504                         //rotationX
15505                         if (angle) {
15506                             cos = Math.cos(-angle);
15507                             sin = Math.sin(-angle);
15508                             t1 = a12*cos+a13*sin;
15509                             t2 = a22*cos+a23*sin;
15510                             t3 = a32*cos+a33*sin;
15511                             a13 = a12*-sin+a13*cos;
15512                             a23 = a22*-sin+a23*cos;
15513                             a33 = a32*-sin+a33*cos;
15514                             a43 = a42*-sin+a43*cos;
15515                             a12 = t1;
15516                             a22 = t2;
15517                             a32 = t3;
15518                         }
15519                         //rotationY
15520                         angle = Math.atan2(a13, a11);
15521                         tm.rotationY = angle * _RAD2DEG;
15522                         if (angle) {
15523                             yFlip = (angle < -minPI || angle > minPI);
15524                             cos = Math.cos(-angle);
15525                             sin = Math.sin(-angle);
15526                             t1 = a11*cos-a13*sin;
15527                             t2 = a21*cos-a23*sin;
15528                             t3 = a31*cos-a33*sin;
15529                             a23 = a21*sin+a23*cos;
15530                             a33 = a31*sin+a33*cos;
15531                             a43 = a41*sin+a43*cos;
15532                             a11 = t1;
15533                             a21 = t2;
15534                             a31 = t3;
15535                         }
15536                         //rotationZ
15537                         angle = Math.atan2(a21, a22);
15538                         tm.rotation = angle * _RAD2DEG;
15539                         if (angle) {
15540                             zFlip = (angle < -minPI || angle > minPI);
15541                             cos = Math.cos(-angle);
15542                             sin = Math.sin(-angle);
15543                             a11 = a11*cos+a12*sin;
15544                             t2 = a21*cos+a22*sin;
15545                             a22 = a21*-sin+a22*cos;
15546                             a32 = a31*-sin+a32*cos;
15547                             a21 = t2;
15548                         }
15549
15550                         if (zFlip && xFlip) {
15551                             tm.rotation = tm.rotationX = 0;
15552                         } else if (zFlip && yFlip) {
15553                             tm.rotation = tm.rotationY = 0;
15554                         } else if (yFlip && xFlip) {
15555                             tm.rotationY = tm.rotationX = 0;
15556                         }
15557
15558                         tm.scaleX = ((Math.sqrt(a11 * a11 + a21 * a21) * rnd + 0.5) | 0) / rnd;
15559                         tm.scaleY = ((Math.sqrt(a22 * a22 + a23 * a23) * rnd + 0.5) | 0) / rnd;
15560                         tm.scaleZ = ((Math.sqrt(a32 * a32 + a33 * a33) * rnd + 0.5) | 0) / rnd;
15561                         tm.skewX = 0;
15562                         tm.perspective = a43 ? 1 / ((a43 < 0) ? -a43 : a43) : 0;
15563                         tm.x = a14;
15564                         tm.y = a24;
15565                         tm.z = a34;
15566                     }
15567
15568                 } 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.
15569                     var k = (m.length >= 6),
15570                         a = k ? m[0] : 1,
15571                         b = m[1] || 0,
15572                         c = m[2] || 0,
15573                         d = k ? m[3] : 1;
15574                     tm.x = m[4] || 0;
15575                     tm.y = m[5] || 0;
15576                     scaleX = Math.sqrt(a * a + b * b);
15577                     scaleY = Math.sqrt(d * d + c * c);
15578                     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).
15579                     skewX = (c || d) ? Math.atan2(c, d) * _RAD2DEG + rotation : tm.skewX || 0;
15580                     difX = scaleX - Math.abs(tm.scaleX || 0);
15581                     difY = scaleY - Math.abs(tm.scaleY || 0);
15582                     if (Math.abs(skewX) > 90 && Math.abs(skewX) < 270) {
15583                         if (invX) {
15584                             scaleX *= -1;
15585                             skewX += (rotation <= 0) ? 180 : -180;
15586                             rotation += (rotation <= 0) ? 180 : -180;
15587                         } else {
15588                             scaleY *= -1;
15589                             skewX += (skewX <= 0) ? 180 : -180;
15590                         }
15591                     }
15592                     difR = (rotation - tm.rotation) % 180; //note: matching ranges would be very small (+/-0.0001) or very close to 180.
15593                     difS = (skewX - tm.skewX) % 180;
15594                     //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.
15595                     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)) {
15596                         tm.scaleX = scaleX;
15597                         tm.scaleY = scaleY;
15598                         tm.rotation = rotation;
15599                         tm.skewX = skewX;
15600                     }
15601                     if (_supports3D) {
15602                         tm.rotationX = tm.rotationY = tm.z = 0;
15603                         tm.perspective = parseFloat(CSSPlugin.defaultTransformPerspective) || 0;
15604                         tm.scaleZ = 1;
15605                     }
15606                 }
15607                 tm.zOrigin = zOrigin;
15608
15609                 //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.
15610                 for (i in tm) {
15611                     if (tm[i] < min) if (tm[i] > -min) {
15612                         tm[i] = 0;
15613                     }
15614                 }
15615                 //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);
15616                 if (rec) {
15617                     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)
15618                 }
15619                 return tm;
15620             },
15621
15622             //for setting 2D transforms in IE6, IE7, and IE8 (must use a "filter" to emulate the behavior of modern day browser transforms)
15623             _setIETransformRatio = function(v) {
15624                 var t = this.data, //refers to the element's _gsTransform object
15625                     ang = -t.rotation * _DEG2RAD,
15626                     skew = ang + t.skewX * _DEG2RAD,
15627                     rnd = 100000,
15628                     a = ((Math.cos(ang) * t.scaleX * rnd) | 0) / rnd,
15629                     b = ((Math.sin(ang) * t.scaleX * rnd) | 0) / rnd,
15630                     c = ((Math.sin(skew) * -t.scaleY * rnd) | 0) / rnd,
15631                     d = ((Math.cos(skew) * t.scaleY * rnd) | 0) / rnd,
15632                     style = this.t.style,
15633                     cs = this.t.currentStyle,
15634                     filters, val;
15635                 if (!cs) {
15636                     return;
15637                 }
15638                 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)
15639                 b = -c;
15640                 c = -val;
15641                 filters = cs.filter;
15642                 style.filter = ""; //remove filters so that we can accurately measure offsetWidth/offsetHeight
15643                 var w = this.t.offsetWidth,
15644                     h = this.t.offsetHeight,
15645                     clip = (cs.position !== "absolute"),
15646                     m = "progid:DXImageTransform.Microsoft.Matrix(M11=" + a + ", M12=" + b + ", M21=" + c + ", M22=" + d,
15647                     ox = t.x,
15648                     oy = t.y,
15649                     dx, dy;
15650
15651                 //if transformOrigin is being used, adjust the offset x and y
15652                 if (t.ox != null) {
15653                     dx = ((t.oxp) ? w * t.ox * 0.01 : t.ox) - w / 2;
15654                     dy = ((t.oyp) ? h * t.oy * 0.01 : t.oy) - h / 2;
15655                     ox += dx - (dx * a + dy * b);
15656                     oy += dy - (dx * c + dy * d);
15657                 }
15658
15659                 if (!clip) {
15660                     m += ", sizingMethod='auto expand')";
15661                 } else {
15662                     dx = (w / 2);
15663                     dy = (h / 2);
15664                     //translate to ensure that transformations occur around the correct origin (default is center).
15665                     m += ", Dx=" + (dx - (dx * a + dy * b) + ox) + ", Dy=" + (dy - (dx * c + dy * d) + oy) + ")";
15666                 }
15667                 if (filters.indexOf("DXImageTransform.Microsoft.Matrix(") !== -1) {
15668                     style.filter = filters.replace(_ieSetMatrixExp, m);
15669                 } else {
15670                     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.
15671                 }
15672
15673                 //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.
15674                 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) {
15675                     style.removeAttribute("filter");
15676                 }
15677
15678                 //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).
15679                 if (!clip) {
15680                     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
15681                         marg, prop, dif;
15682                     dx = t.ieOffsetX || 0;
15683                     dy = t.ieOffsetY || 0;
15684                     t.ieOffsetX = Math.round((w - ((a < 0 ? -a : a) * w + (b < 0 ? -b : b) * h)) / 2 + ox);
15685                     t.ieOffsetY = Math.round((h - ((d < 0 ? -d : d) * h + (c < 0 ? -c : c) * w)) / 2 + oy);
15686                     for (i = 0; i < 4; i++) {
15687                         prop = _margins[i];
15688                         marg = cs[prop];
15689                         //we need to get the current margin in case it is being tweened separately (we want to respect that tween's changes)
15690                         val = (marg.indexOf("px") !== -1) ? parseFloat(marg) : _convertToPixels(this.t, prop, parseFloat(marg), marg.replace(_suffixExp, "")) || 0;
15691                         if (val !== t[prop]) {
15692                             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.
15693                         } else {
15694                             dif = (i < 2) ? dx - t.ieOffsetX : dy - t.ieOffsetY;
15695                         }
15696                         style[prop] = (t[prop] = Math.round( val - dif * ((i === 0 || i === 2) ? 1 : mult) )) + "px";
15697                     }
15698                 }
15699             },
15700
15701             _set3DTransformRatio = _internals.set3DTransformRatio = function(v) {
15702                 var t = this.data, //refers to the element's _gsTransform object
15703                     style = this.t.style,
15704                     angle = t.rotation * _DEG2RAD,
15705                     sx = t.scaleX,
15706                     sy = t.scaleY,
15707                     sz = t.scaleZ,
15708                     perspective = t.perspective,
15709                     a11, a12, a13, a14, a21, a22, a23, a24, a31, a32, a33, a34, a41, a42, a43,
15710                     zOrigin, rnd, cos, sin, t1, t2, t3, t4;
15711                 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
15712                     _set2DTransformRatio.call(this, v);
15713                     return;
15714                 }
15715                 if (_isFirefox) {
15716                     var n = 0.0001;
15717                     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.
15718                         sx = sz = 0.00002;
15719                     }
15720                     if (sy < n && sy > -n) {
15721                         sy = sz = 0.00002;
15722                     }
15723                     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).
15724                         perspective = 0;
15725                     }
15726                 }
15727                 if (angle || t.skewX) {
15728                     cos = Math.cos(angle);
15729                     sin = Math.sin(angle);
15730                     a11 = cos;
15731                     a21 = sin;
15732                     if (t.skewX) {
15733                         angle -= t.skewX * _DEG2RAD;
15734                         cos = Math.cos(angle);
15735                         sin = Math.sin(angle);
15736                         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
15737                             t1 = Math.tan(t.skewX * _DEG2RAD);
15738                             t1 = Math.sqrt(1 + t1 * t1);
15739                             cos *= t1;
15740                             sin *= t1;
15741                         }
15742                     }
15743                     a12 = -sin;
15744                     a22 = cos;
15745
15746                 } else if (!t.rotationY && !t.rotationX && sz === 1 && !perspective) { //if we're only translating and/or 2D scaling, this is faster...
15747                     style[_transformProp] = "translate3d(" + t.x + "px," + t.y + "px," + t.z +"px)" + ((sx !== 1 || sy !== 1) ? " scale(" + sx + "," + sy + ")" : "");
15748                     return;
15749                 } else {
15750                     a11 = a22 = 1;
15751                     a12 = a21 = 0;
15752                 }
15753                 a33 = 1;
15754                 a13 = a14 = a23 = a24 = a31 = a32 = a34 = a41 = a42 = 0;
15755                 a43 = (perspective) ? -1 / perspective : 0;
15756                 zOrigin = t.zOrigin;
15757                 rnd = 100000;
15758                 angle = t.rotationY * _DEG2RAD;
15759                 if (angle) {
15760                     cos = Math.cos(angle);
15761                     sin = Math.sin(angle);
15762                     a31 = a33*-sin;
15763                     a41 = a43*-sin;
15764                     a13 = a11*sin;
15765                     a23 = a21*sin;
15766                     a33 *= cos;
15767                     a43 *= cos;
15768                     a11 *= cos;
15769                     a21 *= cos;
15770                 }
15771                 angle = t.rotationX * _DEG2RAD;
15772                 if (angle) {
15773                     cos = Math.cos(angle);
15774                     sin = Math.sin(angle);
15775                     t1 = a12*cos+a13*sin;
15776                     t2 = a22*cos+a23*sin;
15777                     t3 = a32*cos+a33*sin;
15778                     t4 = a42*cos+a43*sin;
15779                     a13 = a12*-sin+a13*cos;
15780                     a23 = a22*-sin+a23*cos;
15781                     a33 = a32*-sin+a33*cos;
15782                     a43 = a42*-sin+a43*cos;
15783                     a12 = t1;
15784                     a22 = t2;
15785                     a32 = t3;
15786                     a42 = t4;
15787                 }
15788                 if (sz !== 1) {
15789                     a13*=sz;
15790                     a23*=sz;
15791                     a33*=sz;
15792                     a43*=sz;
15793                 }
15794                 if (sy !== 1) {
15795                     a12*=sy;
15796                     a22*=sy;
15797                     a32*=sy;
15798                     a42*=sy;
15799                 }
15800                 if (sx !== 1) {
15801                     a11*=sx;
15802                     a21*=sx;
15803                     a31*=sx;
15804                     a41*=sx;
15805                 }
15806                 if (zOrigin) {
15807                     a34 -= zOrigin;
15808                     a14 = a13*a34;
15809                     a24 = a23*a34;
15810                     a34 = a33*a34+zOrigin;
15811                 }
15812                 //we round the x, y, and z slightly differently to allow even larger values.
15813                 a14 = (t1 = (a14 += t.x) - (a14 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a14 : a14;
15814                 a24 = (t1 = (a24 += t.y) - (a24 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a24 : a24;
15815                 a34 = (t1 = (a34 += t.z) - (a34 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a34 : a34;
15816                 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(",") + ")";
15817             },
15818
15819             _set2DTransformRatio = _internals.set2DTransformRatio = function(v) {
15820                 var t = this.data, //refers to the element's _gsTransform object
15821                     targ = this.t,
15822                     style = targ.style,
15823                     ang, skew, rnd, sx, sy;
15824                 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.
15825                     this.setRatio = _set3DTransformRatio;
15826                     _set3DTransformRatio.call(this, v);
15827                     return;
15828                 }
15829                 if (!t.rotation && !t.skewX) {
15830                     style[_transformProp] = "matrix(" + t.scaleX + ",0,0," + t.scaleY + "," + t.x + "," + t.y + ")";
15831                 } else {
15832                     ang = t.rotation * _DEG2RAD;
15833                     skew = ang - t.skewX * _DEG2RAD;
15834                     rnd = 100000;
15835                     sx = t.scaleX * rnd;
15836                     sy = t.scaleY * rnd;
15837                     //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.
15838                     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 + ")";
15839                 }
15840             };
15841
15842         _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) {
15843             if (cssp._transform) { return pt; } //only need to parse the transform once, and only if the browser supports it.
15844             var m1 = cssp._transform = _getTransform(t, _cs, true, vars.parseTransform),
15845                 style = t.style,
15846                 min = 0.000001,
15847                 i = _transformProps.length,
15848                 v = vars,
15849                 endRotations = {},
15850                 m2, skewY, copy, orig, has3D, hasChange, dr;
15851             if (typeof(v.transform) === "string" && _transformProp) { //for values like transform:"rotate(60deg) scale(0.5, 0.8)"
15852                 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.
15853                 copy[_transformProp] = v.transform;
15854                 copy.display = "block"; //if display is "none", the browser often refuses to report the transform properties correctly.
15855                 copy.position = "absolute";
15856                 _doc.body.appendChild(_tempDiv);
15857                 m2 = _getTransform(_tempDiv, null, false);
15858                 _doc.body.removeChild(_tempDiv);
15859             } else if (typeof(v) === "object") { //for values like scaleX, scaleY, rotation, x, y, skewX, and skewY or transform:{...} (object)
15860                 m2 = {scaleX:_parseVal((v.scaleX != null) ? v.scaleX : v.scale, m1.scaleX),
15861                     scaleY:_parseVal((v.scaleY != null) ? v.scaleY : v.scale, m1.scaleY),
15862                     scaleZ:_parseVal(v.scaleZ, m1.scaleZ),
15863                     x:_parseVal(v.x, m1.x),
15864                     y:_parseVal(v.y, m1.y),
15865                     z:_parseVal(v.z, m1.z),
15866                     perspective:_parseVal(v.transformPerspective, m1.perspective)};
15867                 dr = v.directionalRotation;
15868                 if (dr != null) {
15869                     if (typeof(dr) === "object") {
15870                         for (copy in dr) {
15871                             v[copy] = dr[copy];
15872                         }
15873                     } else {
15874                         v.rotation = dr;
15875                     }
15876                 }
15877                 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);
15878                 if (_supports3D) {
15879                     m2.rotationX = _parseAngle(("rotationX" in v) ? v.rotationX : ("shortRotationX" in v) ? v.shortRotationX + "_short" : m1.rotationX || 0, m1.rotationX, "rotationX", endRotations);
15880                     m2.rotationY = _parseAngle(("rotationY" in v) ? v.rotationY : ("shortRotationY" in v) ? v.shortRotationY + "_short" : m1.rotationY || 0, m1.rotationY, "rotationY", endRotations);
15881                 }
15882                 m2.skewX = (v.skewX == null) ? m1.skewX : _parseAngle(v.skewX, m1.skewX);
15883
15884                 //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.
15885                 m2.skewY = (v.skewY == null) ? m1.skewY : _parseAngle(v.skewY, m1.skewY);
15886                 if ((skewY = m2.skewY - m1.skewY)) {
15887                     m2.skewX += skewY;
15888                     m2.rotation += skewY;
15889                 }
15890             }
15891
15892             if (_supports3D && v.force3D != null) {
15893                 m1.force3D = v.force3D;
15894                 hasChange = true;
15895             }
15896
15897             m1.skewType = v.skewType || m1.skewType || CSSPlugin.defaultSkewType;
15898
15899             has3D = (m1.force3D || m1.z || m1.rotationX || m1.rotationY || m2.z || m2.rotationX || m2.rotationY || m2.perspective);
15900             if (!has3D && v.scale != null) {
15901                 m2.scaleZ = 1; //no need to tween scaleZ.
15902             }
15903
15904             while (--i > -1) {
15905                 p = _transformProps[i];
15906                 orig = m2[p] - m1[p];
15907                 if (orig > min || orig < -min || _forcePT[p] != null) {
15908                     hasChange = true;
15909                     pt = new CSSPropTween(m1, p, m1[p], orig, pt);
15910                     if (p in endRotations) {
15911                         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
15912                     }
15913                     pt.xs0 = 0; //ensures the value stays numeric in setRatio()
15914                     pt.plugin = plugin;
15915                     cssp._overwriteProps.push(pt.n);
15916                 }
15917             }
15918
15919             orig = v.transformOrigin;
15920             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).
15921                 if (_transformProp) {
15922                     hasChange = true;
15923                     p = _transformOriginProp;
15924                     orig = (orig || _getStyle(t, p, _cs, false, "50% 50%")) + ""; //cast as string to avoid errors
15925                     pt = new CSSPropTween(style, p, 0, 0, pt, -1, "transformOrigin");
15926                     pt.b = style[p];
15927                     pt.plugin = plugin;
15928                     if (_supports3D) {
15929                         copy = m1.zOrigin;
15930                         orig = orig.split(" ");
15931                         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.
15932                         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)!
15933                         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)
15934                         pt.b = copy;
15935                         pt.xs0 = pt.e = m1.zOrigin;
15936                     } else {
15937                         pt.xs0 = pt.e = orig;
15938                     }
15939
15940                 //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).
15941                 } else {
15942                     _parsePosition(orig + "", m1);
15943                 }
15944             }
15945
15946             if (hasChange) {
15947                 cssp._transformType = (has3D || this._transformType === 3) ? 3 : 2; //quicker than calling cssp._enableTransforms();
15948             }
15949             return pt;
15950         }, prefix:true});
15951
15952         _registerComplexSpecialProp("boxShadow", {defaultValue:"0px 0px 0px 0px #999", prefix:true, color:true, multi:true, keyword:"inset"});
15953
15954         _registerComplexSpecialProp("borderRadius", {defaultValue:"0px", parser:function(t, e, p, cssp, pt, plugin) {
15955             e = this.format(e);
15956             var props = ["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"],
15957                 style = t.style,
15958                 ea1, i, es2, bs2, bs, es, bn, en, w, h, esfx, bsfx, rel, hn, vn, em;
15959             w = parseFloat(t.offsetWidth);
15960             h = parseFloat(t.offsetHeight);
15961             ea1 = e.split(" ");
15962             for (i = 0; i < props.length; i++) { //if we're dealing with percentages, we must convert things separately for the horizontal and vertical axis!
15963                 if (this.p.indexOf("border")) { //older browsers used a prefix
15964                     props[i] = _checkPropPrefix(props[i]);
15965                 }
15966                 bs = bs2 = _getStyle(t, props[i], _cs, false, "0px");
15967                 if (bs.indexOf(" ") !== -1) {
15968                     bs2 = bs.split(" ");
15969                     bs = bs2[0];
15970                     bs2 = bs2[1];
15971                 }
15972                 es = es2 = ea1[i];
15973                 bn = parseFloat(bs);
15974                 bsfx = bs.substr((bn + "").length);
15975                 rel = (es.charAt(1) === "=");
15976                 if (rel) {
15977                     en = parseInt(es.charAt(0)+"1", 10);
15978                     es = es.substr(2);
15979                     en *= parseFloat(es);
15980                     esfx = es.substr((en + "").length - (en < 0 ? 1 : 0)) || "";
15981                 } else {
15982                     en = parseFloat(es);
15983                     esfx = es.substr((en + "").length);
15984                 }
15985                 if (esfx === "") {
15986                     esfx = _suffixMap[p] || bsfx;
15987                 }
15988                 if (esfx !== bsfx) {
15989                     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.
15990                     vn = _convertToPixels(t, "borderTop", bn, bsfx); //vertical number
15991                     if (esfx === "%") {
15992                         bs = (hn / w * 100) + "%";
15993                         bs2 = (vn / h * 100) + "%";
15994                     } else if (esfx === "em") {
15995                         em = _convertToPixels(t, "borderLeft", 1, "em");
15996                         bs = (hn / em) + "em";
15997                         bs2 = (vn / em) + "em";
15998                     } else {
15999                         bs = hn + "px";
16000                         bs2 = vn + "px";
16001                     }
16002                     if (rel) {
16003                         es = (parseFloat(bs) + en) + esfx;
16004                         es2 = (parseFloat(bs2) + en) + esfx;
16005                     }
16006                 }
16007                 pt = _parseComplex(style, props[i], bs + " " + bs2, es + " " + es2, false, "0px", pt);
16008             }
16009             return pt;
16010         }, prefix:true, formatter:_getFormatter("0px 0px 0px 0px", false, true)});
16011         _registerComplexSpecialProp("backgroundPosition", {defaultValue:"0 0", parser:function(t, e, p, cssp, pt, plugin) {
16012             var bp = "background-position",
16013                 cs = (_cs || _getComputedStyle(t, null)),
16014                 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
16015                 es = this.format(e),
16016                 ba, ea, i, pct, overlap, src;
16017             if ((bs.indexOf("%") !== -1) !== (es.indexOf("%") !== -1)) {
16018                 src = _getStyle(t, "backgroundImage").replace(_urlExp, "");
16019                 if (src && src !== "none") {
16020                     ba = bs.split(" ");
16021                     ea = es.split(" ");
16022                     _tempImg.setAttribute("src", src); //set the temp <img>'s src to the background-image so that we can measure its width/height
16023                     i = 2;
16024                     while (--i > -1) {
16025                         bs = ba[i];
16026                         pct = (bs.indexOf("%") !== -1);
16027                         if (pct !== (ea[i].indexOf("%") !== -1)) {
16028                             overlap = (i === 0) ? t.offsetWidth - _tempImg.width : t.offsetHeight - _tempImg.height;
16029                             ba[i] = pct ? (parseFloat(bs) / 100 * overlap) + "px" : (parseFloat(bs) / overlap * 100) + "%";
16030                         }
16031                     }
16032                     bs = ba.join(" ");
16033                 }
16034             }
16035             return this.parseComplex(t.style, bs, es, pt, plugin);
16036         }, formatter:_parsePosition});
16037         _registerComplexSpecialProp("backgroundSize", {defaultValue:"0 0", formatter:_parsePosition});
16038         _registerComplexSpecialProp("perspective", {defaultValue:"0px", prefix:true});
16039         _registerComplexSpecialProp("perspectiveOrigin", {defaultValue:"50% 50%", prefix:true});
16040         _registerComplexSpecialProp("transformStyle", {prefix:true});
16041         _registerComplexSpecialProp("backfaceVisibility", {prefix:true});
16042         _registerComplexSpecialProp("userSelect", {prefix:true});
16043         _registerComplexSpecialProp("margin", {parser:_getEdgeParser("marginTop,marginRight,marginBottom,marginLeft")});
16044         _registerComplexSpecialProp("padding", {parser:_getEdgeParser("paddingTop,paddingRight,paddingBottom,paddingLeft")});
16045         _registerComplexSpecialProp("clip", {defaultValue:"rect(0px,0px,0px,0px)", parser:function(t, e, p, cssp, pt, plugin){
16046             var b, cs, delim;
16047             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.
16048                 cs = t.currentStyle;
16049                 delim = _ieVers < 8 ? " " : ",";
16050                 b = "rect(" + cs.clipTop + delim + cs.clipRight + delim + cs.clipBottom + delim + cs.clipLeft + ")";
16051                 e = this.format(e).split(",").join(delim);
16052             } else {
16053                 b = this.format(_getStyle(t, this.p, _cs, false, this.dflt));
16054                 e = this.format(e);
16055             }
16056             return this.parseComplex(t.style, b, e, pt, plugin);
16057         }});
16058         _registerComplexSpecialProp("textShadow", {defaultValue:"0px 0px 0px #999", color:true, multi:true});
16059         _registerComplexSpecialProp("autoRound,strictUnits", {parser:function(t, e, p, cssp, pt) {return pt;}}); //just so that we can ignore these properties (not tween them)
16060         _registerComplexSpecialProp("border", {defaultValue:"0px solid #000", parser:function(t, e, p, cssp, pt, plugin) {
16061                 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);
16062             }, color:true, formatter:function(v) {
16063                 var a = v.split(" ");
16064                 return a[0] + " " + (a[1] || "solid") + " " + (v.match(_colorExp) || ["#000"])[0];
16065             }});
16066         _registerComplexSpecialProp("borderWidth", {parser:_getEdgeParser("borderTopWidth,borderRightWidth,borderBottomWidth,borderLeftWidth")}); //Firefox doesn't pick up on borderWidth set in style sheets (only inline).
16067         _registerComplexSpecialProp("float,cssFloat,styleFloat", {parser:function(t, e, p, cssp, pt, plugin) {
16068             var s = t.style,
16069                 prop = ("cssFloat" in s) ? "cssFloat" : "styleFloat";
16070             return new CSSPropTween(s, prop, 0, 0, pt, -1, p, false, 0, s[prop], e);
16071         }});
16072
16073         //opacity-related
16074         var _setIEOpacityRatio = function(v) {
16075                 var t = this.t, //refers to the element's style property
16076                     filters = t.filter || _getStyle(this.data, "filter"),
16077                     val = (this.s + this.c * v) | 0,
16078                     skip;
16079                 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.
16080                     if (filters.indexOf("atrix(") === -1 && filters.indexOf("radient(") === -1 && filters.indexOf("oader(") === -1) {
16081                         t.removeAttribute("filter");
16082                         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.
16083                     } else {
16084                         t.filter = filters.replace(_alphaFilterExp, "");
16085                         skip = true;
16086                     }
16087                 }
16088                 if (!skip) {
16089                     if (this.xn1) {
16090                         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.
16091                     }
16092                     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
16093                         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)
16094                             t.filter = filters + " alpha(opacity=" + val + ")"; //we round the value because otherwise, bugs in IE7/8 can prevent "visibility" changes from being applied properly.
16095                         }
16096                     } else {
16097                         t.filter = filters.replace(_opacityExp, "opacity=" + val);
16098                     }
16099                 }
16100             };
16101         _registerComplexSpecialProp("opacity,alpha,autoAlpha", {defaultValue:"1", parser:function(t, e, p, cssp, pt, plugin) {
16102             var b = parseFloat(_getStyle(t, "opacity", _cs, false, "1")),
16103                 style = t.style,
16104                 isAutoAlpha = (p === "autoAlpha");
16105             if (typeof(e) === "string" && e.charAt(1) === "=") {
16106                 e = ((e.charAt(0) === "-") ? -1 : 1) * parseFloat(e.substr(2)) + b;
16107             }
16108             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)
16109                 b = 0;
16110             }
16111             if (_supportsOpacity) {
16112                 pt = new CSSPropTween(style, "opacity", b, e - b, pt);
16113             } else {
16114                 pt = new CSSPropTween(style, "opacity", b * 100, (e - b) * 100, pt);
16115                 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.
16116                 style.zoom = 1; //helps correct an IE issue.
16117                 pt.type = 2;
16118                 pt.b = "alpha(opacity=" + pt.s + ")";
16119                 pt.e = "alpha(opacity=" + (pt.s + pt.c) + ")";
16120                 pt.data = t;
16121                 pt.plugin = plugin;
16122                 pt.setRatio = _setIEOpacityRatio;
16123             }
16124             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
16125                 pt = new CSSPropTween(style, "visibility", 0, 0, pt, -1, null, false, 0, ((b !== 0) ? "inherit" : "hidden"), ((e === 0) ? "hidden" : "inherit"));
16126                 pt.xs0 = "inherit";
16127                 cssp._overwriteProps.push(pt.n);
16128                 cssp._overwriteProps.push(p);
16129             }
16130             return pt;
16131         }});
16132
16133
16134         var _removeProp = function(s, p) {
16135                 if (p) {
16136                     if (s.removeProperty) {
16137                         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)
16138                             p = "M" + p.substr(1);
16139                         }
16140                         s.removeProperty(p.replace(_capsExp, "-$1").toLowerCase());
16141                     } else { //note: old versions of IE use "removeAttribute()" instead of "removeProperty()"
16142                         s.removeAttribute(p);
16143                     }
16144                 }
16145             },
16146             _setClassNameRatio = function(v) {
16147                 this.t._gsClassPT = this;
16148                 if (v === 1 || v === 0) {
16149                     this.t.setAttribute("class", (v === 0) ? this.b : this.e);
16150                     var mpt = this.data, //first MiniPropTween
16151                         s = this.t.style;
16152                     while (mpt) {
16153                         if (!mpt.v) {
16154                             _removeProp(s, mpt.p);
16155                         } else {
16156                             s[mpt.p] = mpt.v;
16157                         }
16158                         mpt = mpt._next;
16159                     }
16160                     if (v === 1 && this.t._gsClassPT === this) {
16161                         this.t._gsClassPT = null;
16162                     }
16163                 } else if (this.t.getAttribute("class") !== this.e) {
16164                     this.t.setAttribute("class", this.e);
16165                 }
16166             };
16167         _registerComplexSpecialProp("className", {parser:function(t, e, p, cssp, pt, plugin, vars) {
16168             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.
16169                 cssText = t.style.cssText,
16170                 difData, bs, cnpt, cnptLookup, mpt;
16171             pt = cssp._classNamePT = new CSSPropTween(t, p, 0, 0, pt, 2);
16172             pt.setRatio = _setClassNameRatio;
16173             pt.pr = -11;
16174             _hasPriority = true;
16175             pt.b = b;
16176             bs = _getAllStyles(t, _cs);
16177             //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)
16178             cnpt = t._gsClassPT;
16179             if (cnpt) {
16180                 cnptLookup = {};
16181                 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.
16182                 while (mpt) {
16183                     cnptLookup[mpt.p] = 1;
16184                     mpt = mpt._next;
16185                 }
16186                 cnpt.setRatio(1);
16187             }
16188             t._gsClassPT = pt;
16189             pt.e = (e.charAt(1) !== "=") ? e : b.replace(new RegExp("\\s*\\b" + e.substr(2) + "\\b"), "") + ((e.charAt(0) === "+") ? " " + e.substr(2) : "");
16190             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.
16191                 t.setAttribute("class", pt.e);
16192                 difData = _cssDif(t, bs, _getAllStyles(t), vars, cnptLookup);
16193                 t.setAttribute("class", b);
16194                 pt.data = difData.firstMPT;
16195                 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).
16196                 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)
16197             }
16198             return pt;
16199         }});
16200
16201
16202         var _setClearPropsRatio = function(v) {
16203             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).
16204                 var s = this.t.style,
16205                     transformParse = _specialProps.transform.parse,
16206                     a, p, i, clearTransform;
16207                 if (this.e === "all") {
16208                     s.cssText = "";
16209                     clearTransform = true;
16210                 } else {
16211                     a = this.e.split(",");
16212                     i = a.length;
16213                     while (--i > -1) {
16214                         p = a[i];
16215                         if (_specialProps[p]) {
16216                             if (_specialProps[p].parse === transformParse) {
16217                                 clearTransform = true;
16218                             } else {
16219                                 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"
16220                             }
16221                         }
16222                         _removeProp(s, p);
16223                     }
16224                 }
16225                 if (clearTransform) {
16226                     _removeProp(s, _transformProp);
16227                     if (this.t._gsTransform) {
16228                         delete this.t._gsTransform;
16229                     }
16230                 }
16231
16232             }
16233         };
16234         _registerComplexSpecialProp("clearProps", {parser:function(t, e, p, cssp, pt) {
16235             pt = new CSSPropTween(t, p, 0, 0, pt, 2);
16236             pt.setRatio = _setClearPropsRatio;
16237             pt.e = e;
16238             pt.pr = -10;
16239             pt.data = cssp._tween;
16240             _hasPriority = true;
16241             return pt;
16242         }});
16243
16244         p = "bezier,throwProps,physicsProps,physics2D".split(",");
16245         i = p.length;
16246         while (i--) {
16247             _registerPluginProp(p[i]);
16248         }
16249
16250
16251
16252
16253
16254
16255
16256
16257         p = CSSPlugin.prototype;
16258         p._firstPT = null;
16259
16260         //gets called when the tween renders for the first time. This kicks everything off, recording start/end values, etc.
16261         p._onInitTween = function(target, vars, tween) {
16262             if (!target.nodeType) { //css is only for dom elements
16263                 return false;
16264             }
16265             this._target = target;
16266             this._tween = tween;
16267             this._vars = vars;
16268             _autoRound = vars.autoRound;
16269             _hasPriority = false;
16270             _suffixMap = vars.suffixMap || CSSPlugin.suffixMap;
16271             _cs = _getComputedStyle(target, "");
16272             _overwriteProps = this._overwriteProps;
16273             var style = target.style,
16274                 v, pt, pt2, first, last, next, zIndex, tpt, threeD;
16275             if (_reqSafariFix) if (style.zIndex === "") {
16276                 v = _getStyle(target, "zIndex", _cs);
16277                 if (v === "auto" || v === "") {
16278                     //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.
16279                     this._addLazySet(style, "zIndex", 0);
16280                 }
16281             }
16282
16283             if (typeof(vars) === "string") {
16284                 first = style.cssText;
16285                 v = _getAllStyles(target, _cs);
16286                 style.cssText = first + ";" + vars;
16287                 v = _cssDif(target, v, _getAllStyles(target)).difs;
16288                 if (!_supportsOpacity && _opacityValExp.test(vars)) {
16289                     v.opacity = parseFloat( RegExp.$1 );
16290                 }
16291                 vars = v;
16292                 style.cssText = first;
16293             }
16294             this._firstPT = pt = this.parse(target, vars, null);
16295
16296             if (this._transformType) {
16297                 threeD = (this._transformType === 3);
16298                 if (!_transformProp) {
16299                     style.zoom = 1; //helps correct an IE issue.
16300                 } else if (_isSafari) {
16301                     _reqSafariFix = true;
16302                     //if zIndex isn't set, iOS Safari doesn't repaint things correctly sometimes (seemingly at random).
16303                     if (style.zIndex === "") {
16304                         zIndex = _getStyle(target, "zIndex", _cs);
16305                         if (zIndex === "auto" || zIndex === "") {
16306                             this._addLazySet(style, "zIndex", 0);
16307                         }
16308                     }
16309                     //Setting WebkitBackfaceVisibility corrects 3 bugs:
16310                     // 1) [non-Android] Safari skips rendering changes to "top" and "left" that are made on the same frame/render as a transform update.
16311                     // 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.
16312                     // 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.
16313                     //Note: we allow the user to override the auto-setting by defining WebkitBackfaceVisibility in the vars of the tween.
16314                     if (_isSafariLT6) {
16315                         this._addLazySet(style, "WebkitBackfaceVisibility", this._vars.WebkitBackfaceVisibility || (threeD ? "visible" : "hidden"));
16316                     }
16317                 }
16318                 pt2 = pt;
16319                 while (pt2 && pt2._next) {
16320                     pt2 = pt2._next;
16321                 }
16322                 tpt = new CSSPropTween(target, "transform", 0, 0, null, 2);
16323                 this._linkCSSP(tpt, null, pt2);
16324                 tpt.setRatio = (threeD && _supports3D) ? _set3DTransformRatio : _transformProp ? _set2DTransformRatio : _setIETransformRatio;
16325                 tpt.data = this._transform || _getTransform(target, _cs, true);
16326                 _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.
16327             }
16328
16329             if (_hasPriority) {
16330                 //reorders the linked list in order of pr (priority)
16331                 while (pt) {
16332                     next = pt._next;
16333                     pt2 = first;
16334                     while (pt2 && pt2.pr > pt.pr) {
16335                         pt2 = pt2._next;
16336                     }
16337                     if ((pt._prev = pt2 ? pt2._prev : last)) {
16338                         pt._prev._next = pt;
16339                     } else {
16340                         first = pt;
16341                     }
16342                     if ((pt._next = pt2)) {
16343                         pt2._prev = pt;
16344                     } else {
16345                         last = pt;
16346                     }
16347                     pt = next;
16348                 }
16349                 this._firstPT = first;
16350             }
16351             return true;
16352         };
16353
16354
16355         p.parse = function(target, vars, pt, plugin) {
16356             var style = target.style,
16357                 p, sp, bn, en, bs, es, bsfx, esfx, isStr, rel;
16358             for (p in vars) {
16359                 es = vars[p]; //ending value string
16360                 sp = _specialProps[p]; //SpecialProp lookup.
16361                 if (sp) {
16362                     pt = sp.parse(target, es, p, this, pt, plugin, vars);
16363
16364                 } else {
16365                     bs = _getStyle(target, p, _cs) + "";
16366                     isStr = (typeof(es) === "string");
16367                     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:
16368                         if (!isStr) {
16369                             es = _parseColor(es);
16370                             es = ((es.length > 3) ? "rgba(" : "rgb(") + es.join(",") + ")";
16371                         }
16372                         pt = _parseComplex(style, p, bs, es, true, "transparent", pt, 0, plugin);
16373
16374                     } else if (isStr && (es.indexOf(" ") !== -1 || es.indexOf(",") !== -1)) {
16375                         pt = _parseComplex(style, p, bs, es, true, null, pt, 0, plugin);
16376
16377                     } else {
16378                         bn = parseFloat(bs);
16379                         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.
16380
16381                         if (bs === "" || bs === "auto") {
16382                             if (p === "width" || p === "height") {
16383                                 bn = _getDimension(target, p, _cs);
16384                                 bsfx = "px";
16385                             } else if (p === "left" || p === "top") {
16386                                 bn = _calculateOffset(target, p, _cs);
16387                                 bsfx = "px";
16388                             } else {
16389                                 bn = (p !== "opacity") ? 0 : 1;
16390                                 bsfx = "";
16391                             }
16392                         }
16393
16394                         rel = (isStr && es.charAt(1) === "=");
16395                         if (rel) {
16396                             en = parseInt(es.charAt(0) + "1", 10);
16397                             es = es.substr(2);
16398                             en *= parseFloat(es);
16399                             esfx = es.replace(_suffixExp, "");
16400                         } else {
16401                             en = parseFloat(es);
16402                             esfx = isStr ? es.substr((en + "").length) || "" : "";
16403                         }
16404
16405                         if (esfx === "") {
16406                             esfx = (p in _suffixMap) ? _suffixMap[p] : bsfx; //populate the end suffix, prioritizing the map, then if none is found, use the beginning suffix.
16407                         }
16408
16409                         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.
16410
16411                         //if the beginning/ending suffixes don't match, normalize them...
16412                         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!
16413                             bn = _convertToPixels(target, p, bn, bsfx);
16414                             if (esfx === "%") {
16415                                 bn /= _convertToPixels(target, p, 100, "%") / 100;
16416                                 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.
16417                                     bs = bn + "%";
16418                                 }
16419
16420                             } else if (esfx === "em") {
16421                                 bn /= _convertToPixels(target, p, 1, "em");
16422
16423                             //otherwise convert to pixels.
16424                             } else if (esfx !== "px") {
16425                                 en = _convertToPixels(target, p, en, esfx);
16426                                 esfx = "px"; //we don't use bsfx after this, so we don't need to set it to px too.
16427                             }
16428                             if (rel) if (en || en === 0) {
16429                                 es = (en + bn) + esfx; //the changes we made affect relative calculations, so adjust the end value here.
16430                             }
16431                         }
16432
16433                         if (rel) {
16434                             en += bn;
16435                         }
16436
16437                         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.
16438                             pt = new CSSPropTween(style, p, bn, en - bn, pt, 0, p, (_autoRound !== false && (esfx === "px" || p === "zIndex")), 0, bs, es);
16439                             pt.xs0 = esfx;
16440                             //DEBUG: _log("tween "+p+" from "+pt.b+" ("+bn+esfx+") to "+pt.e+" with suffix: "+pt.xs0);
16441                         } else if (style[p] === undefined || !es && (es + "" === "NaN" || es == null)) {
16442                             _log("invalid " + p + " tween value: " + vars[p]);
16443                         } else {
16444                             pt = new CSSPropTween(style, p, en || bn || 0, 0, pt, -1, p, false, 0, bs, es);
16445                             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.
16446                             //DEBUG: _log("non-tweening value "+p+": "+pt.xs0);
16447                         }
16448                     }
16449                 }
16450                 if (plugin) if (pt && !pt.plugin) {
16451                     pt.plugin = plugin;
16452                 }
16453             }
16454             return pt;
16455         };
16456
16457
16458         //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.
16459         p.setRatio = function(v) {
16460             var pt = this._firstPT,
16461                 min = 0.000001,
16462                 val, str, i;
16463
16464             //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).
16465             if (v === 1 && (this._tween._time === this._tween._duration || this._tween._time === 0)) {
16466                 while (pt) {
16467                     if (pt.type !== 2) {
16468                         pt.t[pt.p] = pt.e;
16469                     } else {
16470                         pt.setRatio(v);
16471                     }
16472                     pt = pt._next;
16473                 }
16474
16475             } else if (v || !(this._tween._time === this._tween._duration || this._tween._time === 0) || this._tween._rawPrevTime === -0.000001) {
16476                 while (pt) {
16477                     val = pt.c * v + pt.s;
16478                     if (pt.r) {
16479                         val = Math.round(val);
16480                     } else if (val < min) if (val > -min) {
16481                         val = 0;
16482                     }
16483                     if (!pt.type) {
16484                         pt.t[pt.p] = val + pt.xs0;
16485                     } else if (pt.type === 1) { //complex value (one that typically has multiple numbers inside a string, like "rect(5px,10px,20px,25px)"
16486                         i = pt.l;
16487                         if (i === 2) {
16488                             pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2;
16489                         } else if (i === 3) {
16490                             pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3;
16491                         } else if (i === 4) {
16492                             pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3 + pt.xn3 + pt.xs4;
16493                         } else if (i === 5) {
16494                             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;
16495                         } else {
16496                             str = pt.xs0 + val + pt.xs1;
16497                             for (i = 1; i < pt.l; i++) {
16498                                 str += pt["xn"+i] + pt["xs"+(i+1)];
16499                             }
16500                             pt.t[pt.p] = str;
16501                         }
16502
16503                     } else if (pt.type === -1) { //non-tweening value
16504                         pt.t[pt.p] = pt.xs0;
16505
16506                     } else if (pt.setRatio) { //custom setRatio() for things like SpecialProps, external plugins, etc.
16507                         pt.setRatio(v);
16508                     }
16509                     pt = pt._next;
16510                 }
16511
16512             //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).
16513             } else {
16514                 while (pt) {
16515                     if (pt.type !== 2) {
16516                         pt.t[pt.p] = pt.b;
16517                     } else {
16518                         pt.setRatio(v);
16519                     }
16520                     pt = pt._next;
16521                 }
16522             }
16523         };
16524
16525         /**
16526          * @private
16527          * Forces rendering of the target's transforms (rotation, scale, etc.) whenever the CSSPlugin's setRatio() is called.
16528          * Basically, this tells the CSSPlugin to create a CSSPropTween (type 2) after instantiation that runs last in the linked
16529          * list and calls the appropriate (3D or 2D) rendering function. We separate this into its own method so that we can call
16530          * it from other plugins like BezierPlugin if, for example, it needs to apply an autoRotation and this CSSPlugin
16531          * doesn't have any transform-related properties of its own. You can call this method as many times as you
16532          * want and it won't create duplicate CSSPropTweens.
16533          *
16534          * @param {boolean} threeD if true, it should apply 3D tweens (otherwise, just 2D ones are fine and typically faster)
16535          */
16536         p._enableTransforms = function(threeD) {
16537             this._transformType = (threeD || this._transformType === 3) ? 3 : 2;
16538             this._transform = this._transform || _getTransform(this._target, _cs, true); //ensures that the element has a _gsTransform property with the appropriate values.
16539         };
16540
16541         var lazySet = function(v) {
16542             this.t[this.p] = this.e;
16543             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.
16544         };
16545         /** @private Gives us a way to set a value on the first render (and only the first render). **/
16546         p._addLazySet = function(t, p, v) {
16547             var pt = this._firstPT = new CSSPropTween(t, p, 0, 0, this._firstPT, 2);
16548             pt.e = v;
16549             pt.setRatio = lazySet;
16550             pt.data = this;
16551         };
16552
16553         /** @private **/
16554         p._linkCSSP = function(pt, next, prev, remove) {
16555             if (pt) {
16556                 if (next) {
16557                     next._prev = pt;
16558                 }
16559                 if (pt._next) {
16560                     pt._next._prev = pt._prev;
16561                 }
16562                 if (pt._prev) {
16563                     pt._prev._next = pt._next;
16564                 } else if (this._firstPT === pt) {
16565                     this._firstPT = pt._next;
16566                     remove = true; //just to prevent resetting this._firstPT 5 lines down in case pt._next is null. (optimized for speed)
16567                 }
16568                 if (prev) {
16569                     prev._next = pt;
16570                 } else if (!remove && this._firstPT === null) {
16571                     this._firstPT = pt;
16572                 }
16573                 pt._next = next;
16574                 pt._prev = prev;
16575             }
16576             return pt;
16577         };
16578
16579         //we need to make sure that if alpha or autoAlpha is killed, opacity is too. And autoAlpha affects the "visibility" property.
16580         p._kill = function(lookup) {
16581             var copy = lookup,
16582                 pt, p, xfirst;
16583             if (lookup.autoAlpha || lookup.alpha) {
16584                 copy = {};
16585                 for (p in lookup) { //copy the lookup so that we're not changing the original which may be passed elsewhere.
16586                     copy[p] = lookup[p];
16587                 }
16588                 copy.opacity = 1;
16589                 if (copy.autoAlpha) {
16590                     copy.visibility = 1;
16591                 }
16592             }
16593             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".
16594                 xfirst = pt.xfirst;
16595                 if (xfirst && xfirst._prev) {
16596                     this._linkCSSP(xfirst._prev, pt._next, xfirst._prev._prev); //break off the prev
16597                 } else if (xfirst === this._firstPT) {
16598                     this._firstPT = pt._next;
16599                 }
16600                 if (pt._next) {
16601                     this._linkCSSP(pt._next, pt._next._next, xfirst._prev);
16602                 }
16603                 this._classNamePT = null;
16604             }
16605             return TweenPlugin.prototype._kill.call(this, copy);
16606         };
16607
16608
16609
16610         //used by cascadeTo() for gathering all the style properties of each child element into an array for comparison.
16611         var _getChildStyles = function(e, props, targets) {
16612                 var children, i, child, type;
16613                 if (e.slice) {
16614                     i = e.length;
16615                     while (--i > -1) {
16616                         _getChildStyles(e[i], props, targets);
16617                     }
16618                     return;
16619                 }
16620                 children = e.childNodes;
16621                 i = children.length;
16622                 while (--i > -1) {
16623                     child = children[i];
16624                     type = child.type;
16625                     if (child.style) {
16626                         props.push(_getAllStyles(child));
16627                         if (targets) {
16628                             targets.push(child);
16629                         }
16630                     }
16631                     if ((type === 1 || type === 9 || type === 11) && child.childNodes.length) {
16632                         _getChildStyles(child, props, targets);
16633                     }
16634                 }
16635             };
16636
16637         /**
16638          * Typically only useful for className tweens that may affect child elements, this method creates a TweenLite
16639          * and then compares the style properties of all the target's child elements at the tween's start and end, and
16640          * if any are different, it also creates tweens for those and returns an array containing ALL of the resulting
16641          * tweens (so that you can easily add() them to a TimelineLite, for example). The reason this functionality is
16642          * wrapped into a separate static method of CSSPlugin instead of being integrated into all regular className tweens
16643          * is because it creates entirely new tweens that may have completely different targets than the original tween,
16644          * so if they were all lumped into the original tween instance, it would be inconsistent with the rest of the API
16645          * and it would create other problems. For example:
16646          *  - 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)
16647          *  - 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.
16648          *  - 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.
16649          *
16650          * @param {Object} target object to be tweened
16651          * @param {number} Duration in seconds (or frames for frames-based tweens)
16652          * @param {Object} Object containing the end values, like {className:"newClass", ease:Linear.easeNone}
16653          * @return {Array} An array of TweenLite instances
16654          */
16655         CSSPlugin.cascadeTo = function(target, duration, vars) {
16656             var tween = TweenLite.to(target, duration, vars),
16657                 results = [tween],
16658                 b = [],
16659                 e = [],
16660                 targets = [],
16661                 _reservedProps = TweenLite._internals.reservedProps,
16662                 i, difs, p;
16663             target = tween._targets || tween.target;
16664             _getChildStyles(target, b, targets);
16665             tween.render(duration, true);
16666             _getChildStyles(target, e);
16667             tween.render(0, true);
16668             tween._enabled(true);
16669             i = targets.length;
16670             while (--i > -1) {
16671                 difs = _cssDif(targets[i], b[i], e[i]);
16672                 if (difs.firstMPT) {
16673                     difs = difs.difs;
16674                     for (p in vars) {
16675                         if (_reservedProps[p]) {
16676                             difs[p] = vars[p];
16677                         }
16678                     }
16679                     results.push( TweenLite.to(targets[i], duration, difs) );
16680                 }
16681             }
16682             return results;
16683         };
16684
16685         TweenPlugin.activate([CSSPlugin]);
16686         return CSSPlugin;
16687
16688     }, true);
16689
16690     
16691     
16692     
16693     
16694     
16695     
16696     
16697     
16698     
16699     
16700 /*
16701  * ----------------------------------------------------------------
16702  * RoundPropsPlugin
16703  * ----------------------------------------------------------------
16704  */
16705     (function() {
16706
16707         var RoundPropsPlugin = window._gsDefine.plugin({
16708                 propName: "roundProps",
16709                 priority: -1,
16710                 API: 2,
16711
16712                 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
16713                 init: function(target, value, tween) {
16714                     this._tween = tween;
16715                     return true;
16716                 }
16717
16718             }),
16719             p = RoundPropsPlugin.prototype;
16720
16721         p._onInitAllProps = function() {
16722             var tween = this._tween,
16723                 rp = (tween.vars.roundProps instanceof Array) ? tween.vars.roundProps : tween.vars.roundProps.split(","),
16724                 i = rp.length,
16725                 lookup = {},
16726                 rpt = tween._propLookup.roundProps,
16727                 prop, pt, next;
16728             while (--i > -1) {
16729                 lookup[rp[i]] = 1;
16730             }
16731             i = rp.length;
16732             while (--i > -1) {
16733                 prop = rp[i];
16734                 pt = tween._firstPT;
16735                 while (pt) {
16736                     next = pt._next; //record here, because it may get removed
16737                     if (pt.pg) {
16738                         pt.t._roundProps(lookup, true);
16739                     } else if (pt.n === prop) {
16740                         this._add(pt.t, prop, pt.s, pt.c);
16741                         //remove from linked list
16742                         if (next) {
16743                             next._prev = pt._prev;
16744                         }
16745                         if (pt._prev) {
16746                             pt._prev._next = next;
16747                         } else if (tween._firstPT === pt) {
16748                             tween._firstPT = next;
16749                         }
16750                         pt._next = pt._prev = null;
16751                         tween._propLookup[prop] = rpt;
16752                     }
16753                     pt = next;
16754                 }
16755             }
16756             return false;
16757         };
16758
16759         p._add = function(target, p, s, c) {
16760             this._addTween(target, p, s, s + c, p, true);
16761             this._overwriteProps.push(p);
16762         };
16763
16764     }());
16765
16766
16767
16768
16769
16770
16771
16772
16773
16774
16775 /*
16776  * ----------------------------------------------------------------
16777  * AttrPlugin
16778  * ----------------------------------------------------------------
16779  */
16780     window._gsDefine.plugin({
16781         propName: "attr",
16782         API: 2,
16783         version: "0.3.2",
16784
16785         //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
16786         init: function(target, value, tween) {
16787             var p, start, end;
16788             if (typeof(target.setAttribute) !== "function") {
16789                 return false;
16790             }
16791             this._target = target;
16792             this._proxy = {};
16793             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.
16794             this._end = {};
16795             for (p in value) {
16796                 this._start[p] = this._proxy[p] = start = target.getAttribute(p);
16797                 end = this._addTween(this._proxy, p, parseFloat(start), value[p], p);
16798                 this._end[p] = end ? end.s + end.c : value[p];
16799                 this._overwriteProps.push(p);
16800             }
16801             return true;
16802         },
16803
16804         //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.)
16805         set: function(ratio) {
16806             this._super.setRatio.call(this, ratio);
16807             var props = this._overwriteProps,
16808                 i = props.length,
16809                 lookup = (ratio === 1) ? this._end : ratio ? this._proxy : this._start,
16810                 p;
16811             while (--i > -1) {
16812                 p = props[i];
16813                 this._target.setAttribute(p, lookup[p] + "");
16814             }
16815         }
16816
16817     });
16818
16819
16820
16821
16822
16823
16824
16825
16826
16827
16828 /*
16829  * ----------------------------------------------------------------
16830  * DirectionalRotationPlugin
16831  * ----------------------------------------------------------------
16832  */
16833     window._gsDefine.plugin({
16834         propName: "directionalRotation",
16835         API: 2,
16836         version: "0.2.0",
16837
16838         //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
16839         init: function(target, value, tween) {
16840             if (typeof(value) !== "object") {
16841                 value = {rotation:value};
16842             }
16843             this.finals = {};
16844             var cap = (value.useRadians === true) ? Math.PI * 2 : 360,
16845                 min = 0.000001,
16846                 p, v, start, end, dif, split;
16847             for (p in value) {
16848                 if (p !== "useRadians") {
16849                     split = (value[p] + "").split("_");
16850                     v = split[0];
16851                     start = parseFloat( (typeof(target[p]) !== "function") ? target[p] : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]() );
16852                     end = this.finals[p] = (typeof(v) === "string" && v.charAt(1) === "=") ? start + parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) : Number(v) || 0;
16853                     dif = end - start;
16854                     if (split.length) {
16855                         v = split.join("_");
16856                         if (v.indexOf("short") !== -1) {
16857                             dif = dif % cap;
16858                             if (dif !== dif % (cap / 2)) {
16859                                 dif = (dif < 0) ? dif + cap : dif - cap;
16860                             }
16861                         }
16862                         if (v.indexOf("_cw") !== -1 && dif < 0) {
16863                             dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
16864                         } else if (v.indexOf("ccw") !== -1 && dif > 0) {
16865                             dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
16866                         }
16867                     }
16868                     if (dif > min || dif < -min) {
16869                         this._addTween(target, p, start, start + dif, p);
16870                         this._overwriteProps.push(p);
16871                     }
16872                 }
16873             }
16874             return true;
16875         },
16876
16877         //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.)
16878         set: function(ratio) {
16879             var pt;
16880             if (ratio !== 1) {
16881                 this._super.setRatio.call(this, ratio);
16882             } else {
16883                 pt = this._firstPT;
16884                 while (pt) {
16885                     if (pt.f) {
16886                         pt.t[pt.p](this.finals[pt.p]);
16887                     } else {
16888                         pt.t[pt.p] = this.finals[pt.p];
16889                     }
16890                     pt = pt._next;
16891                 }
16892             }
16893         }
16894
16895     })._autoCSS = true;
16896
16897
16898
16899
16900
16901
16902
16903     
16904     
16905     
16906     
16907 /*
16908  * ----------------------------------------------------------------
16909  * EasePack
16910  * ----------------------------------------------------------------
16911  */
16912     window._gsDefine("easing.Back", ["easing.Ease"], function(Ease) {
16913         
16914         var w = (window.GreenSockGlobals || window),
16915             gs = w.com.greensock,
16916             _2PI = Math.PI * 2,
16917             _HALF_PI = Math.PI / 2,
16918             _class = gs._class,
16919             _create = function(n, f) {
16920                 var C = _class("easing." + n, function(){}, true),
16921                     p = C.prototype = new Ease();
16922                 p.constructor = C;
16923                 p.getRatio = f;
16924                 return C;
16925             },
16926             _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.
16927             _wrap = function(name, EaseOut, EaseIn, EaseInOut, aliases) {
16928                 var C = _class("easing."+name, {
16929                     easeOut:new EaseOut(),
16930                     easeIn:new EaseIn(),
16931                     easeInOut:new EaseInOut()
16932                 }, true);
16933                 _easeReg(C, name);
16934                 return C;
16935             },
16936             EasePoint = function(time, value, next) {
16937                 this.t = time;
16938                 this.v = value;
16939                 if (next) {
16940                     this.next = next;
16941                     next.prev = this;
16942                     this.c = next.v - value;
16943                     this.gap = next.t - time;
16944                 }
16945             },
16946
16947             //Back
16948             _createBack = function(n, f) {
16949                 var C = _class("easing." + n, function(overshoot) {
16950                         this._p1 = (overshoot || overshoot === 0) ? overshoot : 1.70158;
16951                         this._p2 = this._p1 * 1.525;
16952                     }, true),
16953                     p = C.prototype = new Ease();
16954                 p.constructor = C;
16955                 p.getRatio = f;
16956                 p.config = function(overshoot) {
16957                     return new C(overshoot);
16958                 };
16959                 return C;
16960             },
16961
16962             Back = _wrap("Back",
16963                 _createBack("BackOut", function(p) {
16964                     return ((p = p - 1) * p * ((this._p1 + 1) * p + this._p1) + 1);
16965                 }),
16966                 _createBack("BackIn", function(p) {
16967                     return p * p * ((this._p1 + 1) * p - this._p1);
16968                 }),
16969                 _createBack("BackInOut", function(p) {
16970                     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);
16971                 })
16972             ),
16973
16974
16975             //SlowMo
16976             SlowMo = _class("easing.SlowMo", function(linearRatio, power, yoyoMode) {
16977                 power = (power || power === 0) ? power : 0.7;
16978                 if (linearRatio == null) {
16979                     linearRatio = 0.7;
16980                 } else if (linearRatio > 1) {
16981                     linearRatio = 1;
16982                 }
16983                 this._p = (linearRatio !== 1) ? power : 0;
16984                 this._p1 = (1 - linearRatio) / 2;
16985                 this._p2 = linearRatio;
16986                 this._p3 = this._p1 + this._p2;
16987                 this._calcEnd = (yoyoMode === true);
16988             }, true),
16989             p = SlowMo.prototype = new Ease(),
16990             SteppedEase, RoughEase, _createElastic;
16991
16992         p.constructor = SlowMo;
16993         p.getRatio = function(p) {
16994             var r = p + (0.5 - p) * this._p;
16995             if (p < this._p1) {
16996                 return this._calcEnd ? 1 - ((p = 1 - (p / this._p1)) * p) : r - ((p = 1 - (p / this._p1)) * p * p * p * r);
16997             } else if (p > this._p3) {
16998                 return this._calcEnd ? 1 - (p = (p - this._p3) / this._p1) * p : r + ((p - r) * (p = (p - this._p3) / this._p1) * p * p * p);
16999             }
17000             return this._calcEnd ? 1 : r;
17001         };
17002         SlowMo.ease = new SlowMo(0.7, 0.7);
17003
17004         p.config = SlowMo.config = function(linearRatio, power, yoyoMode) {
17005             return new SlowMo(linearRatio, power, yoyoMode);
17006         };
17007
17008
17009         //SteppedEase
17010         SteppedEase = _class("easing.SteppedEase", function(steps) {
17011                 steps = steps || 1;
17012                 this._p1 = 1 / steps;
17013                 this._p2 = steps + 1;
17014             }, true);
17015         p = SteppedEase.prototype = new Ease();
17016         p.constructor = SteppedEase;
17017         p.getRatio = function(p) {
17018             if (p < 0) {
17019                 p = 0;
17020             } else if (p >= 1) {
17021                 p = 0.999999999;
17022             }
17023             return ((this._p2 * p) >> 0) * this._p1;
17024         };
17025         p.config = SteppedEase.config = function(steps) {
17026             return new SteppedEase(steps);
17027         };
17028
17029
17030         //RoughEase
17031         RoughEase = _class("easing.RoughEase", function(vars) {
17032             vars = vars || {};
17033             var taper = vars.taper || "none",
17034                 a = [],
17035                 cnt = 0,
17036                 points = (vars.points || 20) | 0,
17037                 i = points,
17038                 randomize = (vars.randomize !== false),
17039                 clamp = (vars.clamp === true),
17040                 template = (vars.template instanceof Ease) ? vars.template : null,
17041                 strength = (typeof(vars.strength) === "number") ? vars.strength * 0.4 : 0.4,
17042                 x, y, bump, invX, obj, pnt;
17043             while (--i > -1) {
17044                 x = randomize ? Math.random() : (1 / points) * i;
17045                 y = template ? template.getRatio(x) : x;
17046                 if (taper === "none") {
17047                     bump = strength;
17048                 } else if (taper === "out") {
17049                     invX = 1 - x;
17050                     bump = invX * invX * strength;
17051                 } else if (taper === "in") {
17052                     bump = x * x * strength;
17053                 } else if (x < 0.5) {  //"both" (start)
17054                     invX = x * 2;
17055                     bump = invX * invX * 0.5 * strength;
17056                 } else {                //"both" (end)
17057                     invX = (1 - x) * 2;
17058                     bump = invX * invX * 0.5 * strength;
17059                 }
17060                 if (randomize) {
17061                     y += (Math.random() * bump) - (bump * 0.5);
17062                 } else if (i % 2) {
17063                     y += bump * 0.5;
17064                 } else {
17065                     y -= bump * 0.5;
17066                 }
17067                 if (clamp) {
17068                     if (y > 1) {
17069                         y = 1;
17070                     } else if (y < 0) {
17071                         y = 0;
17072                     }
17073                 }
17074                 a[cnt++] = {x:x, y:y};
17075             }
17076             a.sort(function(a, b) {
17077                 return a.x - b.x;
17078             });
17079
17080             pnt = new EasePoint(1, 1, null);
17081             i = points;
17082             while (--i > -1) {
17083                 obj = a[i];
17084                 pnt = new EasePoint(obj.x, obj.y, pnt);
17085             }
17086
17087             this._prev = new EasePoint(0, 0, (pnt.t !== 0) ? pnt : pnt.next);
17088         }, true);
17089         p = RoughEase.prototype = new Ease();
17090         p.constructor = RoughEase;
17091         p.getRatio = function(p) {
17092             var pnt = this._prev;
17093             if (p > pnt.t) {
17094                 while (pnt.next && p >= pnt.t) {
17095                     pnt = pnt.next;
17096                 }
17097                 pnt = pnt.prev;
17098             } else {
17099                 while (pnt.prev && p <= pnt.t) {
17100                     pnt = pnt.prev;
17101                 }
17102             }
17103             this._prev = pnt;
17104             return (pnt.v + ((p - pnt.t) / pnt.gap) * pnt.c);
17105         };
17106         p.config = function(vars) {
17107             return new RoughEase(vars);
17108         };
17109         RoughEase.ease = new RoughEase();
17110
17111
17112         //Bounce
17113         _wrap("Bounce",
17114             _create("BounceOut", function(p) {
17115                 if (p < 1 / 2.75) {
17116                     return 7.5625 * p * p;
17117                 } else if (p < 2 / 2.75) {
17118                     return 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;
17119                 } else if (p < 2.5 / 2.75) {
17120                     return 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;
17121                 }
17122                 return 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;
17123             }),
17124             _create("BounceIn", function(p) {
17125                 if ((p = 1 - p) < 1 / 2.75) {
17126                     return 1 - (7.5625 * p * p);
17127                 } else if (p < 2 / 2.75) {
17128                     return 1 - (7.5625 * (p -= 1.5 / 2.75) * p + 0.75);
17129                 } else if (p < 2.5 / 2.75) {
17130                     return 1 - (7.5625 * (p -= 2.25 / 2.75) * p + 0.9375);
17131                 }
17132                 return 1 - (7.5625 * (p -= 2.625 / 2.75) * p + 0.984375);
17133             }),
17134             _create("BounceInOut", function(p) {
17135                 var invert = (p < 0.5);
17136                 if (invert) {
17137                     p = 1 - (p * 2);
17138                 } else {
17139                     p = (p * 2) - 1;
17140                 }
17141                 if (p < 1 / 2.75) {
17142                     p = 7.5625 * p * p;
17143                 } else if (p < 2 / 2.75) {
17144                     p = 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;
17145                 } else if (p < 2.5 / 2.75) {
17146                     p = 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;
17147                 } else {
17148                     p = 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;
17149                 }
17150                 return invert ? (1 - p) * 0.5 : p * 0.5 + 0.5;
17151             })
17152         );
17153
17154
17155         //CIRC
17156         _wrap("Circ",
17157             _create("CircOut", function(p) {
17158                 return Math.sqrt(1 - (p = p - 1) * p);
17159             }),
17160             _create("CircIn", function(p) {
17161                 return -(Math.sqrt(1 - (p * p)) - 1);
17162             }),
17163             _create("CircInOut", function(p) {
17164                 return ((p*=2) < 1) ? -0.5 * (Math.sqrt(1 - p * p) - 1) : 0.5 * (Math.sqrt(1 - (p -= 2) * p) + 1);
17165             })
17166         );
17167
17168
17169         //Elastic
17170         _createElastic = function(n, f, def) {
17171             var C = _class("easing." + n, function(amplitude, period) {
17172                     this._p1 = amplitude || 1;
17173                     this._p2 = period || def;
17174                     this._p3 = this._p2 / _2PI * (Math.asin(1 / this._p1) || 0);
17175                 }, true),
17176                 p = C.prototype = new Ease();
17177             p.constructor = C;
17178             p.getRatio = f;
17179             p.config = function(amplitude, period) {
17180                 return new C(amplitude, period);
17181             };
17182             return C;
17183         };
17184         _wrap("Elastic",
17185             _createElastic("ElasticOut", function(p) {
17186                 return this._p1 * Math.pow(2, -10 * p) * Math.sin( (p - this._p3) * _2PI / this._p2 ) + 1;
17187             }, 0.3),
17188             _createElastic("ElasticIn", function(p) {
17189                 return -(this._p1 * Math.pow(2, 10 * (p -= 1)) * Math.sin( (p - this._p3) * _2PI / this._p2 ));
17190             }, 0.3),
17191             _createElastic("ElasticInOut", function(p) {
17192                 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;
17193             }, 0.45)
17194         );
17195
17196
17197         //Expo
17198         _wrap("Expo",
17199             _create("ExpoOut", function(p) {
17200                 return 1 - Math.pow(2, -10 * p);
17201             }),
17202             _create("ExpoIn", function(p) {
17203                 return Math.pow(2, 10 * (p - 1)) - 0.001;
17204             }),
17205             _create("ExpoInOut", function(p) {
17206                 return ((p *= 2) < 1) ? 0.5 * Math.pow(2, 10 * (p - 1)) : 0.5 * (2 - Math.pow(2, -10 * (p - 1)));
17207             })
17208         );
17209
17210
17211         //Sine
17212         _wrap("Sine",
17213             _create("SineOut", function(p) {
17214                 return Math.sin(p * _HALF_PI);
17215             }),
17216             _create("SineIn", function(p) {
17217                 return -Math.cos(p * _HALF_PI) + 1;
17218             }),
17219             _create("SineInOut", function(p) {
17220                 return -0.5 * (Math.cos(Math.PI * p) - 1);
17221             })
17222         );
17223
17224         _class("easing.EaseLookup", {
17225                 find:function(s) {
17226                     return Ease.map[s];
17227                 }
17228             }, true);
17229
17230         //register the non-standard eases
17231         _easeReg(w.SlowMo, "SlowMo", "ease,");
17232         _easeReg(RoughEase, "RoughEase", "ease,");
17233         _easeReg(SteppedEase, "SteppedEase", "ease,");
17234
17235         return Back;
17236         
17237     }, true);
17238
17239
17240 }); 
17241
17242
17243
17244
17245
17246
17247
17248
17249
17250
17251
17252 /*
17253  * ----------------------------------------------------------------
17254  * Base classes like TweenLite, SimpleTimeline, Ease, Ticker, etc.
17255  * ----------------------------------------------------------------
17256  */
17257 (function(window) {
17258
17259         "use strict";
17260         var _globals = window.GreenSockGlobals || window;
17261         if (_globals.TweenLite) {
17262             return; //in case the core set of classes is already loaded, don't instantiate twice.
17263         }
17264         var _namespace = function(ns) {
17265                 var a = ns.split("."),
17266                     p = _globals, i;
17267                 for (i = 0; i < a.length; i++) {
17268                     p[a[i]] = p = p[a[i]] || {};
17269                 }
17270                 return p;
17271             },
17272             gs = _namespace("com.greensock"),
17273             _tinyNum = 0.0000000001,
17274             _slice = [].slice,
17275             _emptyFunc = function() {},
17276             _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)
17277                 var toString = Object.prototype.toString,
17278                     array = toString.call([]);
17279                 return function(obj) {
17280                     return obj != null && (obj instanceof Array || (typeof(obj) === "object" && !!obj.push && toString.call(obj) === array));
17281                 };
17282             }()),
17283             a, i, p, _ticker, _tickerActive,
17284             _defLookup = {},
17285
17286             /**
17287              * @constructor
17288              * Defines a GreenSock class, optionally with an array of dependencies that must be instantiated first and passed into the definition.
17289              * This allows users to load GreenSock JS files in any order even if they have interdependencies (like CSSPlugin extends TweenPlugin which is
17290              * inside TweenLite.js, but if CSSPlugin is loaded first, it should wait to run its code until TweenLite.js loads and instantiates TweenPlugin
17291              * and then pass TweenPlugin to CSSPlugin's definition). This is all done automatically and internally.
17292              *
17293              * Every definition will be added to a "com.greensock" global object (typically window, but if a window.GreenSockGlobals object is found,
17294              * 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,
17295              * it is ALSO referenced at window.TweenLite. However some classes aren't considered global, like the base com.greensock.core.Animation class, so
17296              * those will only be at the package like window.com.greensock.core.Animation. Again, if you define a GreenSockGlobals object on the window, everything
17297              * gets tucked neatly inside there instead of on the window directly. This allows you to do advanced things like load multiple versions of GreenSock
17298              * 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
17299              * sandbox the banner one like:
17300              *
17301              * <script>
17302              *     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.
17303              * </script>
17304              * <script src="js/greensock/v1.7/TweenMax.js"></script>
17305              * <script>
17306              *     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(...)
17307              * </script>
17308              * <script src="js/greensock/v1.6/TweenMax.js"></script>
17309              * <script>
17310              *     gs.TweenLite.to(...); //would use v1.7
17311              *     TweenLite.to(...); //would use v1.6
17312              * </script>
17313              *
17314              * @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".
17315              * @param {!Array.<string>} dependencies An array of dependencies (described as their namespaces minus "com.greensock." prefix). For example ["TweenLite","plugins.TweenPlugin","core.Animation"]
17316              * @param {!function():Object} func The function that should be called and passed the resolved dependencies which will return the actual class for this definition.
17317              * @param {boolean=} global If true, the class will be added to the global scope (typically window unless you define a window.GreenSockGlobals object)
17318              */
17319             Definition = function(ns, dependencies, func, global) {
17320                 this.sc = (_defLookup[ns]) ? _defLookup[ns].sc : []; //subclasses
17321                 _defLookup[ns] = this;
17322                 this.gsClass = null;
17323                 this.func = func;
17324                 var _classes = [];
17325                 this.check = function(init) {
17326                     var i = dependencies.length,
17327                         missing = i,
17328                         cur, a, n, cl;
17329                     while (--i > -1) {
17330                         if ((cur = _defLookup[dependencies[i]] || new Definition(dependencies[i], [])).gsClass) {
17331                             _classes[i] = cur.gsClass;
17332                             missing--;
17333                         } else if (init) {
17334                             cur.sc.push(this);
17335                         }
17336                     }
17337                     if (missing === 0 && func) {
17338                         a = ("com.greensock." + ns).split(".");
17339                         n = a.pop();
17340                         cl = _namespace(a.join("."))[n] = this.gsClass = func.apply(func, _classes);
17341
17342                         //exports to multiple environments
17343                         if (global) {
17344                             _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.)
17345                             if (typeof(define) === "function" && define.amd){ //AMD
17346                                 define((window.GreenSockAMDPath ? window.GreenSockAMDPath + "/" : "") + ns.split(".").join("/"), [], function() { return cl; });
17347                             } else if (typeof(module) !== "undefined" && module.exports){ //node
17348                                 module.exports = cl;
17349                             }
17350                         }
17351                         for (i = 0; i < this.sc.length; i++) {
17352                             this.sc[i].check();
17353                         }
17354                     }
17355                 };
17356                 this.check(true);
17357             },
17358
17359             //used to create Definition instances (which basically registers a class that has dependencies).
17360             _gsDefine = window._gsDefine = function(ns, dependencies, func, global) {
17361                 return new Definition(ns, dependencies, func, global);
17362             },
17363
17364             //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).
17365             _class = gs._class = function(ns, func, global) {
17366                 func = func || function() {};
17367                 _gsDefine(ns, [], function(){ return func; }, global);
17368                 return func;
17369             };
17370
17371         _gsDefine.globals = _globals;
17372
17373
17374
17375 /*
17376  * ----------------------------------------------------------------
17377  * Ease
17378  * ----------------------------------------------------------------
17379  */
17380         var _baseParams = [0, 0, 1, 1],
17381             _blankArray = [],
17382             Ease = _class("easing.Ease", function(func, extraParams, type, power) {
17383                 this._func = func;
17384                 this._type = type || 0;
17385                 this._power = power || 0;
17386                 this._params = extraParams ? _baseParams.concat(extraParams) : _baseParams;
17387             }, true),
17388             _easeMap = Ease.map = {},
17389             _easeReg = Ease.register = function(ease, names, types, create) {
17390                 var na = names.split(","),
17391                     i = na.length,
17392                     ta = (types || "easeIn,easeOut,easeInOut").split(","),
17393                     e, name, j, type;
17394                 while (--i > -1) {
17395                     name = na[i];
17396                     e = create ? _class("easing."+name, null, true) : gs.easing[name] || {};
17397                     j = ta.length;
17398                     while (--j > -1) {
17399                         type = ta[j];
17400                         _easeMap[name + "." + type] = _easeMap[type + name] = e[type] = ease.getRatio ? ease : ease[type] || new ease();
17401                     }
17402                 }
17403             };
17404
17405         p = Ease.prototype;
17406         p._calcEnd = false;
17407         p.getRatio = function(p) {
17408             if (this._func) {
17409                 this._params[0] = p;
17410                 return this._func.apply(null, this._params);
17411             }
17412             var t = this._type,
17413                 pw = this._power,
17414                 r = (t === 1) ? 1 - p : (t === 2) ? p : (p < 0.5) ? p * 2 : (1 - p) * 2;
17415             if (pw === 1) {
17416                 r *= r;
17417             } else if (pw === 2) {
17418                 r *= r * r;
17419             } else if (pw === 3) {
17420                 r *= r * r * r;
17421             } else if (pw === 4) {
17422                 r *= r * r * r * r;
17423             }
17424             return (t === 1) ? 1 - r : (t === 2) ? r : (p < 0.5) ? r / 2 : 1 - (r / 2);
17425         };
17426
17427         //create all the standard eases like Linear, Quad, Cubic, Quart, Quint, Strong, Power0, Power1, Power2, Power3, and Power4 (each with easeIn, easeOut, and easeInOut)
17428         a = ["Linear","Quad","Cubic","Quart","Quint,Strong"];
17429         i = a.length;
17430         while (--i > -1) {
17431             p = a[i]+",Power"+i;
17432             _easeReg(new Ease(null,null,1,i), p, "easeOut", true);
17433             _easeReg(new Ease(null,null,2,i), p, "easeIn" + ((i === 0) ? ",easeNone" : ""));
17434             _easeReg(new Ease(null,null,3,i), p, "easeInOut");
17435         }
17436         _easeMap.linear = gs.easing.Linear.easeIn;
17437         _easeMap.swing = gs.easing.Quad.easeInOut; //for jQuery folks
17438
17439
17440 /*
17441  * ----------------------------------------------------------------
17442  * EventDispatcher
17443  * ----------------------------------------------------------------
17444  */
17445         var EventDispatcher = _class("events.EventDispatcher", function(target) {
17446             this._listeners = {};
17447             this._eventTarget = target || this;
17448         });
17449         p = EventDispatcher.prototype;
17450
17451         p.addEventListener = function(type, callback, scope, useParam, priority) {
17452             priority = priority || 0;
17453             var list = this._listeners[type],
17454                 index = 0,
17455                 listener, i;
17456             if (list == null) {
17457                 this._listeners[type] = list = [];
17458             }
17459             i = list.length;
17460             while (--i > -1) {
17461                 listener = list[i];
17462                 if (listener.c === callback && listener.s === scope) {
17463                     list.splice(i, 1);
17464                 } else if (index === 0 && listener.pr < priority) {
17465                     index = i + 1;
17466                 }
17467             }
17468             list.splice(index, 0, {c:callback, s:scope, up:useParam, pr:priority});
17469             if (this === _ticker && !_tickerActive) {
17470                 _ticker.wake();
17471             }
17472         };
17473
17474         p.removeEventListener = function(type, callback) {
17475             var list = this._listeners[type], i;
17476             if (list) {
17477                 i = list.length;
17478                 while (--i > -1) {
17479                     if (list[i].c === callback) {
17480                         list.splice(i, 1);
17481                         return;
17482                     }
17483                 }
17484             }
17485         };
17486
17487         p.dispatchEvent = function(type) {
17488             var list = this._listeners[type],
17489                 i, t, listener;
17490             if (list) {
17491                 i = list.length;
17492                 t = this._eventTarget;
17493                 while (--i > -1) {
17494                     listener = list[i];
17495                     if (listener.up) {
17496                         listener.c.call(listener.s || t, {type:type, target:t});
17497                     } else {
17498                         listener.c.call(listener.s || t);
17499                     }
17500                 }
17501             }
17502         };
17503
17504
17505 /*
17506  * ----------------------------------------------------------------
17507  * Ticker
17508  * ----------------------------------------------------------------
17509  */
17510         var _reqAnimFrame = window.requestAnimationFrame,
17511             _cancelAnimFrame = window.cancelAnimationFrame,
17512             _getTime = Date.now || function() {return new Date().getTime();},
17513             _lastUpdate = _getTime();
17514
17515         //now try to determine the requestAnimationFrame and cancelAnimationFrame functions and if none are found, we'll use a setTimeout()/clearTimeout() polyfill.
17516         a = ["ms","moz","webkit","o"];
17517         i = a.length;
17518         while (--i > -1 && !_reqAnimFrame) {
17519             _reqAnimFrame = window[a[i] + "RequestAnimationFrame"];
17520             _cancelAnimFrame = window[a[i] + "CancelAnimationFrame"] || window[a[i] + "CancelRequestAnimationFrame"];
17521         }
17522
17523         _class("Ticker", function(fps, useRAF) {
17524             var _self = this,
17525                 _startTime = _getTime(),
17526                 _useRAF = (useRAF !== false && _reqAnimFrame),
17527                 _lagThreshold = 500,
17528                 _adjustedLag = 33,
17529                 _fps, _req, _id, _gap, _nextTime,
17530                 _tick = function(manual) {
17531                     var elapsed = _getTime() - _lastUpdate,
17532                         overlap, dispatch;
17533                     if (elapsed > _lagThreshold) {
17534                         _startTime += elapsed - _adjustedLag;
17535                     }
17536                     _lastUpdate += elapsed;
17537                     _self.time = (_lastUpdate - _startTime) / 1000;
17538                     overlap = _self.time - _nextTime;
17539                     if (!_fps || overlap > 0 || manual === true) {
17540                         _self.frame++;
17541                         _nextTime += overlap + (overlap >= _gap ? 0.004 : _gap - overlap);
17542                         dispatch = true;
17543                     }
17544                     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.
17545                         _id = _req(_tick);
17546                     }
17547                     if (dispatch) {
17548                         _self.dispatchEvent("tick");
17549                     }
17550                 };
17551
17552             EventDispatcher.call(_self);
17553             _self.time = _self.frame = 0;
17554             _self.tick = function() {
17555                 _tick(true);
17556             };
17557
17558             _self.lagSmoothing = function(threshold, adjustedLag) {
17559                 _lagThreshold = threshold || (1 / _tinyNum); //zero should be interpreted as basically unlimited
17560                 _adjustedLag = Math.min(adjustedLag, _lagThreshold, 0);
17561             };
17562
17563             _self.sleep = function() {
17564                 if (_id == null) {
17565                     return;
17566                 }
17567                 if (!_useRAF || !_cancelAnimFrame) {
17568                     clearTimeout(_id);
17569                 } else {
17570                     _cancelAnimFrame(_id);
17571                 }
17572                 _req = _emptyFunc;
17573                 _id = null;
17574                 if (_self === _ticker) {
17575                     _tickerActive = false;
17576                 }
17577             };
17578
17579             _self.wake = function() {
17580                 if (_id !== null) {
17581                     _self.sleep();
17582                 } 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().
17583                     _lastUpdate = _getTime() - _lagThreshold + 5;
17584                 }
17585                 _req = (_fps === 0) ? _emptyFunc : (!_useRAF || !_reqAnimFrame) ? function(f) { return setTimeout(f, ((_nextTime - _self.time) * 1000 + 1) | 0); } : _reqAnimFrame;
17586                 if (_self === _ticker) {
17587                     _tickerActive = true;
17588                 }
17589                 _tick(2);
17590             };
17591
17592             _self.fps = function(value) {
17593                 if (!arguments.length) {
17594                     return _fps;
17595                 }
17596                 _fps = value;
17597                 _gap = 1 / (_fps || 60);
17598                 _nextTime = this.time + _gap;
17599                 _self.wake();
17600             };
17601
17602             _self.useRAF = function(value) {
17603                 if (!arguments.length) {
17604                     return _useRAF;
17605                 }
17606                 _self.sleep();
17607                 _useRAF = value;
17608                 _self.fps(_fps);
17609             };
17610             _self.fps(fps);
17611
17612             //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.
17613             setTimeout(function() {
17614                 if (_useRAF && (!_id || _self.frame < 5)) {
17615                     _self.useRAF(false);
17616                 }
17617             }, 1500);
17618         });
17619
17620         p = gs.Ticker.prototype = new gs.events.EventDispatcher();
17621         p.constructor = gs.Ticker;
17622
17623
17624 /*
17625  * ----------------------------------------------------------------
17626  * Animation
17627  * ----------------------------------------------------------------
17628  */
17629         var Animation = _class("core.Animation", function(duration, vars) {
17630                 this.vars = vars = vars || {};
17631                 this._duration = this._totalDuration = duration || 0;
17632                 this._delay = Number(vars.delay) || 0;
17633                 this._timeScale = 1;
17634                 this._active = (vars.immediateRender === true);
17635                 this.data = vars.data;
17636                 this._reversed = (vars.reversed === true);
17637
17638                 if (!_rootTimeline) {
17639                     return;
17640                 }
17641                 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.
17642                     _ticker.wake();
17643                 }
17644
17645                 var tl = this.vars.useFrames ? _rootFramesTimeline : _rootTimeline;
17646                 tl.add(this, tl._time);
17647
17648                 if (this.vars.paused) {
17649                     this.paused(true);
17650                 }
17651             });
17652
17653         _ticker = Animation.ticker = new gs.Ticker();
17654         p = Animation.prototype;
17655         p._dirty = p._gc = p._initted = p._paused = false;
17656         p._totalTime = p._time = 0;
17657         p._rawPrevTime = -1;
17658         p._next = p._last = p._onUpdate = p._timeline = p.timeline = null;
17659         p._paused = false;
17660
17661
17662         //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.
17663         var _checkTimeout = function() {
17664                 if (_tickerActive && _getTime() - _lastUpdate > 2000) {
17665                     _ticker.wake();
17666                 }
17667                 setTimeout(_checkTimeout, 2000);
17668             };
17669         _checkTimeout();
17670
17671
17672         p.play = function(from, suppressEvents) {
17673             if (from != null) {
17674                 this.seek(from, suppressEvents);
17675             }
17676             return this.reversed(false).paused(false);
17677         };
17678
17679         p.pause = function(atTime, suppressEvents) {
17680             if (atTime != null) {
17681                 this.seek(atTime, suppressEvents);
17682             }
17683             return this.paused(true);
17684         };
17685
17686         p.resume = function(from, suppressEvents) {
17687             if (from != null) {
17688                 this.seek(from, suppressEvents);
17689             }
17690             return this.paused(false);
17691         };
17692
17693         p.seek = function(time, suppressEvents) {
17694             return this.totalTime(Number(time), suppressEvents !== false);
17695         };
17696
17697         p.restart = function(includeDelay, suppressEvents) {
17698             return this.reversed(false).paused(false).totalTime(includeDelay ? -this._delay : 0, (suppressEvents !== false), true);
17699         };
17700
17701         p.reverse = function(from, suppressEvents) {
17702             if (from != null) {
17703                 this.seek((from || this.totalDuration()), suppressEvents);
17704             }
17705             return this.reversed(true).paused(false);
17706         };
17707
17708         p.render = function(time, suppressEvents, force) {
17709             //stub - we override this method in subclasses.
17710         };
17711
17712         p.invalidate = function() {
17713             return this;
17714         };
17715
17716         p.isActive = function() {
17717             var tl = this._timeline, //the 2 root timelines won't have a _timeline; they're always active.
17718                 startTime = this._startTime,
17719                 rawTime;
17720             return (!tl || (!this._gc && !this._paused && tl.isActive() && (rawTime = tl.rawTime()) >= startTime && rawTime < startTime + this.totalDuration() / this._timeScale));
17721         };
17722
17723         p._enabled = function (enabled, ignoreTimeline) {
17724             if (!_tickerActive) {
17725                 _ticker.wake();
17726             }
17727             this._gc = !enabled;
17728             this._active = this.isActive();
17729             if (ignoreTimeline !== true) {
17730                 if (enabled && !this.timeline) {
17731                     this._timeline.add(this, this._startTime - this._delay);
17732                 } else if (!enabled && this.timeline) {
17733                     this._timeline._remove(this, true);
17734                 }
17735             }
17736             return false;
17737         };
17738
17739
17740         p._kill = function(vars, target) {
17741             return this._enabled(false, false);
17742         };
17743
17744         p.kill = function(vars, target) {
17745             this._kill(vars, target);
17746             return this;
17747         };
17748
17749         p._uncache = function(includeSelf) {
17750             var tween = includeSelf ? this : this.timeline;
17751             while (tween) {
17752                 tween._dirty = true;
17753                 tween = tween.timeline;
17754             }
17755             return this;
17756         };
17757
17758         p._swapSelfInParams = function(params) {
17759             var i = params.length,
17760                 copy = params.concat();
17761             while (--i > -1) {
17762                 if (params[i] === "{self}") {
17763                     copy[i] = this;
17764                 }
17765             }
17766             return copy;
17767         };
17768
17769 //----Animation getters/setters --------------------------------------------------------
17770
17771         p.eventCallback = function(type, callback, params, scope) {
17772             if ((type || "").substr(0,2) === "on") {
17773                 var v = this.vars;
17774                 if (arguments.length === 1) {
17775                     return v[type];
17776                 }
17777                 if (callback == null) {
17778                     delete v[type];
17779                 } else {
17780                     v[type] = callback;
17781                     v[type + "Params"] = (_isArray(params) && params.join("").indexOf("{self}") !== -1) ? this._swapSelfInParams(params) : params;
17782                     v[type + "Scope"] = scope;
17783                 }
17784                 if (type === "onUpdate") {
17785                     this._onUpdate = callback;
17786                 }
17787             }
17788             return this;
17789         };
17790
17791         p.delay = function(value) {
17792             if (!arguments.length) {
17793                 return this._delay;
17794             }
17795             if (this._timeline.smoothChildTiming) {
17796                 this.startTime( this._startTime + value - this._delay );
17797             }
17798             this._delay = value;
17799             return this;
17800         };
17801
17802         p.duration = function(value) {
17803             if (!arguments.length) {
17804                 this._dirty = false;
17805                 return this._duration;
17806             }
17807             this._duration = this._totalDuration = value;
17808             this._uncache(true); //true in case it's a TweenMax or TimelineMax that has a repeat - we'll need to refresh the totalDuration.
17809             if (this._timeline.smoothChildTiming) if (this._time > 0) if (this._time < this._duration) if (value !== 0) {
17810                 this.totalTime(this._totalTime * (value / this._duration), true);
17811             }
17812             return this;
17813         };
17814
17815         p.totalDuration = function(value) {
17816             this._dirty = false;
17817             return (!arguments.length) ? this._totalDuration : this.duration(value);
17818         };
17819
17820         p.time = function(value, suppressEvents) {
17821             if (!arguments.length) {
17822                 return this._time;
17823             }
17824             if (this._dirty) {
17825                 this.totalDuration();
17826             }
17827             return this.totalTime((value > this._duration) ? this._duration : value, suppressEvents);
17828         };
17829
17830         p.totalTime = function(time, suppressEvents, uncapped) {
17831             if (!_tickerActive) {
17832                 _ticker.wake();
17833             }
17834             if (!arguments.length) {
17835                 return this._totalTime;
17836             }
17837             if (this._timeline) {
17838                 if (time < 0 && !uncapped) {
17839                     time += this.totalDuration();
17840                 }
17841                 if (this._timeline.smoothChildTiming) {
17842                     if (this._dirty) {
17843                         this.totalDuration();
17844                     }
17845                     var totalDuration = this._totalDuration,
17846                         tl = this._timeline;
17847                     if (time > totalDuration && !uncapped) {
17848                         time = totalDuration;
17849                     }
17850                     this._startTime = (this._paused ? this._pauseTime : tl._time) - ((!this._reversed ? time : totalDuration - time) / this._timeScale);
17851                     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.
17852                         this._uncache(false);
17853                     }
17854                     //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.
17855                     if (tl._timeline) {
17856                         while (tl._timeline) {
17857                             if (tl._timeline._time !== (tl._startTime + tl._totalTime) / tl._timeScale) {
17858                                 tl.totalTime(tl._totalTime, true);
17859                             }
17860                             tl = tl._timeline;
17861                         }
17862                     }
17863                 }
17864                 if (this._gc) {
17865                     this._enabled(true, false);
17866                 }
17867                 if (this._totalTime !== time || this._duration === 0) {
17868                     this.render(time, suppressEvents, false);
17869                     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.
17870                         _lazyRender();
17871                     }
17872                 }
17873             }
17874             return this;
17875         };
17876
17877         p.progress = p.totalProgress = function(value, suppressEvents) {
17878             return (!arguments.length) ? this._time / this.duration() : this.totalTime(this.duration() * value, suppressEvents);
17879         };
17880
17881         p.startTime = function(value) {
17882             if (!arguments.length) {
17883                 return this._startTime;
17884             }
17885             if (value !== this._startTime) {
17886                 this._startTime = value;
17887                 if (this.timeline) if (this.timeline._sortChildren) {
17888                     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.
17889                 }
17890             }
17891             return this;
17892         };
17893
17894         p.timeScale = function(value) {
17895             if (!arguments.length) {
17896                 return this._timeScale;
17897             }
17898             value = value || _tinyNum; //can't allow zero because it'll throw the math off
17899             if (this._timeline && this._timeline.smoothChildTiming) {
17900                 var pauseTime = this._pauseTime,
17901                     t = (pauseTime || pauseTime === 0) ? pauseTime : this._timeline.totalTime();
17902                 this._startTime = t - ((t - this._startTime) * this._timeScale / value);
17903             }
17904             this._timeScale = value;
17905             return this._uncache(false);
17906         };
17907
17908         p.reversed = function(value) {
17909             if (!arguments.length) {
17910                 return this._reversed;
17911             }
17912             if (value != this._reversed) {
17913                 this._reversed = value;
17914                 this.totalTime(((this._timeline && !this._timeline.smoothChildTiming) ? this.totalDuration() - this._totalTime : this._totalTime), true);
17915             }
17916             return this;
17917         };
17918
17919         p.paused = function(value) {
17920             if (!arguments.length) {
17921                 return this._paused;
17922             }
17923             if (value != this._paused) if (this._timeline) {
17924                 if (!_tickerActive && !value) {
17925                     _ticker.wake();
17926                 }
17927                 var tl = this._timeline,
17928                     raw = tl.rawTime(),
17929                     elapsed = raw - this._pauseTime;
17930                 if (!value && tl.smoothChildTiming) {
17931                     this._startTime += elapsed;
17932                     this._uncache(false);
17933                 }
17934                 this._pauseTime = value ? raw : null;
17935                 this._paused = value;
17936                 this._active = this.isActive();
17937                 if (!value && elapsed !== 0 && this._initted && this.duration()) {
17938                     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.
17939                 }
17940             }
17941             if (this._gc && !value) {
17942                 this._enabled(true, false);
17943             }
17944             return this;
17945         };
17946
17947
17948 /*
17949  * ----------------------------------------------------------------
17950  * SimpleTimeline
17951  * ----------------------------------------------------------------
17952  */
17953         var SimpleTimeline = _class("core.SimpleTimeline", function(vars) {
17954             Animation.call(this, 0, vars);
17955             this.autoRemoveChildren = this.smoothChildTiming = true;
17956         });
17957
17958         p = SimpleTimeline.prototype = new Animation();
17959         p.constructor = SimpleTimeline;
17960         p.kill()._gc = false;
17961         p._first = p._last = null;
17962         p._sortChildren = false;
17963
17964         p.add = p.insert = function(child, position, align, stagger) {
17965             var prevTween, st;
17966             child._startTime = Number(position || 0) + child._delay;
17967             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).
17968                 child._pauseTime = child._startTime + ((this.rawTime() - child._startTime) / child._timeScale);
17969             }
17970             if (child.timeline) {
17971                 child.timeline._remove(child, true); //removes from existing timeline so that it can be properly added to this one.
17972             }
17973             child.timeline = child._timeline = this;
17974             if (child._gc) {
17975                 child._enabled(true, true);
17976             }
17977             prevTween = this._last;
17978             if (this._sortChildren) {
17979                 st = child._startTime;
17980                 while (prevTween && prevTween._startTime > st) {
17981                     prevTween = prevTween._prev;
17982                 }
17983             }
17984             if (prevTween) {
17985                 child._next = prevTween._next;
17986                 prevTween._next = child;
17987             } else {
17988                 child._next = this._first;
17989                 this._first = child;
17990             }
17991             if (child._next) {
17992                 child._next._prev = child;
17993             } else {
17994                 this._last = child;
17995             }
17996             child._prev = prevTween;
17997             if (this._timeline) {
17998                 this._uncache(true);
17999             }
18000             return this;
18001         };
18002
18003         p._remove = function(tween, skipDisable) {
18004             if (tween.timeline === this) {
18005                 if (!skipDisable) {
18006                     tween._enabled(false, true);
18007                 }
18008                 tween.timeline = null;
18009
18010                 if (tween._prev) {
18011                     tween._prev._next = tween._next;
18012                 } else if (this._first === tween) {
18013                     this._first = tween._next;
18014                 }
18015                 if (tween._next) {
18016                     tween._next._prev = tween._prev;
18017                 } else if (this._last === tween) {
18018                     this._last = tween._prev;
18019                 }
18020
18021                 if (this._timeline) {
18022                     this._uncache(true);
18023                 }
18024             }
18025             return this;
18026         };
18027
18028         p.render = function(time, suppressEvents, force) {
18029             var tween = this._first,
18030                 next;
18031             this._totalTime = this._time = this._rawPrevTime = time;
18032             while (tween) {
18033                 next = tween._next; //record it here because the value could change after rendering...
18034                 if (tween._active || (time >= tween._startTime && !tween._paused)) {
18035                     if (!tween._reversed) {
18036                         tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
18037                     } else {
18038                         tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
18039                     }
18040                 }
18041                 tween = next;
18042             }
18043         };
18044
18045         p.rawTime = function() {
18046             if (!_tickerActive) {
18047                 _ticker.wake();
18048             }
18049             return this._totalTime;
18050         };
18051
18052 /*
18053  * ----------------------------------------------------------------
18054  * TweenLite
18055  * ----------------------------------------------------------------
18056  */
18057         var TweenLite = _class("TweenLite", function(target, duration, vars) {
18058                 Animation.call(this, duration, vars);
18059                 this.render = TweenLite.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method)
18060
18061                 if (target == null) {
18062                     throw "Cannot tween a null target.";
18063                 }
18064
18065                 this.target = target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;
18066
18067                 var isSelector = (target.jquery || (target.length && target !== window && target[0] && (target[0] === window || (target[0].nodeType && target[0].style && !target.nodeType)))),
18068                     overwrite = this.vars.overwrite,
18069                     i, targ, targets;
18070
18071                 this._overwrite = overwrite = (overwrite == null) ? _overwriteLookup[TweenLite.defaultOverwrite] : (typeof(overwrite) === "number") ? overwrite >> 0 : _overwriteLookup[overwrite];
18072
18073                 if ((isSelector || target instanceof Array || (target.push && _isArray(target))) && typeof(target[0]) !== "number") {
18074                     this._targets = targets = _slice.call(target, 0);
18075                     this._propLookup = [];
18076                     this._siblings = [];
18077                     for (i = 0; i < targets.length; i++) {
18078                         targ = targets[i];
18079                         if (!targ) {
18080                             targets.splice(i--, 1);
18081                             continue;
18082                         } else if (typeof(targ) === "string") {
18083                             targ = targets[i--] = TweenLite.selector(targ); //in case it's an array of strings
18084                             if (typeof(targ) === "string") {
18085                                 targets.splice(i+1, 1); //to avoid an endless loop (can't imagine why the selector would return a string, but just in case)
18086                             }
18087                             continue;
18088                         } 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.
18089                             targets.splice(i--, 1);
18090                             this._targets = targets = targets.concat(_slice.call(targ, 0));
18091                             continue;
18092                         }
18093                         this._siblings[i] = _register(targ, this, false);
18094                         if (overwrite === 1) if (this._siblings[i].length > 1) {
18095                             _applyOverwrite(targ, this, null, 1, this._siblings[i]);
18096                         }
18097                     }
18098
18099                 } else {
18100                     this._propLookup = {};
18101                     this._siblings = _register(target, this, false);
18102                     if (overwrite === 1) if (this._siblings.length > 1) {
18103                         _applyOverwrite(target, this, null, 1, this._siblings);
18104                     }
18105                 }
18106                 if (this.vars.immediateRender || (duration === 0 && this._delay === 0 && this.vars.immediateRender !== false)) {
18107                     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)
18108                     this.render(-this._delay);
18109                 }
18110             }, true),
18111             _isSelector = function(v) {
18112                 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.
18113             },
18114             _autoCSS = function(vars, target) {
18115                 var css = {},
18116                     p;
18117                 for (p in vars) {
18118                     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.
18119                         css[p] = vars[p];
18120                         delete vars[p];
18121                     }
18122                 }
18123                 vars.css = css;
18124             };
18125
18126         p = TweenLite.prototype = new Animation();
18127         p.constructor = TweenLite;
18128         p.kill()._gc = false;
18129
18130 //----TweenLite defaults, overwrite management, and root updates ----------------------------------------------------
18131
18132         p.ratio = 0;
18133         p._firstPT = p._targets = p._overwrittenProps = p._startAt = null;
18134         p._notifyPluginsOfEnabled = p._lazy = false;
18135
18136         TweenLite.version = "1.12.1";
18137         TweenLite.defaultEase = p._ease = new Ease(null, null, 1, 1);
18138         TweenLite.defaultOverwrite = "auto";
18139         TweenLite.ticker = _ticker;
18140         TweenLite.autoSleep = true;
18141         TweenLite.lagSmoothing = function(threshold, adjustedLag) {
18142             _ticker.lagSmoothing(threshold, adjustedLag);
18143         };
18144         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; };
18145
18146         var _lazyTweens = [],
18147             _lazyLookup = {},
18148             _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.
18149             _plugins = TweenLite._plugins = {},
18150             _tweenLookup = _internals.tweenLookup = {},
18151             _tweenLookupNum = 0,
18152             _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},
18153             _overwriteLookup = {none:0, all:1, auto:2, concurrent:3, allOnStart:4, preexisting:5, "true":1, "false":0},
18154             _rootFramesTimeline = Animation._rootFramesTimeline = new SimpleTimeline(),
18155             _rootTimeline = Animation._rootTimeline = new SimpleTimeline(),
18156             _lazyRender = function() {
18157                 var i = _lazyTweens.length;
18158                 _lazyLookup = {};
18159                 while (--i > -1) {
18160                     a = _lazyTweens[i];
18161                     if (a && a._lazy !== false) {
18162                         a.render(a._lazy, false, true);
18163                         a._lazy = false;
18164                     }
18165                 }
18166                 _lazyTweens.length = 0;
18167             };
18168
18169         _rootTimeline._startTime = _ticker.time;
18170         _rootFramesTimeline._startTime = _ticker.frame;
18171         _rootTimeline._active = _rootFramesTimeline._active = true;
18172         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".
18173
18174         Animation._updateRoot = TweenLite.render = function() {
18175                 var i, a, p;
18176                 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.
18177                     _lazyRender();
18178                 }
18179                 _rootTimeline.render((_ticker.time - _rootTimeline._startTime) * _rootTimeline._timeScale, false, false);
18180                 _rootFramesTimeline.render((_ticker.frame - _rootFramesTimeline._startTime) * _rootFramesTimeline._timeScale, false, false);
18181                 if (_lazyTweens.length) {
18182                     _lazyRender();
18183                 }
18184                 if (!(_ticker.frame % 120)) { //dump garbage every 120 frames...
18185                     for (p in _tweenLookup) {
18186                         a = _tweenLookup[p].tweens;
18187                         i = a.length;
18188                         while (--i > -1) {
18189                             if (a[i]._gc) {
18190                                 a.splice(i, 1);
18191                             }
18192                         }
18193                         if (a.length === 0) {
18194                             delete _tweenLookup[p];
18195                         }
18196                     }
18197                     //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
18198                     p = _rootTimeline._first;
18199                     if (!p || p._paused) if (TweenLite.autoSleep && !_rootFramesTimeline._first && _ticker._listeners.tick.length === 1) {
18200                         while (p && p._paused) {
18201                             p = p._next;
18202                         }
18203                         if (!p) {
18204                             _ticker.sleep();
18205                         }
18206                     }
18207                 }
18208             };
18209
18210         _ticker.addEventListener("tick", Animation._updateRoot);
18211
18212         var _register = function(target, tween, scrub) {
18213                 var id = target._gsTweenID, a, i;
18214                 if (!_tweenLookup[id || (target._gsTweenID = id = "t" + (_tweenLookupNum++))]) {
18215                     _tweenLookup[id] = {target:target, tweens:[]};
18216                 }
18217                 if (tween) {
18218                     a = _tweenLookup[id].tweens;
18219                     a[(i = a.length)] = tween;
18220                     if (scrub) {
18221                         while (--i > -1) {
18222                             if (a[i] === tween) {
18223                                 a.splice(i, 1);
18224                             }
18225                         }
18226                     }
18227                 }
18228                 return _tweenLookup[id].tweens;
18229             },
18230
18231             _applyOverwrite = function(target, tween, props, mode, siblings) {
18232                 var i, changed, curTween, l;
18233                 if (mode === 1 || mode >= 4) {
18234                     l = siblings.length;
18235                     for (i = 0; i < l; i++) {
18236                         if ((curTween = siblings[i]) !== tween) {
18237                             if (!curTween._gc) if (curTween._enabled(false, false)) {
18238                                 changed = true;
18239                             }
18240                         } else if (mode === 5) {
18241                             break;
18242                         }
18243                     }
18244                     return changed;
18245                 }
18246                 //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)
18247                 var startTime = tween._startTime + _tinyNum,
18248                     overlaps = [],
18249                     oCount = 0,
18250                     zeroDur = (tween._duration === 0),
18251                     globalStart;
18252                 i = siblings.length;
18253                 while (--i > -1) {
18254                     if ((curTween = siblings[i]) === tween || curTween._gc || curTween._paused) {
18255                         //ignore
18256                     } else if (curTween._timeline !== tween._timeline) {
18257                         globalStart = globalStart || _checkOverlap(tween, 0, zeroDur);
18258                         if (_checkOverlap(curTween, globalStart, zeroDur) === 0) {
18259                             overlaps[oCount++] = curTween;
18260                         }
18261                     } else if (curTween._startTime <= startTime) if (curTween._startTime + curTween.totalDuration() / curTween._timeScale > startTime) if (!((zeroDur || !curTween._initted) && startTime - curTween._startTime <= 0.0000000002)) {
18262                         overlaps[oCount++] = curTween;
18263                     }
18264                 }
18265
18266                 i = oCount;
18267                 while (--i > -1) {
18268                     curTween = overlaps[i];
18269                     if (mode === 2) if (curTween._kill(props, target)) {
18270                         changed = true;
18271                     }
18272                     if (mode !== 2 || (!curTween._firstPT && curTween._initted)) {
18273                         if (curTween._enabled(false, false)) { //if all property tweens have been overwritten, kill the tween.
18274                             changed = true;
18275                         }
18276                     }
18277                 }
18278                 return changed;
18279             },
18280
18281             _checkOverlap = function(tween, reference, zeroDur) {
18282                 var tl = tween._timeline,
18283                     ts = tl._timeScale,
18284                     t = tween._startTime;
18285                 while (tl._timeline) {
18286                     t += tl._startTime;
18287                     ts *= tl._timeScale;
18288                     if (tl._paused) {
18289                         return -100;
18290                     }
18291                     tl = tl._timeline;
18292                 }
18293                 t /= ts;
18294                 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;
18295             };
18296
18297
18298 //---- TweenLite instance methods -----------------------------------------------------------------------------
18299
18300         p._init = function() {
18301             var v = this.vars,
18302                 op = this._overwrittenProps,
18303                 dur = this._duration,
18304                 immediate = !!v.immediateRender,
18305                 ease = v.ease,
18306                 i, initPlugins, pt, p, startVars;
18307             if (v.startAt) {
18308                 if (this._startAt) {
18309                     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.
18310                     this._startAt.kill();
18311                 }
18312                 startVars = {};
18313                 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);
18314                     startVars[p] = v.startAt[p];
18315                 }
18316                 startVars.overwrite = false;
18317                 startVars.immediateRender = true;
18318                 startVars.lazy = (immediate && v.lazy !== false);
18319                 startVars.startAt = startVars.delay = null; //no nesting of startAt objects allowed (otherwise it could cause an infinite loop).
18320                 this._startAt = TweenLite.to(this.target, 0, startVars);
18321                 if (immediate) {
18322                     if (this._time > 0) {
18323                         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()).
18324                     } else if (dur !== 0) {
18325                         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.
18326                     }
18327                 }
18328             } else if (v.runBackwards && dur !== 0) {
18329                 //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)
18330                 if (this._startAt) {
18331                     this._startAt.render(-1, true);
18332                     this._startAt.kill();
18333                     this._startAt = null;
18334                 } else {
18335                     pt = {};
18336                     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.
18337                         if (!_reservedProps[p] || p === "autoCSS") {
18338                             pt[p] = v[p];
18339                         }
18340                     }
18341                     pt.overwrite = 0;
18342                     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.
18343                     pt.lazy = (immediate && v.lazy !== false);
18344                     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)
18345                     this._startAt = TweenLite.to(this.target, 0, pt);
18346                     if (!immediate) {
18347                         this._startAt._init(); //ensures that the initial values are recorded
18348                         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.
18349                     } else if (this._time === 0) {
18350                         return;
18351                     }
18352                 }
18353             }
18354             if (!ease) {
18355                 this._ease = TweenLite.defaultEase;
18356             } else if (ease instanceof Ease) {
18357                 this._ease = (v.easeParams instanceof Array) ? ease.config.apply(ease, v.easeParams) : ease;
18358             } else {
18359                 this._ease = (typeof(ease) === "function") ? new Ease(ease, v.easeParams) : _easeMap[ease] || TweenLite.defaultEase;
18360             }
18361             this._easeType = this._ease._type;
18362             this._easePower = this._ease._power;
18363             this._firstPT = null;
18364
18365             if (this._targets) {
18366                 i = this._targets.length;
18367                 while (--i > -1) {
18368                     if ( this._initProps( this._targets[i], (this._propLookup[i] = {}), this._siblings[i], (op ? op[i] : null)) ) {
18369                         initPlugins = true;
18370                     }
18371                 }
18372             } else {
18373                 initPlugins = this._initProps(this.target, this._propLookup, this._siblings, op);
18374             }
18375
18376             if (initPlugins) {
18377                 TweenLite._onPluginEvent("_onInitAllProps", this); //reorders the array in order of priority. Uses a static TweenPlugin method in order to minimize file size in TweenLite
18378             }
18379             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.
18380                 this._enabled(false, false);
18381             }
18382             if (v.runBackwards) {
18383                 pt = this._firstPT;
18384                 while (pt) {
18385                     pt.s += pt.c;
18386                     pt.c = -pt.c;
18387                     pt = pt._next;
18388                 }
18389             }
18390             this._onUpdate = v.onUpdate;
18391             this._initted = true;
18392         };
18393
18394         p._initProps = function(target, propLookup, siblings, overwrittenProps) {
18395             var p, i, initPlugins, plugin, pt, v;
18396             if (target == null) {
18397                 return false;
18398             }
18399
18400             if (_lazyLookup[target._gsTweenID]) {
18401                 _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)
18402             }
18403
18404             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.
18405                 _autoCSS(this.vars, target);
18406             }
18407             for (p in this.vars) {
18408                 v = this.vars[p];
18409                 if (_reservedProps[p]) {
18410                     if (v) if ((v instanceof Array) || (v.push && _isArray(v))) if (v.join("").indexOf("{self}") !== -1) {
18411                         this.vars[p] = v = this._swapSelfInParams(v, this);
18412                     }
18413
18414                 } else if (_plugins[p] && (plugin = new _plugins[p]())._onInitTween(target, this.vars[p], this)) {
18415
18416                     //t - target        [object]
18417                     //p - property      [string]
18418                     //s - start         [number]
18419                     //c - change        [number]
18420                     //f - isFunction    [boolean]
18421                     //n - name          [string]
18422                     //pg - isPlugin     [boolean]
18423                     //pr - priority     [number]
18424                     this._firstPT = pt = {_next:this._firstPT, t:plugin, p:"setRatio", s:0, c:1, f:true, n:p, pg:true, pr:plugin._priority};
18425                     i = plugin._overwriteProps.length;
18426                     while (--i > -1) {
18427                         propLookup[plugin._overwriteProps[i]] = this._firstPT;
18428                     }
18429                     if (plugin._priority || plugin._onInitAllProps) {
18430                         initPlugins = true;
18431                     }
18432                     if (plugin._onDisable || plugin._onEnable) {
18433                         this._notifyPluginsOfEnabled = true;
18434                     }
18435
18436                 } else {
18437                     this._firstPT = propLookup[p] = pt = {_next:this._firstPT, t:target, p:p, f:(typeof(target[p]) === "function"), n:p, pg:false, pr:0};
18438                     pt.s = (!pt.f) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();
18439                     pt.c = (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) : (Number(v) - pt.s) || 0;
18440                 }
18441                 if (pt) if (pt._next) {
18442                     pt._next._prev = pt;
18443                 }
18444             }
18445
18446             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)
18447                 return this._initProps(target, propLookup, siblings, overwrittenProps);
18448             }
18449             if (this._overwrite > 1) if (this._firstPT) if (siblings.length > 1) if (_applyOverwrite(target, this, propLookup, this._overwrite, siblings)) {
18450                 this._kill(propLookup, target);
18451                 return this._initProps(target, propLookup, siblings, overwrittenProps);
18452             }
18453             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.
18454                 _lazyLookup[target._gsTweenID] = true;
18455             }
18456             return initPlugins;
18457         };
18458
18459         p.render = function(time, suppressEvents, force) {
18460             var prevTime = this._time,
18461                 duration = this._duration,
18462                 prevRawPrevTime = this._rawPrevTime,
18463                 isComplete, callback, pt, rawPrevTime;
18464             if (time >= duration) {
18465                 this._totalTime = this._time = duration;
18466                 this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1;
18467                 if (!this._reversed ) {
18468                     isComplete = true;
18469                     callback = "onComplete";
18470                 }
18471                 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.
18472                     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.
18473                         time = 0;
18474                     }
18475                     if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time) {
18476                         force = true;
18477                         if (prevRawPrevTime > _tinyNum) {
18478                             callback = "onReverseComplete";
18479                         }
18480                     }
18481                     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.
18482                 }
18483
18484             } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
18485                 this._totalTime = this._time = 0;
18486                 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
18487                 if (prevTime !== 0 || (duration === 0 && prevRawPrevTime > 0 && prevRawPrevTime !== _tinyNum)) {
18488                     callback = "onReverseComplete";
18489                     isComplete = this._reversed;
18490                 }
18491                 if (time < 0) {
18492                     this._active = false;
18493                     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.
18494                         if (prevRawPrevTime >= 0) {
18495                             force = true;
18496                         }
18497                         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.
18498                     }
18499                 } 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.
18500                     force = true;
18501                 }
18502             } else {
18503                 this._totalTime = this._time = time;
18504
18505                 if (this._easeType) {
18506                     var r = time / duration, type = this._easeType, pow = this._easePower;
18507                     if (type === 1 || (type === 3 && r >= 0.5)) {
18508                         r = 1 - r;
18509                     }
18510                     if (type === 3) {
18511                         r *= 2;
18512                     }
18513                     if (pow === 1) {
18514                         r *= r;
18515                     } else if (pow === 2) {
18516                         r *= r * r;
18517                     } else if (pow === 3) {
18518                         r *= r * r * r;
18519                     } else if (pow === 4) {
18520                         r *= r * r * r * r;
18521                     }
18522
18523                     if (type === 1) {
18524                         this.ratio = 1 - r;
18525                     } else if (type === 2) {
18526                         this.ratio = r;
18527                     } else if (time / duration < 0.5) {
18528                         this.ratio = r / 2;
18529                     } else {
18530                         this.ratio = 1 - (r / 2);
18531                     }
18532
18533                 } else {
18534                     this.ratio = this._ease.getRatio(time / duration);
18535                 }
18536             }
18537
18538             if (this._time === prevTime && !force) {
18539                 return;
18540             } else if (!this._initted) {
18541                 this._init();
18542                 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.
18543                     return;
18544                 } else if (!force && this._firstPT && ((this.vars.lazy !== false && this._duration) || (this.vars.lazy && !this._duration))) {
18545                     this._time = this._totalTime = prevTime;
18546                     this._rawPrevTime = prevRawPrevTime;
18547                     _lazyTweens.push(this);
18548                     this._lazy = time;
18549                     return;
18550                 }
18551                 //_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.
18552                 if (this._time && !isComplete) {
18553                     this.ratio = this._ease.getRatio(this._time / duration);
18554                 } else if (isComplete && this._ease._calcEnd) {
18555                     this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1);
18556                 }
18557             }
18558             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.
18559                 this._lazy = false;
18560             }
18561             if (!this._active) if (!this._paused && this._time !== prevTime && time >= 0) {
18562                 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.
18563             }
18564             if (prevTime === 0) {
18565                 if (this._startAt) {
18566                     if (time >= 0) {
18567                         this._startAt.render(time, suppressEvents, force);
18568                     } else if (!callback) {
18569                         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.
18570                     }
18571                 }
18572                 if (this.vars.onStart) if (this._time !== 0 || duration === 0) if (!suppressEvents) {
18573                     this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
18574                 }
18575             }
18576
18577             pt = this._firstPT;
18578             while (pt) {
18579                 if (pt.f) {
18580                     pt.t[pt.p](pt.c * this.ratio + pt.s);
18581                 } else {
18582                     pt.t[pt.p] = pt.c * this.ratio + pt.s;
18583                 }
18584                 pt = pt._next;
18585             }
18586
18587             if (this._onUpdate) {
18588                 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.
18589                     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.
18590                 }
18591                 if (!suppressEvents) if (this._time !== prevTime || isComplete) {
18592                     this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
18593                 }
18594             }
18595
18596             if (callback) if (!this._gc) { //check _gc because there's a chance that kill() could be called in an onUpdate
18597                 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.
18598                     this._startAt.render(time, suppressEvents, force);
18599                 }
18600                 if (isComplete) {
18601                     if (this._timeline.autoRemoveChildren) {
18602                         this._enabled(false, false);
18603                     }
18604                     this._active = false;
18605                 }
18606                 if (!suppressEvents && this.vars[callback]) {
18607                     this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
18608                 }
18609                 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.
18610                     this._rawPrevTime = 0;
18611                 }
18612             }
18613
18614         };
18615
18616         p._kill = function(vars, target) {
18617             if (vars === "all") {
18618                 vars = null;
18619             }
18620             if (vars == null) if (target == null || target === this.target) {
18621                 this._lazy = false;
18622                 return this._enabled(false, false);
18623             }
18624             target = (typeof(target) !== "string") ? (target || this._targets || this.target) : TweenLite.selector(target) || target;
18625             var i, overwrittenProps, p, pt, propLookup, changed, killProps, record;
18626             if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") {
18627                 i = target.length;
18628                 while (--i > -1) {
18629                     if (this._kill(vars, target[i])) {
18630                         changed = true;
18631                     }
18632                 }
18633             } else {
18634                 if (this._targets) {
18635                     i = this._targets.length;
18636                     while (--i > -1) {
18637                         if (target === this._targets[i]) {
18638                             propLookup = this._propLookup[i] || {};
18639                             this._overwrittenProps = this._overwrittenProps || [];
18640                             overwrittenProps = this._overwrittenProps[i] = vars ? this._overwrittenProps[i] || {} : "all";
18641                             break;
18642                         }
18643                     }
18644                 } else if (target !== this.target) {
18645                     return false;
18646                 } else {
18647                     propLookup = this._propLookup;
18648                     overwrittenProps = this._overwrittenProps = vars ? this._overwrittenProps || {} : "all";
18649                 }
18650
18651                 if (propLookup) {
18652                     killProps = vars || propLookup;
18653                     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)
18654                     for (p in killProps) {
18655                         if ((pt = propLookup[p])) {
18656                             if (pt.pg && pt.t._kill(killProps)) {
18657                                 changed = true; //some plugins need to be notified so they can perform cleanup tasks first
18658                             }
18659                             if (!pt.pg || pt.t._overwriteProps.length === 0) {
18660                                 if (pt._prev) {
18661                                     pt._prev._next = pt._next;
18662                                 } else if (pt === this._firstPT) {
18663                                     this._firstPT = pt._next;
18664                                 }
18665                                 if (pt._next) {
18666                                     pt._next._prev = pt._prev;
18667                                 }
18668                                 pt._next = pt._prev = null;
18669                             }
18670                             delete propLookup[p];
18671                         }
18672                         if (record) {
18673                             overwrittenProps[p] = 1;
18674                         }
18675                     }
18676                     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.
18677                         this._enabled(false, false);
18678                     }
18679                 }
18680             }
18681             return changed;
18682         };
18683
18684         p.invalidate = function() {
18685             if (this._notifyPluginsOfEnabled) {
18686                 TweenLite._onPluginEvent("_onDisable", this);
18687             }
18688             this._firstPT = null;
18689             this._overwrittenProps = null;
18690             this._onUpdate = null;
18691             this._startAt = null;
18692             this._initted = this._active = this._notifyPluginsOfEnabled = this._lazy = false;
18693             this._propLookup = (this._targets) ? {} : [];
18694             return this;
18695         };
18696
18697         p._enabled = function(enabled, ignoreTimeline) {
18698             if (!_tickerActive) {
18699                 _ticker.wake();
18700             }
18701             if (enabled && this._gc) {
18702                 var targets = this._targets,
18703                     i;
18704                 if (targets) {
18705                     i = targets.length;
18706                     while (--i > -1) {
18707                         this._siblings[i] = _register(targets[i], this, true);
18708                     }
18709                 } else {
18710                     this._siblings = _register(this.target, this, true);
18711                 }
18712             }
18713             Animation.prototype._enabled.call(this, enabled, ignoreTimeline);
18714             if (this._notifyPluginsOfEnabled) if (this._firstPT) {
18715                 return TweenLite._onPluginEvent((enabled ? "_onEnable" : "_onDisable"), this);
18716             }
18717             return false;
18718         };
18719
18720
18721 //----TweenLite static methods -----------------------------------------------------
18722
18723         TweenLite.to = function(target, duration, vars) {
18724             return new TweenLite(target, duration, vars);
18725         };
18726
18727         TweenLite.from = function(target, duration, vars) {
18728             vars.runBackwards = true;
18729             vars.immediateRender = (vars.immediateRender != false);
18730             return new TweenLite(target, duration, vars);
18731         };
18732
18733         TweenLite.fromTo = function(target, duration, fromVars, toVars) {
18734             toVars.startAt = fromVars;
18735             toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
18736             return new TweenLite(target, duration, toVars);
18737         };
18738
18739         TweenLite.delayedCall = function(delay, callback, params, scope, useFrames) {
18740             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});
18741         };
18742
18743         TweenLite.set = function(target, vars) {
18744             return new TweenLite(target, 0, vars);
18745         };
18746
18747         TweenLite.getTweensOf = function(target, onlyActive) {
18748             if (target == null) { return []; }
18749             target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;
18750             var i, a, j, t;
18751             if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") {
18752                 i = target.length;
18753                 a = [];
18754                 while (--i > -1) {
18755                     a = a.concat(TweenLite.getTweensOf(target[i], onlyActive));
18756                 }
18757                 i = a.length;
18758                 //now get rid of any duplicates (tweens of arrays of objects could cause duplicates)
18759                 while (--i > -1) {
18760                     t = a[i];
18761                     j = i;
18762                     while (--j > -1) {
18763                         if (t === a[j]) {
18764                             a.splice(i, 1);
18765                         }
18766                     }
18767                 }
18768             } else {
18769                 a = _register(target).concat();
18770                 i = a.length;
18771                 while (--i > -1) {
18772                     if (a[i]._gc || (onlyActive && !a[i].isActive())) {
18773                         a.splice(i, 1);
18774                     }
18775                 }
18776             }
18777             return a;
18778         };
18779
18780         TweenLite.killTweensOf = TweenLite.killDelayedCallsTo = function(target, onlyActive, vars) {
18781             if (typeof(onlyActive) === "object") {
18782                 vars = onlyActive; //for backwards compatibility (before "onlyActive" parameter was inserted)
18783                 onlyActive = false;
18784             }
18785             var a = TweenLite.getTweensOf(target, onlyActive),
18786                 i = a.length;
18787             while (--i > -1) {
18788                 a[i]._kill(vars, target);
18789             }
18790         };
18791
18792
18793
18794 /*
18795  * ----------------------------------------------------------------
18796  * 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)
18797  * ----------------------------------------------------------------
18798  */
18799         var TweenPlugin = _class("plugins.TweenPlugin", function(props, priority) {
18800                     this._overwriteProps = (props || "").split(",");
18801                     this._propName = this._overwriteProps[0];
18802                     this._priority = priority || 0;
18803                     this._super = TweenPlugin.prototype;
18804                 }, true);
18805
18806         p = TweenPlugin.prototype;
18807         TweenPlugin.version = "1.10.1";
18808         TweenPlugin.API = 2;
18809         p._firstPT = null;
18810
18811         p._addTween = function(target, prop, start, end, overwriteProp, round) {
18812             var c, pt;
18813             if (end != null && (c = (typeof(end) === "number" || end.charAt(1) !== "=") ? Number(end) - start : parseInt(end.charAt(0) + "1", 10) * Number(end.substr(2)))) {
18814                 this._firstPT = pt = {_next:this._firstPT, t:target, p:prop, s:start, c:c, f:(typeof(target[prop]) === "function"), n:overwriteProp || prop, r:round};
18815                 if (pt._next) {
18816                     pt._next._prev = pt;
18817                 }
18818                 return pt;
18819             }
18820         };
18821
18822         p.setRatio = function(v) {
18823             var pt = this._firstPT,
18824                 min = 0.000001,
18825                 val;
18826             while (pt) {
18827                 val = pt.c * v + pt.s;
18828                 if (pt.r) {
18829                     val = Math.round(val);
18830                 } else if (val < min) if (val > -min) { //prevents issues with converting very small numbers to strings in the browser
18831                     val = 0;
18832                 }
18833                 if (pt.f) {
18834                     pt.t[pt.p](val);
18835                 } else {
18836                     pt.t[pt.p] = val;
18837                 }
18838                 pt = pt._next;
18839             }
18840         };
18841
18842         p._kill = function(lookup) {
18843             var a = this._overwriteProps,
18844                 pt = this._firstPT,
18845                 i;
18846             if (lookup[this._propName] != null) {
18847                 this._overwriteProps = [];
18848             } else {
18849                 i = a.length;
18850                 while (--i > -1) {
18851                     if (lookup[a[i]] != null) {
18852                         a.splice(i, 1);
18853                     }
18854                 }
18855             }
18856             while (pt) {
18857                 if (lookup[pt.n] != null) {
18858                     if (pt._next) {
18859                         pt._next._prev = pt._prev;
18860                     }
18861                     if (pt._prev) {
18862                         pt._prev._next = pt._next;
18863                         pt._prev = null;
18864                     } else if (this._firstPT === pt) {
18865                         this._firstPT = pt._next;
18866                     }
18867                 }
18868                 pt = pt._next;
18869             }
18870             return false;
18871         };
18872
18873         p._roundProps = function(lookup, value) {
18874             var pt = this._firstPT;
18875             while (pt) {
18876                 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.
18877                     pt.r = value;
18878                 }
18879                 pt = pt._next;
18880             }
18881         };
18882
18883         TweenLite._onPluginEvent = function(type, tween) {
18884             var pt = tween._firstPT,
18885                 changed, pt2, first, last, next;
18886             if (type === "_onInitAllProps") {
18887                 //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.
18888                 while (pt) {
18889                     next = pt._next;
18890                     pt2 = first;
18891                     while (pt2 && pt2.pr > pt.pr) {
18892                         pt2 = pt2._next;
18893                     }
18894                     if ((pt._prev = pt2 ? pt2._prev : last)) {
18895                         pt._prev._next = pt;
18896                     } else {
18897                         first = pt;
18898                     }
18899                     if ((pt._next = pt2)) {
18900                         pt2._prev = pt;
18901                     } else {
18902                         last = pt;
18903                     }
18904                     pt = next;
18905                 }
18906                 pt = tween._firstPT = first;
18907             }
18908             while (pt) {
18909                 if (pt.pg) if (typeof(pt.t[type]) === "function") if (pt.t[type]()) {
18910                     changed = true;
18911                 }
18912                 pt = pt._next;
18913             }
18914             return changed;
18915         };
18916
18917         TweenPlugin.activate = function(plugins) {
18918             var i = plugins.length;
18919             while (--i > -1) {
18920                 if (plugins[i].API === TweenPlugin.API) {
18921                     _plugins[(new plugins[i]())._propName] = plugins[i];
18922                 }
18923             }
18924             return true;
18925         };
18926
18927         //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.
18928         _gsDefine.plugin = function(config) {
18929             if (!config || !config.propName || !config.init || !config.API) { throw "illegal plugin definition."; }
18930             var propName = config.propName,
18931                 priority = config.priority || 0,
18932                 overwriteProps = config.overwriteProps,
18933                 map = {init:"_onInitTween", set:"setRatio", kill:"_kill", round:"_roundProps", initAll:"_onInitAllProps"},
18934                 Plugin = _class("plugins." + propName.charAt(0).toUpperCase() + propName.substr(1) + "Plugin",
18935                     function() {
18936                         TweenPlugin.call(this, propName, priority);
18937                         this._overwriteProps = overwriteProps || [];
18938                     }, (config.global === true)),
18939                 p = Plugin.prototype = new TweenPlugin(propName),
18940                 prop;
18941             p.constructor = Plugin;
18942             Plugin.API = config.API;
18943             for (prop in map) {
18944                 if (typeof(config[prop]) === "function") {
18945                     p[map[prop]] = config[prop];
18946                 }
18947             }
18948             Plugin.version = config.version;
18949             TweenPlugin.activate([Plugin]);
18950             return Plugin;
18951         };
18952
18953
18954         //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.
18955         a = window._gsQueue;
18956         if (a) {
18957             for (i = 0; i < a.length; i++) {
18958                 a[i]();
18959             }
18960             for (p in _defLookup) {
18961                 if (!_defLookup[p].func) {
18962                     //window.console.log("GSAP encountered missing dependency: com.greensock." + p);
18963                 }
18964             }
18965         }
18966
18967         _tickerActive = false; //ensures that the first official animation forces a ticker.tick() to update the time when it is instantiated
18968
18969 })(window);
18970
18971 angular.module('b2b.att.collapse', ['b2b.att.transition'])
18972
18973 // The collapsible directive indicates a block of html that will expand and collapse
18974 .directive('b2bCollapse', ['$transition', function($transition) {
18975     // CSS transitions don't work with height: auto, so we have to manually change the height to a
18976     // specific value and then once the animation completes, we can reset the height to auto.
18977     // Unfortunately if you do this while the CSS transitions are specified (i.e. in the CSS class
18978     // "collapse") then you trigger a change to height 0 in between.
18979     // The fix is to remove the "collapse" CSS class while changing the height back to auto - phew!
18980
18981     var props = {
18982         open: {
18983             marginTop: null,
18984             marginBottom: null,
18985             paddingTop: null,
18986             paddingBottom: null,
18987             display: 'block'
18988         },
18989         closed: {
18990             marginTop: 0,
18991             marginBottom: 0,
18992             paddingTop: 0,
18993             paddingBottom: 0,
18994             display: 'none'
18995         }
18996     };
18997
18998     var fixUpHeight = function(scope, element, height) {
18999         // We remove the collapse CSS class to prevent a transition when we change to height: auto
19000         element.removeClass('b2bCollapse');
19001         element.css({height: height});
19002         //adjusting for any margin or padding
19003         if (height === 0) {
19004             element.css(props.closed);
19005         } else {
19006             element.css(props.open);
19007         }
19008         // It appears that  reading offsetWidth makes the browser realise that we have changed the
19009         // height already :-/
19010         var x = element[0].offsetWidth;
19011         element.addClass('b2bCollapse');
19012     };
19013
19014     return {
19015         link: function(scope, element, attrs) {
19016             var isCollapsed;
19017             var initialAnimSkip = true;
19018             scope.$watch(function() {
19019                 return element[0].scrollHeight;
19020             }, function(value) {
19021                 //The listener is called when scrollHeight changes
19022                 //It actually does on 2 scenarios: 
19023                 // 1. Parent is set to display none
19024                 // 2. angular bindings inside are resolved
19025                 //When we have a change of scrollHeight we are setting again the correct height if the group is opened
19026                 if (element[0].scrollHeight !== 0) {
19027                     if (!isCollapsed) {
19028                         if (initialAnimSkip) {
19029                             fixUpHeight(scope, element, element[0].scrollHeight + 'px');
19030                         } else {
19031                             fixUpHeight(scope, element, 'auto');
19032                             element.css({overflow: 'visible'});
19033                         }
19034                     }
19035                 }
19036             });
19037
19038             scope.$watch(attrs.b2bCollapse, function(value) {
19039                 if (value) {
19040                     collapse();
19041                 } else {
19042                     expand();
19043                 }
19044             });
19045
19046
19047             var currentTransition;
19048             var doTransition = function(change) {
19049                 if (currentTransition) {
19050                     currentTransition.cancel();
19051                 }
19052                 currentTransition = $transition(element, change);
19053                 currentTransition.then(
19054                         function() {
19055                             currentTransition = undefined;
19056                         },
19057                         function() {
19058                             currentTransition = undefined;
19059                         }
19060                 );
19061                 return currentTransition;
19062             };
19063
19064             var expand = function() {
19065                 scope.postTransition = true; 
19066                 if (initialAnimSkip) {
19067                     initialAnimSkip = false;
19068                     if (!isCollapsed) {
19069                         fixUpHeight(scope, element, 'auto');
19070                     }
19071                 } else {
19072                     //doTransition({ height : element[0].scrollHeight + 'px' })
19073                     doTransition(angular.extend({height: element[0].scrollHeight + 'px'}, props.open))
19074                             .then(function() {
19075                                 // This check ensures that we don't accidentally update the height if the user has closed
19076                                 // the group while the animation was still running
19077                                 if (!isCollapsed) {
19078                                     fixUpHeight(scope, element, 'auto');
19079                                 }
19080                             });
19081                 }
19082                 isCollapsed = false;
19083             };
19084
19085             var collapse = function() {
19086                 isCollapsed = true;
19087                 if (initialAnimSkip) {
19088                     initialAnimSkip = false;
19089                     fixUpHeight(scope, element, 0);
19090                 } else {
19091                     fixUpHeight(scope, element, element[0].scrollHeight + 'px');
19092                     doTransition(angular.extend({height: 0}, props.closed)).then(function() {
19093                         scope.postTransition = false;
19094                     });
19095                     element.css({overflow: 'hidden'});
19096                 }
19097             };
19098         }
19099     };
19100 }]);
19101 angular.module('b2b.att.position', [])
19102
19103 .factory('$position', ['$document', '$window', function ($document, $window) {
19104     function getStyle(el, cssprop) {
19105         if (el.currentStyle) { //IE
19106             return el.currentStyle[cssprop];
19107         } else if ($window.getComputedStyle) {
19108             return $window.getComputedStyle(el)[cssprop];
19109         }
19110         // finally try and get inline style
19111         return el.style[cssprop];
19112     }
19113
19114     /**
19115      * Checks if a given element is statically positioned
19116      * @param element - raw DOM element
19117      */
19118     function isStaticPositioned(element) {
19119         return (getStyle(element, "position") || 'static') === 'static';
19120     }
19121
19122     /**
19123      * returns the closest, non-statically positioned parentOffset of a given element
19124      * @param element
19125      */
19126     var parentOffsetEl = function (element) {
19127         var docDomEl = $document[0];
19128         var offsetParent = element.offsetParent || docDomEl;
19129         while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent)) {
19130             offsetParent = offsetParent.offsetParent;
19131         }
19132         return offsetParent || docDomEl;
19133     };
19134
19135     return {
19136         /**
19137          * Provides read-only equivalent of jQuery's position function:
19138          * http://api.jquery.com/position/
19139          */
19140         position: function (element) {
19141             var elBCR = this.offset(element);
19142             var offsetParentBCR = {
19143                 top: 0,
19144                 left: 0
19145             };
19146             var offsetParentEl = parentOffsetEl(element[0]);
19147             if (offsetParentEl !== $document[0]) {
19148                 offsetParentBCR = this.offset(angular.element(offsetParentEl));
19149                 offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop;
19150                 offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft;
19151             }
19152
19153             return {
19154                 width: element.prop('offsetWidth'),
19155                 height: element.prop('offsetHeight'),
19156                 top: elBCR.top - offsetParentBCR.top,
19157                 left: elBCR.left - offsetParentBCR.left
19158             };
19159         },
19160
19161         /**
19162          * Provides read-only equivalent of jQuery's offset function:
19163          * http://api.jquery.com/offset/
19164          */
19165         offset: function (element) {
19166             var boundingClientRect = element[0].getBoundingClientRect();
19167             return {
19168                 width: element.prop('offsetWidth'),
19169                 height: element.prop('offsetHeight'),
19170                 top: boundingClientRect.top + ($window.pageYOffset || $document[0].body.scrollTop || $document[0].documentElement.scrollTop),
19171                 left: boundingClientRect.left + ($window.pageXOffset || $document[0].body.scrollLeft || $document[0].documentElement.scrollLeft)
19172             };
19173         },
19174         
19175          /**
19176          * Provides functionality to check whether an element is in view port.
19177          */
19178         isElementInViewport: function (element) {
19179             if (element) {
19180                 var rect = element[0].getBoundingClientRect();
19181                 return (
19182                     rect.top >= 0 &&
19183                     rect.left >= 0 &&
19184                     rect.bottom <= ($window.innerHeight || $document[0].documentElement.clientHeight) &&
19185                     rect.right <= ($window.innerWidth || $document[0].documentElement.clientWidth)
19186                 );
19187             } else {
19188                 return false;
19189             }
19190         }
19191     };
19192 }])
19193
19194 .factory('$isElement', [function () {
19195     var isElement = function (currentElem, targetElem, alternateElem) {
19196         if (currentElem[0] === targetElem[0]) {
19197             return true;
19198         } else if (currentElem[0] === alternateElem[0]) {
19199             return false;
19200         } else {
19201             return isElement((currentElem.parent()[0] && currentElem.parent()) || targetElem, targetElem, alternateElem);
19202         }
19203     };
19204
19205     return isElement;
19206 }])
19207
19208 .directive('attPosition', ['$position', function ($position) {
19209     return {
19210         restrict: 'A',
19211         link: function (scope, elem, attr) {
19212             scope.$watchCollection(function () {
19213                 return $position.position(elem);
19214             }, function (value) {
19215                 scope[attr.attPosition] = value;
19216             });
19217         }
19218     };
19219 }]);
19220
19221 angular.module('b2b.att.transition', [])
19222
19223 .factory('$transition', ['$q', '$timeout', '$rootScope', function($q, $timeout, $rootScope) {
19224
19225   var $transition = function(element, trigger, options) {
19226     options = options || {};
19227     var deferred = $q.defer();
19228     var endEventName = $transition[options.animation ? "animationEndEventName" : "transitionEndEventName"];
19229
19230     var transitionEndHandler = function() {
19231       $rootScope.$apply(function() {
19232         element.unbind(endEventName, transitionEndHandler);
19233         deferred.resolve(element);
19234       });
19235     };
19236
19237     if (endEventName) {
19238       element.bind(endEventName, transitionEndHandler);
19239     }
19240
19241     // Wrap in a timeout to allow the browser time to update the DOM before the transition is to occur
19242     $timeout(function() {
19243       if ( angular.isString(trigger) ) {
19244         element.addClass(trigger);
19245       } else if ( angular.isFunction(trigger) ) {
19246         trigger(element);
19247       } else if ( angular.isObject(trigger) ) {
19248         element.css(trigger);
19249       }
19250       //If browser does not support transitions, instantly resolve
19251       if ( !endEventName ) {
19252         deferred.resolve(element);
19253       }
19254     }, 100);
19255
19256     // Add our custom cancel function to the promise that is returned
19257     // We can call this if we are about to run a new transition, which we know will prevent this transition from ending,
19258     // i.e. it will therefore never raise a transitionEnd event for that transition
19259     deferred.promise.cancel = function() {
19260       if ( endEventName ) {
19261         element.unbind(endEventName, transitionEndHandler);
19262       }
19263       deferred.reject('Transition cancelled');
19264     };
19265
19266     return deferred.promise;
19267   };
19268
19269   // Work out the name of the transitionEnd event
19270   var transElement = document.createElement('trans');
19271   var transitionEndEventNames = {
19272     'WebkitTransition': 'webkitTransitionEnd',
19273     'MozTransition': 'transitionend',
19274     'OTransition': 'oTransitionEnd',
19275     'transition': 'transitionend'
19276   };
19277   var animationEndEventNames = {
19278     'WebkitTransition': 'webkitAnimationEnd',
19279     'MozTransition': 'animationend',
19280     'OTransition': 'oAnimationEnd',
19281     'transition': 'animationend'
19282   };
19283   function findEndEventName(endEventNames) {
19284     for (var name in endEventNames){
19285       if (transElement.style[name] !== undefined) {
19286         return endEventNames[name];
19287       }
19288     }
19289   }
19290   $transition.transitionEndEventName = findEndEventName(transitionEndEventNames);
19291   $transition.animationEndEventName = findEndEventName(animationEndEventNames);
19292   return $transition;
19293 }])
19294
19295 .factory('$scrollTo', ['$window', function($window) {
19296     var $scrollTo = function(offsetLeft, offsetTop, duration) {
19297         TweenMax.to($window, duration || 1, {scrollTo: {y: offsetTop, x: offsetLeft}, ease: Power4.easeOut});
19298     };
19299     return $scrollTo;
19300 }])
19301 .factory('animation', function(){
19302     return TweenMax;
19303 })
19304 .factory('$progressBar', function(){
19305
19306    //Provides a function to pass in code for closure purposes
19307    var loadingAnimationCreator = function(onUpdateCallback){
19308
19309       //Use closure to setup some resuable code
19310       var loadingAnimation = function(callback, duration){
19311           TweenMax.to({}, duration, {
19312               onUpdateParams: ["{self}"],
19313               onUpdate: onUpdateCallback,
19314               onComplete: callback
19315           });
19316       };
19317       //Returns a function that takes a callback function and a duration for the animation
19318       return (function(){
19319         return loadingAnimation;
19320       })();
19321     };
19322
19323   return loadingAnimationCreator;
19324 })
19325 .factory('$height', function(){
19326   var heightAnimation = function(element,duration,height,alpha){
19327     TweenMax.to(element,
19328       duration,
19329       {height:height, autoAlpha:alpha},
19330       0);
19331   };
19332   return heightAnimation;
19333 });
19334 angular.module('b2b.att.utilities', ['ngSanitize'])
19335 .constant('b2bUtilitiesConfig', {
19336     prev: '37',
19337     up: '38',
19338     next: '39',
19339     down: '40',
19340     type: 'list',
19341     columns: 1,
19342     enableSearch: false,
19343     searchTimer: 200,
19344     circularTraversal: false
19345 })
19346 .constant('b2bWhenScrollEndsConstants', {
19347     'threshold': 100,
19348     'width': 0,
19349     'height': 0
19350 })
19351 // All breakpoints ranges from >= min and < max
19352 .constant('b2bAwdBreakpoints', {
19353     breakpoints: {
19354         mobile: {
19355             min: 1,
19356             max: 768
19357         },
19358         tablet: {
19359             min: 768,
19360             max: 1025
19361         },
19362         desktop: {
19363             min: 1025,
19364             max: 1920
19365         }
19366     }
19367 })
19368 .filter('groupBy', function ($timeout) {
19369     //Custom GroupBy Filter for treeNav, returns key string and value.childarray as set of grouped elements
19370     return function (data, key) {
19371         if (!key) return data;
19372         var outputPropertyName = '__groupBy__' + key;
19373         if (!data[outputPropertyName]) {
19374             var result = {};
19375             for (var i = 0; i < data.length; i++) {
19376                 if (!result[data[i][key]])
19377                     result[data[i][key]] = {};
19378                 if (!result[data[i][key]].childArray) {
19379                     result[data[i][key]].childArray = [];
19380                 }
19381                 result[data[i][key]].childArray.push(data[i]);
19382                 if (data[i].activeGrp && data[i].activeGrp == true) {
19383                     console.log('make ' + data[i].grpChild + ' active');
19384                     result[data[i][key]].showGroup = true;
19385                 }
19386             }
19387             Object.defineProperty(result, 'length', {enumerable: false,value: Object.keys(result).length});
19388             Object.defineProperty(data, outputPropertyName, {enumerable: false,configurable: true,writable:false,value:result});
19389             $timeout(function(){delete data[outputPropertyName];},0,false);
19390         }
19391         return data[outputPropertyName];
19392     };
19393 })
19394 .filter('searchObjectPropertiesFilter', [function() {
19395     return function(items, searchText, attrs) {
19396         if(!searchText){
19397             return items;
19398         }
19399         var filtered = [];
19400         searchText = searchText.toLowerCase();
19401         angular.forEach(items, function(item) {
19402             angular.forEach(attrs, function(attr) {
19403                 if (item.hasOwnProperty(attr) && item[attr].toLowerCase().includes(searchText)) {
19404                     filtered.push(item);
19405                     return;
19406                 }
19407             });
19408         });
19409         return filtered;
19410     };
19411 }])
19412 .filter('unsafe',[ '$sce', function ($sce) { 
19413     return function(val){ 
19414        return $sce.trustAsHtml(val); 
19415     }; 
19416 }])
19417 .filter('b2bHighlight', function () {
19418     function escapeRegexp(queryToEscape) {
19419         return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
19420     }
19421     return function (matchItem, query, className) {
19422         return query && matchItem ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '<span class=\"' + className + '\">$&</span>') : matchItem;
19423     }
19424 })
19425 /*License (MIT)
19426 Copyright Â© 2013 Matt Diamond
19427 https://github.com/cwilso/AudioRecorder/blob/master/js/recorderjs/recorder.js
19428 */
19429 .factory('b2bRecorder', function() {
19430
19431     var Recorder = function(source, cfg) {
19432         var WORKER_PATH = 'recorderWorker.js';
19433         var config = cfg || {};
19434         var bufferLen = config.bufferLen || 4096;
19435         this.context = source.context;
19436         if(!this.context.createScriptProcessor) {
19437             this.node = this.context.createJavacriptProcessor(bufferLen, 2, 2);
19438         } else {
19439             this.node = this.context.createScriptProcessor(bufferLen, 2, 2);
19440         }
19441         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()}};';
19442         var blob = new Blob([workerCode]);
19443
19444         var worker = new Worker(window.URL.createObjectURL(blob)); //TODO: Use a blob instead
19445         worker.postMessage({
19446             command: 'init',
19447             config: {
19448                 sampleRate: this.context.sampleRate
19449             }
19450         });
19451         var recording = false,
19452             currCallback;
19453
19454         this.node.onaudioprocess = function(e) {
19455             if (!recording) return;
19456             worker.postMessage({
19457                 command: 'record',
19458                 buffer: [
19459                     e.inputBuffer.getChannelData(0),
19460                     e.inputBuffer.getChannelData(1)
19461                 ]
19462             });
19463         };
19464
19465         this.configure = function(cfg) {
19466             for (var prop in cfg) {//TODO: look into using angular.extend() here
19467                 if (cfg.hasOwnProperty(prop)) {
19468                     config[prop] = cfg[prop];
19469                 }
19470             }
19471         };
19472
19473         this.record = function() {
19474             recording = true;
19475         };
19476
19477         this.stop = function() {
19478             recording = false;
19479         };
19480
19481         this.clear = function() {
19482             worker.postMessage({ command: 'clear' });
19483             window.URL.revokeObjectURL(blob);
19484         };
19485
19486         this.getBuffers = function(cb) {
19487             currCallback = cb || config.callback;
19488             worker.postMessage({ command: 'getBuffers' });
19489         };
19490
19491         this.exportWAV = function(cb, type) {
19492             currCallback = cb || config.callback;
19493             type = type || config.type || 'audio/wav';
19494             if (!currCallback) throw new Error('[b2bRecorder]: Callback not set!');
19495             worker.postMessage({
19496                 command: 'exportWAV',
19497                 type: type
19498             });
19499         };
19500
19501         this.exportMonoWAV = function(cb, type) {
19502             currCallback = cb || config.callback;
19503             type = type || config.type || 'audio/wav';
19504             if (!currCallback) throw new Error('[b2bRecorder]: Callback not set!');
19505             worker.postMessage({
19506                 command: 'exportMonoWAV',
19507                 type: type
19508             });
19509         };
19510
19511         worker.onmessage = function(e) {
19512             var blob = e.data;
19513             currCallback(blob);
19514         };
19515
19516         source.connect(this.node);
19517         this.node.connect(this.context.destination); // if the script node is not connected to an output the "onaudioprocess" event is not triggerd in Chrome
19518
19519     };
19520
19521     return Recorder;
19522
19523 })
19524 .factory('b2bViewport', function() {
19525   /* Source: https://gist.github.com/bjankord/2399828 */
19526   var _viewportWidth = function() {
19527     var vpw;
19528     var webkit = (!(window.webkitConvertPointFromNodeToPage == null));
19529     
19530     // Webkit:
19531     if ( webkit ) {
19532       var vpwtest = document.createElement( "div" );
19533       // Sets test div to width 100%, !important overrides any other misc. box model styles that may be set in the CSS
19534       vpwtest.style.cssText = "width:100% !important; margin:0 !important; padding:0 !important; border:none !important;";
19535       document.documentElement.insertBefore( vpwtest, document.documentElement.firstChild );
19536       vpw = vpwtest.offsetWidth;
19537       document.documentElement.removeChild( vpwtest );
19538     }
19539     // IE 6-8:
19540     else if ( window.innerWidth === undefined ) { 
19541       vpw = document.documentElement.clientWidth; 
19542     }
19543     // Other:
19544     else{
19545       vpw =  window.innerWidth;
19546     }
19547
19548     return (vpw);
19549   }
19550   return {
19551     viewportWidth: _viewportWidth
19552   };
19553 })
19554 .directive('b2bWhenScrollEnds', function(b2bWhenScrollEndsConstants, $log) {
19555     return {
19556         restrict: 'A',
19557         link: function (scope, element, attrs) {
19558             /**
19559             * Exposed Attributes:
19560             *       threshold - integer - number of pixels before scrollbar hits end that callback is called
19561             *       width - integer - override for element's width (px)
19562             *       height - integer - override for element's height (px)
19563             *       axis - string - x/y for scroll bar axis
19564             */
19565             var threshold = parseInt(attrs.threshold, 10) || b2bWhenScrollEndsConstants.threshold;
19566
19567             if (!attrs.axis || attrs.axis === '') {
19568                 $log.warn('axis attribute must be defined for b2bWhenScrollEnds.');
19569                 return;
19570             }
19571
19572             if (attrs.axis === 'x') {
19573                 visibleWidth = parseInt(attrs.width, 10) || b2bWhenScrollEndsConstants.width;
19574                 if (element.css('width')) {
19575                     visibleWidth = element.css('width').split('px')[0];  
19576                 }
19577
19578                 element[0].addEventListener('scroll', function() {
19579                     var scrollableWidth = element.prop('scrollWidth');
19580                     if (scrollableWidth === undefined) {
19581                         scrollableWidth = 1;
19582                     }
19583                     var hiddenContentWidth = scrollableWidth - visibleWidth;
19584
19585                     if (hiddenContentWidth - element[0].scrollLeft <= threshold) {
19586                         /* Scroll almost at bottom, load more rows */
19587                         scope.$apply(attrs.b2bWhenScrollEnds);
19588                     }
19589                 });
19590             } else if (attrs.axis === 'y') {
19591                 visibleHeight = parseInt(attrs.height, 10) || b2bWhenScrollEndsConstants.height;
19592                 if (element.css('width')) {
19593                     visibleHeight = element.css('height').split('px')[0]; 
19594                 }
19595
19596                 element[0].addEventListener('scroll', function() {
19597                     var scrollableHeight = element.prop('scrollHeight');
19598                     if (scrollableHeight === undefined) {
19599                         scrollableHeight = 1;
19600                     }
19601                     var hiddenContentHeight = scrollableHeight - visibleHeight;
19602
19603                     if (hiddenContentHeight - element[0].scrollTop <= threshold) {
19604                         /* Scroll almost at bottom, load more rows */
19605                         scope.$apply(attrs.b2bWhenScrollEnds);
19606                     }
19607                 });
19608             }
19609         }
19610     };
19611 })
19612
19613 .factory('$windowBind', ['$window', '$timeout', function($window, $timeout) {
19614     var win = angular.element($window);
19615     var _scroll = function (flag, callbackFunc, scope) {
19616         scope.$watch(flag, function (val) {
19617             $timeout(function () {
19618                 if (val) {
19619                     win.bind('scroll', callbackFunc);
19620                 } else {
19621                     win.unbind('scroll', callbackFunc);
19622                 }
19623             });
19624         });
19625     };
19626
19627     var throttle = function(type, name, obj) {
19628         obj = obj || window;
19629         var running = false;
19630         var func = function() {
19631             if (running) { return; }
19632             running = true;
19633              requestAnimationFrame(function() {
19634                 obj.dispatchEvent(new CustomEvent(name));
19635                 running = false;
19636             });
19637         };
19638         obj.addEventListener(type, func);
19639     };
19640
19641     var _resize = function(callbackFunc, scope) {
19642         throttle("resize", "optimizedResize");
19643         window.addEventListener("optimizedResize", function(event) {
19644             callbackFunc();
19645             //win.bind(event, callbackFunc);
19646             if (!scope.$$phase) {
19647                 scope.$digest();
19648             }
19649         });
19650     };
19651
19652     var _click = function (flag, callbackFunc, scope) {
19653         scope.$watch(flag, function (val) {
19654             $timeout(function () {
19655                 if (val) {
19656                     win.bind('click', callbackFunc);
19657                 } else {
19658                     win.unbind('click', callbackFunc);
19659                 }
19660             });
19661         });
19662     };
19663
19664     var _event = function (event, flag, callbackFunc, scope, timeoutFlag, timeoutValue) {
19665         if (timeoutFlag) {
19666             if (!(timeoutValue)) {
19667                 timeoutValue = 0;
19668             }
19669             scope.$watch(flag, function (newVal, oldVal) {
19670                 if (newVal !== oldVal) {
19671                     $timeout(function () {
19672                         if (newVal) {
19673                             win.bind(event, callbackFunc);
19674                         } else {
19675                             win.unbind(event, callbackFunc);
19676                         }
19677                     }, timeoutValue);
19678                 }
19679             });
19680         } else {
19681             scope.$watch(flag, function (newVal, oldVal) {
19682                 if (newVal !== oldVal) {
19683                     if (newVal) {
19684                         win.bind(event, callbackFunc);
19685                     } else {
19686                         win.unbind(event, callbackFunc);
19687                     }
19688                 }
19689             });
19690         }
19691     };
19692
19693     return {
19694         click: _click,
19695         scroll: _scroll,
19696         event: _event, 
19697         resize: _resize
19698     };
19699 }])
19700
19701 .factory('keymap', function () {
19702     return {
19703         KEY: {
19704             TAB: 9,
19705             ENTER: 13,
19706             ESC: 27,
19707             SPACE: 32,
19708             LEFT: 37,
19709             UP: 38,
19710             RIGHT: 39,
19711             DOWN: 40,
19712             SHIFT: 16,
19713             CTRL: 17,
19714             ALT: 18,
19715             PAGE_UP: 33,
19716             PAGE_DOWN: 34,
19717             HOME: 36,
19718             END: 35,
19719             BACKSPACE: 8,
19720             DELETE: 46,
19721             COMMAND: 91
19722         },
19723         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 : "'"
19724         },
19725         isControl: function (e) {
19726             var k = e.keyCode;
19727             switch (k) {
19728             case this.KEY.COMMAND:
19729             case this.KEY.SHIFT:
19730             case this.KEY.CTRL:
19731             case this.KEY.ALT:
19732                 return true;
19733             default:;
19734             }
19735
19736             if (e.metaKey) {
19737                 return true;
19738             }
19739
19740             return false;
19741         },
19742         isFunctionKey: function (k) {
19743             k = k.keyCode ? k.keyCode : k;
19744             return k >= 112 && k <= 123;
19745         },
19746         isVerticalMovement: function (k) {
19747             return ~[this.KEY.UP, this.KEY.DOWN].indexOf(k);
19748         },
19749         isHorizontalMovement: function (k) {
19750             return ~[this.KEY.LEFT, this.KEY.RIGHT, this.KEY.BACKSPACE, this.KEY.DELETE].indexOf(k);
19751         },
19752         isAllowedKey: function (k) {
19753             return (~[this.KEY.SPACE, this.KEY.ESC, this.KEY.ENTER].indexOf(k)) || this.isHorizontalMovement(k) || this.isVerticalMovement(k);
19754         },
19755         isNumericKey: function (e) {
19756             var k = e.keyCode;
19757             if ((k >= 48 && k <= 57) || (k >= 96 && k <= 105)) {
19758                 return true;
19759             } else {
19760                 return false;
19761             }
19762         },
19763         isAlphaNumericKey: function (e) {
19764             var k = e.keyCode;
19765             if ((k >= 48 && k <= 57) || (k >= 96 && k <= 105) || (k >= 65 && k <= 90)) {
19766                 return true;
19767             } else {
19768                 return false;
19769             }
19770         }
19771     };
19772 })
19773
19774 .factory('$isElement', [function () {
19775     var isElement = function (currentElem, targetElem, alternateElem) {
19776         if (currentElem[0] === targetElem[0]) {
19777             return true;
19778         } else if (currentElem[0] === alternateElem[0]) {
19779             return false;
19780         } else {
19781             return isElement((currentElem.parent()[0] && currentElem.parent()) || targetElem, targetElem, alternateElem);
19782         }
19783     };
19784
19785     return isElement;
19786 }])
19787
19788 .factory('events', function () {
19789     var _stopPropagation = function (evt) {
19790         if (evt.stopPropagation) {
19791             evt.stopPropagation();
19792         } else {
19793             evt.returnValue = false;
19794         }
19795     };
19796     var _preventDefault = function (evt) {
19797         if (evt.preventDefault) {
19798             evt.preventDefault();
19799         } else {
19800             evt.returnValue = false;
19801         }
19802     }
19803     return {
19804         stopPropagation: _stopPropagation,
19805         preventDefault: _preventDefault
19806     };
19807 })
19808
19809
19810 .factory('$documentBind', ['$document', '$timeout', function ($document, $timeout) {
19811     var _click = function (flag, callbackFunc, scope) {
19812         scope.$watch(flag, function (val) {
19813             $timeout(function () {
19814                 if (val) {
19815                     $document.bind('click', callbackFunc);
19816                 } else {
19817                     $document.unbind('click', callbackFunc);
19818                 }
19819             });
19820         });
19821     };
19822
19823     var _scroll = function (flag, callbackFunc, scope) {
19824         scope.$watch(flag, function (val) {
19825             $timeout(function () {
19826                 if (val) {
19827                     $document.bind('scroll', callbackFunc);
19828                 } else {
19829                     $document.unbind('scroll', callbackFunc);
19830                 }
19831             });
19832         });
19833     };
19834
19835     var _event = function (event, flag, callbackFunc, scope, timeoutFlag, timeoutValue) {
19836         if (timeoutFlag) {
19837             if (!(timeoutValue)) {
19838                 timeoutValue = 0;
19839             }
19840             scope.$watch(flag, function (newVal, oldVal) {
19841                 if (newVal !== oldVal) {
19842                     $timeout(function () {
19843                         if (newVal) {
19844                             $document.bind(event, callbackFunc);
19845                         } else {
19846                             $document.unbind(event, callbackFunc);
19847                         }
19848                     }, timeoutValue);
19849                 }
19850             });
19851         } else {
19852             scope.$watch(flag, function (newVal, oldVal) {
19853                 if (newVal !== oldVal) {
19854                     if (newVal) {
19855                         $document.bind(event, callbackFunc);
19856                     } else {
19857                         $document.unbind(event, callbackFunc);
19858                     }
19859                 }
19860             });
19861         }
19862     };
19863
19864     return {
19865         click: _click,
19866         scroll: _scroll,
19867         event: _event
19868     };
19869 }])
19870
19871 .directive('b2bOnlyNums', function (keymap) {
19872     return {
19873         restrict: 'A',
19874         require: 'ngModel',
19875         link: function (scope, elm, attrs, ctrl) {
19876             var maxChars = attrs.b2bOnlyNums ? attrs.b2bOnlyNums : 4;
19877             elm.on('keydown', function (event) {
19878                 if ((event.which >= 48 && event.which <= 57) || (event.which >= 96 && event.which <= 105)) {
19879                     // check for maximum characters allowed
19880                     if (elm.val().length < maxChars){
19881                         return true;
19882                     } else {
19883                         event.preventDefault();
19884                         return false;
19885                     }
19886                 } else if ([8, 9, 13, 27, 37, 38, 39, 40].indexOf(event.which) > -1) {
19887                     // to allow backspace, tab, enter, escape, arrows
19888                     return true;
19889                 } else if (event.altKey || event.ctrlKey) {
19890                     // to allow alter, control, and shift keys
19891                     return true;
19892                 } else {
19893                     // to stop others
19894                     event.preventDefault();
19895                     return false;
19896                 }
19897             });
19898
19899             var validateString = function (value) {
19900                 if (angular.isUndefined(value) || value === null || value === '') {
19901                     return ctrl.$modelValue;
19902                 }
19903                 return value;
19904             };
19905             ctrl.$parsers.unshift(validateString);
19906         }
19907     }
19908 })
19909
19910 .directive('b2bKeyupClick', [ function () {
19911     return {
19912         restrict: 'A',
19913         link: function (scope, elem, attr) {
19914             var keyCode = [];
19915             attr.$observe('b2bKeyupClick', function (value) {
19916                 if (value) {
19917                     keyCode = value.split(',');
19918                 }
19919             });
19920             elem.bind('keydown keyup', function (ev) {
19921                 var keyCodeCondition = function () {
19922                     var flag = false;
19923                     if (!(ev.keyCode)) {
19924                         if (ev.which) {
19925                             ev.keyCode = ev.which;
19926                         } else if (ev.charCode) {
19927                             ev.keyCode = ev.charCode;
19928                         }
19929                     }
19930                     if ((ev.keyCode && keyCode.indexOf(ev.keyCode.toString()) > -1)) {
19931                         flag = true;
19932                     }
19933                     return flag;
19934                 };
19935                 if (ev.type === 'keydown' && keyCodeCondition()) {
19936                     ev.preventDefault();
19937                 }
19938                 else if (ev.type === 'keyup' && keyCodeCondition()) {
19939                     elem[0].click();
19940                 }
19941             });
19942         }
19943     };
19944 }])
19945
19946 .factory('b2bDOMHelper', function() {
19947
19948     var _isTabable = function(node) {
19949         var element = angular.element(node);
19950         var tagName = element[0].tagName.toUpperCase();
19951
19952         if (isHidden(element)) {
19953             return false;
19954         }
19955         if (element.attr('tabindex') !== undefined) {
19956             return (parseInt(element.attr('tabindex'), 10) >= 0);
19957         }
19958         if (tagName === 'A' || tagName === 'AREA' || tagName === 'BUTTON' || tagName === 'INPUT' || tagName === 'TEXTAREA' || tagName === 'SELECT') {
19959             if (tagName === 'A' || tagName === 'AREA') {
19960                 // anchors/areas without href are not focusable
19961                 return (element[0].href !== '');
19962             }
19963             return !(element[0].disabled || element[0].readOnly);
19964         }
19965         return false;
19966     };
19967
19968     function isValidChild(child) {
19969         return child.nodeType == 1 && child.nodeName != 'SCRIPT' && child.nodeName != 'STYLE';
19970     }
19971     
19972     function isHidden(obj) {
19973         var elem = angular.element(obj);
19974         var elemStyle = undefined;
19975         if(obj instanceof HTMLElement){
19976             elemStyle = window.getComputedStyle(obj);
19977         }
19978         else {
19979             elemStyle = window.getComputedStyle(obj[0]);
19980         }
19981         return elem.hasClass('ng-hide') || elem.css('display') === 'none' || elemStyle.display === 'none' || elemStyle.visibility === 'hidden' || elem.css('visibility') === 'hidden';
19982     }
19983
19984     function hasValidParent(obj) {
19985         return (isValidChild(obj) && obj.parentElement.nodeName !== 'BODY');
19986     }
19987
19988     function traverse(obj, fromTop) {
19989         var obj = obj || document.getElementsByTagName('body')[0];
19990         if (isValidChild(obj) && _isTabable(obj)) {
19991             return obj;
19992         }
19993         // If object is hidden, skip it's children
19994         if (isValidChild(obj) && isHidden(obj)) {
19995             return undefined;
19996         } 
19997         // If object is hidden, skip it's children
19998         if (angular.element(obj).hasClass('ng-hide')) {
19999             return undefined;
20000         }  
20001         if (obj.hasChildNodes()) {
20002             var child;
20003             if (fromTop) {
20004                 child = obj.firstChild;
20005             } else {
20006                 child = obj.lastChild;
20007             }
20008             while(child) {
20009                 var res =  traverse(child, fromTop);
20010                 if(res){
20011                     return res;
20012                 }
20013                 else{
20014                     if (fromTop) {
20015                         child = child.nextSibling;
20016                     } else {
20017                         child = child.previousSibling;
20018                     }
20019                 }
20020             }
20021         }
20022         else{
20023             return undefined;
20024         }
20025     }
20026
20027     var _previousElement = function(el, isFocusable){
20028
20029         var elem = el;
20030         if (el.hasOwnProperty('length')) {
20031             elem = el[0];
20032         }
20033
20034         var parent = elem.parentElement;
20035         var previousElem = undefined;
20036
20037         if(isFocusable) {
20038             if (hasValidParent(elem)) {
20039                 var siblings = angular.element(parent).children();
20040                 if (siblings.length > 0) {
20041                     // Good practice to splice out the elem from siblings if there, saving some time.
20042                     // We allow for a quick check for jumping to parent first before removing. 
20043                     if (siblings[0] === elem) {
20044                         // If we are looking at immidiate parent and elem is first child, we need to go higher
20045                         var e = _previousElement(angular.element(elem).parent(), isFocusable);
20046                         if (_isTabable(e)) {
20047                             return e;
20048                         }
20049                     } else {
20050                         // I need to filter myself and any nodes next to me from the siblings
20051                         var indexOfElem = Array.prototype.indexOf.call(siblings, elem);
20052                         siblings = Array.prototype.filter.call(siblings, function(item, itemIndex) {
20053                             if (!angular.equals(elem, item) && itemIndex < indexOfElem) {
20054                                 return true;
20055                             }
20056                         });
20057                     }
20058                     // We need to search backwards
20059                     for (var i = 0; i <= siblings.length-1; i++) {//for (var i = siblings.length-1; i >= 0; i--) {
20060                         var ret = traverse(siblings[i], false);
20061                         if (ret !== undefined) {
20062                             return ret;
20063                         }
20064                     }
20065
20066                     var e = _previousElement(angular.element(elem).parent(), isFocusable);
20067                     if (_isTabable(e)) {
20068                         return e;
20069                     }
20070                 }
20071             }
20072         } else {
20073             var siblings = angular.element(parent).children();
20074             if (siblings.length > 1) {
20075                 // Since indexOf is on Array.prototype and parent.children is a NodeList, we have to use call()
20076                 var index = Array.prototype.indexOf.call(siblings, elem);
20077                 previousElem = siblings[index-1];
20078             }
20079         }
20080         return previousElem;
20081     };
20082
20083     var _lastTabableElement = function(el) {
20084         /* This will return the first tabable element from the parent el */
20085         var elem = el;
20086         if (el.hasOwnProperty('length')) {
20087             elem = el[0];
20088         }
20089
20090         return traverse(elem, false);
20091     };
20092
20093     var _firstTabableElement = function(el) {
20094         /* This will return the first tabable element from the parent el */
20095         var elem = el;
20096         if (el.hasOwnProperty('length')) {
20097             elem = el[0];
20098         }
20099
20100         return traverse(elem, true);
20101     };
20102
20103     var _isInDOM = function(obj) {
20104       return document.documentElement.contains(obj);
20105     }
20106
20107     return {
20108         firstTabableElement: _firstTabableElement,
20109         lastTabableElement: _lastTabableElement,
20110         previousElement: _previousElement,
20111         isInDOM: _isInDOM,
20112         isTabable: _isTabable,
20113         isHidden: isHidden
20114     };
20115 })
20116
20117 .factory('trapFocusInElement', ['$document', '$isElement', 'DOMHelper', 'keymap', function ($document, $isElement, DOMHelper, keymap) {
20118     var elementStack = [];
20119     var stackHead = undefined;
20120     var trapFocusInElement = function (flag) {
20121         var bodyElements = $document.find('body').children();
20122
20123         var firstTabableElement = angular.element(DOMHelper.firstTabableElement(stackHead));
20124         var lastTabableElement = angular.element(DOMHelper.lastTabableElement(stackHead));
20125
20126         var trapKeyboardFocusInFirstElement = function (e) {
20127             if (!e.keyCode) {
20128                 e.keyCode = e.which;
20129             }
20130
20131             if (e.shiftKey === true && e.keyCode === keymap.KEY.TAB) {
20132                 lastTabableElement[0].focus();
20133                 e.preventDefault(e);
20134                 e.stopPropagation(e);
20135             }
20136
20137         };
20138
20139         var trapKeyboardFocusInLastElement = function (e) {
20140             if (!e.keyCode) {
20141                 e.keyCode = e.which;
20142             }
20143
20144             if (e.shiftKey === false && e.keyCode === keymap.KEY.TAB) {
20145                 firstTabableElement[0].focus();
20146                 e.preventDefault(e);
20147                 e.stopPropagation(e);
20148             }
20149         };
20150
20151         if (flag) {
20152             for (var i = 0; i < bodyElements.length; i++) {
20153                 if (bodyElements[i] !== stackHead[0]) {
20154                     bodyElements.eq(i).attr('aria-hidden', true);
20155                 }
20156             }
20157             firstTabableElement.bind('keydown', trapKeyboardFocusInFirstElement);
20158             lastTabableElement.bind('keydown', trapKeyboardFocusInLastElement);
20159         } else {
20160             for (var j = 0; j < bodyElements.length; j++) {
20161                 if (bodyElements[j] !== stackHead[0]) {
20162                     bodyElements.eq(j).removeAttr('aria-hidden');
20163                 }
20164             }
20165             firstTabableElement.unbind('keydown', trapKeyboardFocusInFirstElement);
20166             lastTabableElement.unbind('keydown', trapKeyboardFocusInLastElement);
20167         }
20168     };
20169     var toggleTrapFocusInElement = function (flag, element) {
20170         if (angular.isDefined(flag) && angular.isDefined(element)) {
20171             if (angular.isUndefined(stackHead)) {
20172                 stackHead = element;
20173                 trapFocusInElement(flag);
20174             } else {
20175                 if (flag) {
20176                     trapFocusInElement(false);
20177                     elementStack.push(stackHead);
20178                     stackHead = element;
20179                     trapFocusInElement(true);
20180                 } else {
20181                     if (stackHead.prop('$$hashKey') === element.prop('$$hashKey')) {
20182                         trapFocusInElement(false);
20183                         stackHead = elementStack.pop();
20184                         if (angular.isDefined(stackHead)) {
20185                             trapFocusInElement(true);
20186                         }
20187                     }
20188                 }
20189             }
20190         }
20191     };
20192
20193     return toggleTrapFocusInElement;
20194 }])
20195
20196 .factory('DOMHelper', function () {
20197
20198     var _isTabable = function (node) {
20199         var element = angular.element(node);
20200         var tagName = element[0].tagName.toUpperCase();
20201
20202         if (isHidden(element)) {
20203             return false;
20204         }
20205         if (element.attr('tabindex') !== undefined) {
20206             return (parseInt(element.attr('tabindex'), 10) >= 0);
20207         }
20208         if (tagName === 'A' || tagName === 'AREA' || tagName === 'BUTTON' || tagName === 'INPUT' || tagName === 'TEXTAREA' || tagName === 'SELECT') {
20209             if (tagName === 'A' || tagName === 'AREA') {
20210                 // anchors/areas without href are not focusable
20211                 return (element[0].href !== '');
20212             }
20213             return !(element[0].disabled || element[0].readOnly);
20214         }
20215         return false;
20216     };
20217
20218     function isValidChild(child) {
20219         return child.nodeType == 1 && child.nodeName != 'SCRIPT' && child.nodeName != 'STYLE';
20220     }
20221
20222     function isHidden(obj) {
20223         var elem = angular.element(obj);
20224         var style;
20225         try {
20226             style = window.getComputedStyle(obj);
20227         }
20228         catch(err) {
20229             style = window.getComputedStyle(obj[0]);
20230         }
20231
20232         // getComputedStyle() for Zepto object returns null
20233         if (style === null){
20234             return elem.hasClass('ng-hide') || elem.css('display') === 'none';
20235         }
20236
20237         return elem.hasClass('ng-hide') || elem.css('display') === 'none' || style.display === 'none' || style.display === 'hidden';
20238     }
20239
20240     function traverse(obj, fromTop) {
20241         var obj = obj || document.getElementsByTagName('body')[0];
20242
20243         if (isValidChild(obj) && _isTabable(obj)) {
20244             return obj;
20245         }
20246
20247         // If object is hidden, skip it's children
20248         if (isValidChild(obj) && isHidden(obj)) {
20249             return undefined;
20250         }
20251         // If object is hidden, skip it's children
20252         if (angular.element(obj).hasClass('ng-hide')) {
20253             return undefined;
20254         }
20255
20256         if (obj.hasChildNodes()) {
20257             var child;
20258             if (fromTop) {
20259                 child = obj.firstChild;
20260             } else {
20261                 child = obj.lastChild;
20262             }
20263             while (child) {
20264                 var res = traverse(child, fromTop);
20265                 if (res) {
20266                     return res;
20267                 } else {
20268                     if (fromTop) {
20269                         child = child.nextSibling;
20270                     } else {
20271                         child = child.previousSibling;
20272                     }
20273                 }
20274             }
20275         } else {
20276             return undefined;
20277         }
20278     }
20279
20280     var _lastTabableElement = function (el) {
20281         /* This will return the last tabable element from the parent el */
20282         var elem = el;
20283         if (el.hasOwnProperty('length')) {
20284             elem = el[0];
20285         }
20286
20287         return traverse(elem, false);
20288     };
20289
20290     var _firstTabableElement = function (el) {
20291         /* This will return the first tabable element from the parent el */
20292         var elem = el;
20293         if (el.hasOwnProperty('length')) {
20294             elem = el[0];
20295         }
20296
20297         return traverse(elem, true);
20298     };
20299
20300     return {
20301         firstTabableElement: _firstTabableElement,
20302         lastTabableElement: _lastTabableElement,
20303         isTabable: _isTabable
20304     };
20305 })
20306
20307 .factory('windowOrientation', ['$window', function ($window) {
20308     var _isPotrait = function () {
20309         if ($window.innerHeight > $window.innerWidth) {
20310             return true;
20311         } else {
20312             return false;
20313         }
20314     };
20315     var _isLandscape = function () {
20316         if ($window.innerHeight < $window.innerWidth) {
20317             return true;
20318         } else {
20319             return false;
20320         }
20321     };
20322
20323     return {
20324         isPotrait: _isPotrait,
20325         isLandscape: _isLandscape
20326     };
20327 }])
20328
20329 .directive('b2bNextElement', function() {
20330   return {
20331     restrict: 'A',
20332     transclude: false,
20333     link: function (scope, elem, attr, ctrls) {
20334
20335         var keys = attr.b2bNextElement.split(',');
20336
20337         elem.bind('keydown', function (e) {
20338             var nextElement = elem.next();
20339             if(e.keyCode == 39 || e.keyCode == 40){ // if e.keyCode in keys
20340                 if(nextElement.length) {
20341                     e.preventDefault();
20342                     nextElement[0].focus();
20343                 }
20344             }
20345         });
20346     }
20347   }
20348 })
20349
20350 .directive('b2bAccessibilityClick', [function () {
20351     return {
20352         restrict: 'A',
20353         link: function (scope, elem, attr, ctrl) {
20354             var keyCode = [];
20355             attr.$observe('b2bAccessibilityClick', function (value) {
20356                 if (value) {
20357                     keyCode = value.split(',');
20358                 }
20359             });
20360             elem.bind('keydown keypress', function (ev) {
20361                 var keyCodeCondition = function () {
20362                     var flag = false;
20363                     if (!(ev.keyCode)) {
20364                         if (ev.which) {
20365                             ev.keyCode = ev.which; 
20366                         } else if (ev.charCode) {
20367                             ev.keyCode = ev.charCode;
20368                         }
20369                     }
20370                     if ((ev.keyCode && keyCode.indexOf(ev.keyCode.toString()) > -1)) {
20371                         flag = true;
20372                     }
20373                     return flag;
20374                 };
20375                 if (keyCode.length > 0 && keyCodeCondition()) {
20376                     elem[0].click();
20377                     ev.preventDefault();
20378                 }
20379             });
20380         }
20381     };
20382 }])
20383
20384 .directive('b2bReset', ['$compile', function ($compile) {
20385         return {
20386             restrict: 'A',
20387             require: ['?ngModel', 'b2bReset'],
20388             controller: ['$scope', function ($scope) {
20389                 var resetButton = angular.element('<button type="button" class="reset-field" tabindex="-1" aria-label="Click to reset" aria-hidden="true" role="button"></button>');
20390
20391                 this.getResetButton = function () {
20392                     return resetButton;
20393                 };
20394             }],
20395             link: function (scope, element, attrs, ctrls) {
20396
20397                 var ngModelCtrl = ctrls[0];
20398                 var ctrl = ctrls[1];
20399
20400                 var resetButton = ctrl.getResetButton();
20401
20402
20403                 resetButton.on('click', function () {
20404                     element[0].value = '';
20405
20406                     if (ngModelCtrl) {
20407                         if (attrs.b2bReset) {
20408                             ngModelCtrl.$setViewValue(attrs.b2bReset);
20409                         } else {
20410                             ngModelCtrl.$setViewValue('');
20411                         }
20412                         element[0].value = ngModelCtrl.$viewValue;
20413                         ngModelCtrl.$render();
20414                         scope.$digest();
20415                     }
20416                     element[0].focus();
20417                     element[0].select();
20418                 });
20419
20420                 var addResetButton = function () {
20421                     element.after(resetButton);
20422                     element.unbind('focus input', addResetButton);
20423                 };
20424
20425                 element.bind('focus input', addResetButton);
20426             }
20427         };
20428     }])
20429
20430 .directive('b2bPrevElement', ['b2bDOMHelper', 'keymap', function (b2bDOMHelper, keymap) {
20431   return {
20432     restrict: 'A',
20433     transclude: false,
20434     link: function (scope, elem, attr) {
20435
20436         elem.bind('keydown', function (e) {
20437             if(e.keyCode == 37 || e.keyCode == 38){
20438                 var prev = b2bDOMHelper.previousElement(elem, false);
20439                 if(prev !== undefined) {
20440                     e.preventDefault();
20441                     prev.focus();
20442                 }
20443             }
20444         });
20445     }
20446   }
20447 }])
20448 /**
20449  * @param {integer} delay - Timeout before first and last focusable elements are found
20450  * @param {boolean} trigger - A variable on scope that will trigger refinding first/last focusable elements 
20451  */
20452 .directive('b2bTrapFocusInsideElement', ['$timeout', 'b2bDOMHelper', 'keymap', 'events', function ($timeout, b2bDOMHelper, keymap, events) {
20453     return {
20454         restrict: 'A',
20455         transclude: false,
20456         link: function (scope, elem, attr) {
20457
20458             var delay = parseInt(attr.delay, 10) || 10;
20459
20460             /* Before opening modal, find the focused element */
20461             var firstTabableElement = undefined,
20462                 lastTabableElement = undefined;
20463                 
20464             function init() {
20465                 $timeout(function () {
20466                     firstTabableElement = b2bDOMHelper.firstTabableElement(elem);
20467                     lastTabableElement = b2bDOMHelper.lastTabableElement(elem);
20468                     angular.element(firstTabableElement).bind('keydown', firstTabableElementKeyhandler);
20469                     angular.element(lastTabableElement).bind('keydown', lastTabableElementKeyhandler);
20470                 }, delay, false);
20471             }
20472
20473             if (attr.trigger !== undefined) {
20474                 scope.$watch('trigger', function() {
20475                     if (scope.trigger) {
20476                         init();
20477                     }
20478                 });
20479             }
20480
20481             var firstTabableElementKeyhandler = function(e) {
20482                 if (!e.keyCode) {
20483                     e.keyCode = e.which;
20484                 }
20485                 if (e.keyCode === keymap.KEY.TAB && e.shiftKey) {
20486                     if (attr.trapFocusInsideElement === 'true') {
20487                         var temp = b2bDOMHelper.lastTabableElement(elem);
20488                         if (lastTabableElement !== temp) {
20489                             // Unbind keydown handler on lastTabableElement
20490                             angular.element(lastTabableElement).unbind('keydown', lastTabableElementKeyhandler);
20491                             lastTabableElement = temp;
20492                             angular.element(lastTabableElement).bind('keydown', lastTabableElementKeyhandler);
20493                         }
20494                     }
20495                     lastTabableElement.focus();
20496                     events.preventDefault(e);
20497                     events.stopPropagation(e);
20498                 }
20499             };
20500
20501             var lastTabableElementKeyhandler = function(e) {
20502                 if (!e.keyCode) {
20503                     e.keyCode = e.which;
20504                 }
20505                 if (e.keyCode === keymap.KEY.TAB && !e.shiftKey) {
20506                     if (attr.trapFocusInsideElement === 'true') {
20507                         var temp = b2bDOMHelper.firstTabableElement(elem);
20508                         if (firstTabableElement !== temp) {
20509                             // Unbind keydown handler on firstTabableElement
20510                             angular.element(firstTabableElement).unbind('keydown', firstTabableElementKeyhandler);
20511                             firstTabableElement = temp;
20512                             angular.element(firstTabableElement).bind('keydown', firstTabableElementKeyhandler);
20513                         }
20514                     }
20515                     firstTabableElement.focus();
20516                     events.preventDefault(e);
20517                     events.stopPropagation(e);
20518                 }
20519             };
20520
20521             init();
20522         }
20523     };
20524 }])
20525
20526 .factory('trapFocusInElement', ['$document', '$isElement', 'DOMHelper', 'keymap', '$interval', function ($document, $isElement, DOMHelper, keymap, $interval) {
20527     var elementStack = [];
20528     var stackHead = undefined;
20529     var stopInterval = undefined;
20530     var intervalRequired = false;
20531     var interval = 1000;
20532     var firstTabableElement, lastTabableElement;
20533
20534     var trapKeyboardFocusInFirstElement = function (e) {
20535         if (!e.keyCode) {
20536             e.keyCode = e.which;
20537         }
20538
20539         if (e.shiftKey === true && e.keyCode === keymap.KEY.TAB) {
20540             lastTabableElement[0].focus();
20541             e.preventDefault(e);
20542             e.stopPropagation(e);
20543         }
20544
20545     };
20546
20547     var trapKeyboardFocusInLastElement = function (e) {
20548         if (!e.keyCode) {
20549             e.keyCode = e.which;
20550         }
20551
20552         if (e.shiftKey === false && e.keyCode === keymap.KEY.TAB) {
20553             firstTabableElement[0].focus();
20554             e.preventDefault(e);
20555             e.stopPropagation(e);
20556         }
20557     };
20558
20559     var trapFocusInElement = function (flag, firstTabableElementParam, lastTabableElementParam) {
20560         var bodyElements = $document.find('body').children();
20561
20562         firstTabableElement = firstTabableElementParam ? firstTabableElementParam : angular.element(DOMHelper.firstTabableElement(stackHead));
20563         lastTabableElement = lastTabableElementParam ? lastTabableElementParam : angular.element(DOMHelper.lastTabableElement(stackHead));
20564
20565         if (flag) {
20566             for (var i = 0; i < bodyElements.length; i++) {
20567                 if (bodyElements[i] !== stackHead[0]) {
20568                     bodyElements.eq(i).attr('aria-hidden', true);
20569                 }
20570             }
20571             firstTabableElement.bind('keydown', trapKeyboardFocusInFirstElement);
20572             lastTabableElement.bind('keydown', trapKeyboardFocusInLastElement);
20573         } else {
20574             for (var j = 0; j < bodyElements.length; j++) {
20575                 if (bodyElements[j] !== stackHead[0]) {
20576                     bodyElements.eq(j).removeAttr('aria-hidden');
20577                 }
20578             }
20579             firstTabableElement.unbind('keydown', trapKeyboardFocusInFirstElement);
20580             lastTabableElement.unbind('keydown', trapKeyboardFocusInLastElement);
20581         }
20582
20583         if (intervalRequired && flag) {
20584             stopInterval = $interval(function () {
20585                 var firstTabableElementTemp = angular.element(DOMHelper.firstTabableElement(stackHead));
20586                 var lastTabableElementTemp = angular.element(DOMHelper.lastTabableElement(stackHead));
20587                 if (firstTabableElementTemp[0] !== firstTabableElement[0] || lastTabableElementTemp[0] !== lastTabableElement[0]) {
20588                     $interval.cancel(stopInterval);
20589                     stopInterval = undefined;
20590                     trapFocusInElement(false, firstTabableElement, lastTabableElement);
20591                     trapFocusInElement(true, firstTabableElementTemp, lastTabableElementTemp);
20592                 }
20593             }, interval);
20594         } else {
20595             if (stopInterval) {
20596                 $interval.cancel(stopInterval);
20597                 stopInterval = undefined;
20598             }
20599         }
20600     };
20601     var toggleTrapFocusInElement = function (flag, element, intervalRequiredParam, intervalParam) {
20602         intervalRequired = intervalRequiredParam ? intervalRequiredParam : intervalRequired;
20603         interval = intervalParam ? intervalParam : interval;
20604         if (angular.isDefined(flag) && angular.isDefined(element)) {
20605             if (flag && angular.isUndefined(stackHead)) {
20606                 stackHead = element;
20607                 trapFocusInElement(flag);
20608             } else {
20609                 if (flag) {
20610                     trapFocusInElement(false);
20611                     elementStack.push(stackHead);
20612                     stackHead = element;
20613                     trapFocusInElement(true);
20614                 } else {
20615                     if (angular.isDefined(stackHead) && (stackHead[0] === element[0])) {
20616                         trapFocusInElement(false);
20617                         stackHead = elementStack.pop();
20618                         if (angular.isDefined(stackHead)) {
20619                             trapFocusInElement(true);
20620                         }
20621                     }
20622                 }
20623             }
20624         } else {
20625             if (angular.isDefined(stackHead)) {
20626                 trapFocusInElement(false, firstTabableElement, lastTabableElement);
20627                 trapFocusInElement(true);
20628             }
20629         }
20630     };
20631
20632     return toggleTrapFocusInElement;
20633 }])
20634
20635 .directive('b2bSetNextFocusOn', ['b2bDOMHelper', '$timeout', function(b2bDOMHelper, $timeout) {
20636     return {
20637         restrict: 'A',
20638         scope: true,
20639         link: function (scope, elem, attr) {
20640             elem.bind('click', function(){
20641                 var firstFocusableElement = undefined; 
20642                 var containerElem = undefined; 
20643                 var containerArray = [];
20644                 var timeout = parseInt(attr.setNextFocusTimeout, 0) | 100;
20645                 var index = parseInt(attr.b2bSetNextFocusIndex, 0) | 0;
20646
20647                  /*
20648                   *Fix for IE7 and lower 
20649                   *polyfill src: https://github.com/HubSpot/pace/issues/102
20650                   */
20651                 if (!document.querySelectorAll) {
20652                     document.querySelectorAll = function (selectors) {
20653                         var style = document.createElement('style'), elements = [], element;
20654                         document.documentElement.firstChild.appendChild(style);
20655                         document._qsa = [];
20656
20657                         style.styleSheet.cssText = selectors + '{x-qsa:expression(document._qsa && document._qsa.push(this))}';
20658                         window.scrollBy(0, 0);
20659                         style.parentNode.removeChild(style);
20660
20661                         while (document._qsa.length) {
20662                             element = document._qsa.shift();
20663                             element.style.removeAttribute('x-qsa');
20664                             elements.push(element);
20665                         }
20666                         document._qsa = null;
20667                         return elements;
20668                     };
20669                 }
20670
20671                 if (attr.b2bSetNextFocusOn === '') {
20672                     return;
20673                 } else {
20674                     containerArray = attr.b2bSetNextFocusOn.split(' ');
20675                 }
20676                 $timeout(function(){
20677                     var i = 0;
20678                     do { // cycles thru containerArray until finds a match in DOM to set focus to
20679                         containerElem = document.querySelectorAll(containerArray[i])[index]; 
20680                         i++;
20681                     } while ( (!containerElem) && (i < containerArray.length) );
20682                     if(containerElem){
20683                         if (!angular.isDefined(firstFocusableElement)) { 
20684                             firstFocusableElement = b2bDOMHelper.firstTabableElement(containerElem); 
20685                         }
20686                         firstFocusableElement.focus(); 
20687                     }
20688                 }, timeout, false)
20689             });
20690         }
20691
20692     };
20693 }])
20694
20695 .directive('b2bInputAllow', [function() {
20696     return {
20697         restrict: 'A',
20698         require: 'ngModel',
20699         link: function (scope, elem, attr, ctrl) {
20700             var regexExpression = null;
20701             attr.$observe('b2bInputAllow', function (value) {
20702                 if (value) {
20703                     regexExpression = new RegExp(value);
20704                 }
20705             });
20706             var isValid = function(str) {
20707                 if (regexExpression !== null) {
20708                     return regexExpression.test(str);
20709                 }
20710                 return false;
20711             };
20712             elem.bind('keypress', function($event) {
20713                 var charcode = String.fromCharCode($event.which || $event.keyCode);
20714                 if (!isValid(charcode)) {
20715                     $event.preventDefault();
20716                     $event.stopPropagation();
20717                 }
20718             });
20719             elem.bind('input', function (evt) {
20720                 var inputString = ctrl.$viewValue;
20721                 if (isValid(inputString)) {
20722                     ctrl.$setViewValue(inputString);
20723                     ctrl.$render();
20724                     scope.$apply();
20725                 }
20726             });
20727         }
20728     };
20729 }])
20730
20731 .directive('b2bInputDeny', [function() {
20732     return {
20733         restrict: 'A',
20734         require: 'ngModel',
20735         link: function (scope, elem, attr, ctrl) {
20736             var regexExpression = null;
20737             attr.$observe('b2bInputDeny', function (value) {
20738                 if (value) {
20739                     regexExpression = new RegExp(value, 'g');
20740                 }
20741             });
20742             elem.bind('input', function () {
20743                 var inputString = ctrl.$viewValue && ctrl.$viewValue.replace(regexExpression, '');
20744                 if (inputString !== ctrl.$viewValue) {
20745                     ctrl.$setViewValue(inputString);
20746                     ctrl.$render();
20747                     scope.$apply();
20748                 }
20749             });
20750         }
20751     };
20752 }])
20753
20754 .directive('b2bDragonInput', [function() {
20755     return {
20756         restrict: 'A',
20757         require: 'ngModel',
20758         link: function (scope, elem, attr, ctrl) {
20759             elem.on('focus keyup', function(){
20760                 elem.triggerHandler('change');
20761             });
20762         }
20763     };
20764 }])
20765
20766 .directive('b2bKey', ['b2bUtilitiesConfig', '$timeout', 'keymap', function (b2bUtilitiesConfig, $timeout, keymap) {
20767     return {
20768         restrict: 'EA',
20769         controller: ['$scope', '$element', '$attrs', function ($scope, $element,attr) {
20770             this.childElements = [];
20771             this.disableNodes = {};
20772             this.enableSearch = attr.enableSearch !== undefined ? true : b2bUtilitiesConfig.enableSearch;
20773             this.circularTraversal = attr.circularTraversal !== undefined ? true : b2bUtilitiesConfig.circularTraversal;
20774             this.counter = -1;
20775             if (this.enableSearch) {
20776                 this.searchKeys = [];
20777             }
20778             var searchString = '';
20779
20780             var selfCtrl = this;
20781
20782             this.childElementsList = [];
20783
20784             this.b2bKeyID = "";
20785
20786             if (angular.isDefined(attr.b2bKey)) {
20787                 this.b2bKeyID = attr.b2bKey;
20788             }
20789
20790             this.calculateChildElementsList = function () {
20791                 return $element[0].querySelectorAll("[b2b-key-item='" + this.b2bKeyID + "']:not([disabled])");
20792             };
20793
20794             this.resetChildElementsList = function () {
20795                 return $timeout(function () {
20796                     selfCtrl.childElementsList = selfCtrl.calculateChildElementsList();
20797                 });
20798             };
20799
20800             this.resetChildElementsList();
20801
20802             $scope.$on('b2b-key-reset-child-elements-list', function () {
20803                 selfCtrl.resetChildElementsList();
20804             });
20805
20806
20807             this.registerElement = function (childElement, searchKey) {
20808                 this.childElements.push(childElement);
20809                 if (this.enableSearch) {
20810                     this.searchKeys.push(searchKey);
20811                 }
20812                 var count = this.childElements.length - 1;
20813                 this.maxLength = count + 1;
20814                 return count;
20815             };
20816             this.toggleDisable = function (count, state) {
20817                 this.disableNodes[count] = state;
20818             };
20819             this.searchElement = function (searchExp) {
20820                 var regex = new RegExp("\\b" + searchExp, "gi");
20821                 var position = this.searchKeys.regexIndexOf(regex, this.counter + 1, true);
20822                 if (position > -1) {
20823                     this.counter = position;
20824                     this.moveFocus(this.counter);
20825                 }
20826             };
20827             this.startTimer = function (time) {
20828                 if (searchString === '') {
20829                     $timeout(function () {
20830                         searchString = '';
20831                     }, time);
20832                 }
20833             };
20834             this.resetCounter = function (count) {
20835                 this.counter = count;
20836             };
20837             this.moveNext = function (count) {
20838                 this.counter = (this.counter + count) < this.maxLength ? this.counter + count : (this.circularTraversal ? 0 : this.counter);
20839                 if (this.disableNodes[this.counter]) {
20840                     if ((this.counter + count) < this.maxLength) {
20841                         this.moveNext(count);
20842                     }
20843                 } else {
20844                     this.moveFocus(this.counter);
20845                 }
20846             };
20847             this.movePrev = function (count) {
20848                 this.counter = (this.counter - count) > -1 ? this.counter - count : (this.circularTraversal ? this.maxLength-1 : this.counter);
20849                 if (this.disableNodes[this.counter]) {
20850                     if ((this.counter - count) > -1) {
20851                         this.movePrev(count);
20852                     }
20853                 } else {
20854                     this.moveFocus(this.counter);
20855                 }
20856             };
20857             this.moveFocus = function (index) {
20858                 this.childElements[index][0].focus();
20859             };
20860
20861             this.keyDownHandler = function (ev, count) {
20862                 if (angular.isDefined(count) && !isNaN(count) && count !== this.counter) {
20863                     this.resetCounter(count);
20864                 }
20865                 if (!ev.keyCode) {
20866                     if (ev.which) {
20867                         ev.keyCode = ev.which;
20868                     } else if (ev.charCode) {
20869                         ev.keyCode = ev.charCode;
20870                     }
20871                 }
20872                 if (ev.keyCode) {
20873                     if (this.prev && this.prev.indexOf(ev.keyCode.toString()) > -1) {
20874                         this.movePrev(1);
20875                         ev.preventDefault();
20876                         ev.stopPropagation();
20877                     } else if (this.next && this.next.indexOf(ev.keyCode.toString()) > -1) {
20878                         this.moveNext(1);
20879                         ev.preventDefault();
20880                         ev.stopPropagation();
20881                     } else if (this.up && this.up.indexOf(ev.keyCode.toString()) > -1) {
20882                         if (this.type === 'table') {
20883                             this.movePrev(this.columns);
20884                             ev.preventDefault();
20885                             ev.stopPropagation();
20886                         }
20887                     } else if (this.down && this.down.indexOf(ev.keyCode.toString()) > -1) {
20888                         if (this.type === 'table') {
20889                             this.moveNext(this.columns);
20890                             ev.preventDefault();
20891                             ev.stopPropagation();
20892                         }
20893                     } else if (ev.keyCode === keymap.KEY.HOME) {
20894                         var firstIndex = 0;
20895                         while (this.disableNodes[firstIndex] !== false) {
20896                             firstIndex++;
20897                         };
20898                         var count = this.counter - firstIndex;
20899                         this.movePrev(count);
20900                         ev.preventDefault();
20901                         ev.stopPropagation();
20902                     } else if (ev.keyCode === keymap.KEY.END) {
20903                         var lastIndex = this.childElements.length - 1;
20904                         while (this.disableNodes[lastIndex] !== false) {
20905                             lastIndex--;
20906                         };
20907                         var count = lastIndex - this.counter;
20908                         this.moveNext(count);
20909                         ev.preventDefault();
20910                         ev.stopPropagation();
20911                     } else if (ev.keyCode >= 48 && ev.keyCode <= 105) {
20912                         if (this.enableSearch) {
20913                             this.startTimer(b2bUtilitiesConfig.searchTimer);
20914                             searchString = searchString + (keymap.MAP[ev.keyCode] || '');
20915                             this.searchElement(searchString);
20916                             ev.preventDefault();
20917                             ev.stopPropagation();
20918                         }
20919                     }
20920                 }
20921             };
20922         }],
20923         link: function (scope, elem, attr, ctrl) {
20924             ctrl.prev = attr.prev ? attr.prev.split(',') : b2bUtilitiesConfig.prev.split(',');
20925             ctrl.next = attr.next ? attr.next.split(',') : b2bUtilitiesConfig.next.split(',');
20926             ctrl.type = attr.type ? attr.type : b2bUtilitiesConfig.type;
20927             if (ctrl.type === 'table') {
20928                 ctrl.up = attr.up ? attr.up.split(',') : b2bUtilitiesConfig.up.split(',');
20929                 ctrl.down = attr.down ? attr.down.split(',') : b2bUtilitiesConfig.down.split(',');
20930                 ctrl.columns = attr.columns ? parseInt(attr.columns, 10) : b2bUtilitiesConfig.columns;
20931             }
20932
20933             elem.bind('keydown', function (ev) {
20934                 ctrl.keyDownHandler(ev);
20935             });
20936         }
20937     };
20938 }])
20939
20940 .directive('b2bKeyItem', [function () {
20941     return {
20942         restrict: 'EA',
20943         link: function (scope, elem, attr, ctrl) {
20944             var parentCtrl = (elem.parent() && elem.parent().controller('b2bKey')) || undefined;
20945             if (angular.isDefined(parentCtrl)) {
20946                 var count = parentCtrl.registerElement(elem, attr.searchKey);
20947                 elem.bind('keydown', function (ev) {
20948                     parentCtrl.keyDownHandler(ev, count);
20949                 });
20950                 scope.$watch(attr.b2bKeyItem, function (value) {
20951                     value = value === undefined ? true : value;
20952                     parentCtrl.toggleDisable(count, !value); 
20953                 });
20954                 scope.$on('$destroy', function () {
20955                     parentCtrl.toggleDisable(count, true);
20956                 });
20957             }
20958         }
20959     };
20960 }])
20961
20962 .directive('b2bElementFocus', [function () {
20963     return {
20964         restrict: 'A',
20965         link: function (scope, elem, attr, ctrl) {
20966             scope.$watch(attr.b2bElementFocus, function (value) {
20967                 if (value === true) {
20968                     elem[0].focus();
20969                 }
20970             });
20971         }
20972     };
20973 }])
20974
20975
20976 .directive('b2bAppendElement', ['$compile', function ($compile) {
20977     return {
20978         restrict: 'A',
20979         link: function (scope, elem, attr, ctrl) {
20980             var parameters = attr.b2bAppendElement.split(':');
20981             if (parameters.length === 1) {
20982                 elem.append(scope.$eval(parameters[0]));
20983             } else if (parameters.length === 2) {
20984                 if (parameters[1] === 'compile') {
20985                     var element = angular.element('<span>' + scope.$eval(parameters[0]) + '</span>');
20986                     elem.append($compile(element)(scope));
20987                 }
20988             }
20989
20990         }
20991     };
20992 }])
20993
20994 .directive('b2bKeyItemRefreshInNgRepeat', [function () {
20995     return {
20996         restrict: 'EA',
20997         require: '^^b2bKey',
20998         link: function (scope, elem, attr, parentCtrl) {
20999             if (angular.isDefined(parentCtrl)) {
21000
21001                 var attrToObserve = 'attrToObserve';
21002
21003                 if (attr.b2bKeyItemRefreshInNgRepeat) {
21004                     attrToObserve = 'b2bKeyItemRefreshInNgRepeat';
21005                 }
21006
21007                 attr.$observe(attrToObserve, function (newVal, oldVal) {
21008                     if (newVal && newVal !== oldVal) {
21009                         parentCtrl.resetChildElementsList();
21010                     }
21011                 });
21012             }
21013         }
21014     };
21015 }])
21016
21017 .filter('b2bMultiSepartorHighlight', function($sce) {
21018         return function(text, searchText, searchSeperator) {
21019             var splitText = function(string) {
21020                 if(angular.isDefined(searchSeperator)){
21021                     if (string.indexOf(searchSeperator) > -1) {
21022                         return string.split(searchSeperator);
21023                     } else {
21024                         return string
21025                     }
21026                 }else{
21027                     return string;
21028                 }
21029             }
21030             if (text) {
21031                 var newText = splitText(text);
21032                 var newPhrase = splitText(searchText);
21033                 if (angular.isArray(newPhrase)) {
21034                     for (var i = 0; i < newText.length; i++) {
21035                         if (i <= 0) {
21036                             text = newText[i].replace(new RegExp('(' + newPhrase[i] + ')', 'gi'),
21037                                 '<span class="b2b-search-hightlight">$1</span>');
21038                         } else {
21039                             text = text + searchSeperator + ' ' + (newPhrase[i] ? newText[i].replace(new RegExp('(' + newPhrase[i] + ')', 'gi'),
21040                                 '<span class="b2b-search-hightlight">$1</span>') : newText[i]);
21041                         }
21042                     }
21043                 } else {
21044                     text = text.replace(new RegExp('(' + searchText + ')', 'gi'),
21045                         '<span class="b2b-search-hightlight">$1</span>');
21046                 }
21047             }
21048             return $sce.trustAsHtml(text)
21049         }
21050     })
21051     
21052     .factory('b2bUserAgent', [function() {
21053         var _isMobile = function() {
21054             return /Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
21055         };
21056         var _notMobile = function() {
21057             return !/Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
21058         };
21059         var _isIE = function() {
21060             return /msie|trident/i.test(navigator.userAgent);
21061         };
21062         var _isFF = function() {
21063             return /Firefox/.test(navigator.userAgent);
21064         };
21065         var _isChrome = function() {
21066             return /Google Inc/.test(navigator.vendor);
21067         };
21068         var _isSafari = function() {
21069             return /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent);
21070         };
21071
21072         return {
21073             isMobile: _isMobile,
21074             notMobile: _notMobile,
21075             isIE: _isIE,
21076             isFF: _isFF,
21077             isChrome: _isChrome,
21078             isSafari: _isSafari
21079         };
21080     }])
21081     .run(['$document', 'b2bUserAgent', function($document, b2bUserAgent) {
21082         var html = $document.find('html').eq(0);
21083         if (b2bUserAgent.isIE()) {
21084             html.addClass('isIE');
21085         } else {
21086             html.removeClass('isIE');
21087         }
21088     }]);
21089     
21090
21091 (function () {
21092     String.prototype.toSnakeCase = function () {
21093         return this.replace(/([A-Z])/g, function ($1) {
21094             return "-" + $1.toLowerCase();
21095         });
21096     };
21097     var concat = function (character, times) {
21098         character = character || '';
21099         times = (!isNaN(times) && times) || 0;
21100         var finalChar = '';
21101         for (var i = 0; i < times; i++) {
21102             finalChar += character;
21103         }
21104         return finalChar;
21105     };
21106
21107     // direction: true for left and false for right
21108     var pad = function (actualString, width, character, direction) {
21109         actualString = actualString || '';
21110         width = (!isNaN(width) && width) || 0;
21111         character = character || '';
21112         if (width > actualString.length) {
21113             if (direction) {
21114                 return concat(character, (width - actualString.length)) + actualString;
21115             } else {
21116                 return actualString + concat(character, (width - actualString.length));
21117             }
21118         }
21119         return actualString;
21120     };
21121
21122     String.prototype.lPad = function (width, character) {
21123         return pad(this, width, character, true);
21124     };
21125
21126     String.prototype.rPad = function (width, character) {
21127         return pad(this, width, character, false);
21128     };
21129
21130     if (!Array.prototype.indexOf) {
21131         Array.prototype.indexOf = function (val) {
21132             for (var index = 0; index < this.length; index++) {
21133                 if (this[index] === val) {
21134                     return index;
21135                 }
21136             }
21137             return -1;
21138         };
21139     }
21140
21141     if (!Array.prototype.regexIndexOf) {
21142         Object.defineProperty(Array.prototype, 'regexIndexOf', {
21143             enumerable: false,
21144             value: function (regex, startIndex, loop) {
21145                 startIndex = startIndex && startIndex > -1 ? startIndex : 0;
21146                 for (var index = startIndex; index < this.length; index++) {
21147                     if (this[index].toString().match(regex)) {
21148                         return index;
21149                     }
21150                 }
21151                 if (loop) {
21152                     for (var index = 0; index < startIndex; index++) {
21153                         if (this[index].toString().match(regex)) {
21154                             return index;
21155                         }
21156                     }
21157                 }
21158                 return -1;
21159             }
21160         })
21161     }
21162 })();
21163 angular.module("b2bTemplate/audioPlayer/audioPlayer.html", []).run(["$templateCache", function($templateCache) {
21164   $templateCache.put("b2bTemplate/audioPlayer/audioPlayer.html",
21165     "<div class=\"b2b-audio\">\n" +
21166     "   <audio preload=\"auto\">\n" +
21167     "       <source ng-src=\"{{audio.mp3 | trustedAudioUrl}}\" type=\"audio/mp3\"></source>\n" +
21168     "       <i>Your browser does not support the audio element.</i>\n" +
21169     "    </audio>\n" +
21170     "\n" +
21171     "    <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" +
21172     "       <i class=\"icoControls-pointer\" ng-show='!isPlayInProgress'></i>\n" +
21173     "       <i class=\"icoControls-pause\" ng-show='isPlayInProgress'></i>\n" +
21174     "    </div>\n" +
21175     "\n" +
21176     "    <div class=\"seek-bar-container-wrapper\">\n" +
21177     "       <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" +
21178     "       <div class=\"timing-container\">\n" +
21179     "           <span class=\"timing-container-left\">{{timeFormatter(audio.currentTime)}}</span>\n" +
21180     "           <span class=\"timing-container-right\">{{timeFormatter(audio.duration)}}</span>\n" +
21181     "           <div class=\"timing-container-spacer\"></div>\n" +
21182     "       </div>\n" +
21183     "    </div>\n" +
21184     "       \n" +
21185     "    <b2b-flyout>\n" +
21186     "       <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" +
21187     "           <i class=\"icoControls-mutespeakers\" ng-show=\"audio.currentVolume === 0\"></i>\n" +
21188     "           <i class=\"icoControls-volumedown\" ng-show=\"audio.currentVolume > 0 && audio.currentVolume <= 50\"></i>\n" +
21189     "           <i class=\"icoControls-volumeup\" ng-show=\"audio.currentVolume > 50\"></i>\n" +
21190     "       </div> \n" +
21191     "       \n" +
21192     "       <b2b-flyout-content horizontal-placement=\"center\" flyout-style=\"width:70px; height:190px;\" vertical-placement=\"above\">\n" +
21193     "           <div class=\"b2b-audio-popover text-center\">\n" +
21194     "               <span>Max</span>\n" +
21195     "               <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" +
21196     "               <div class=\"min-label\">Min</div>\n" +
21197     "           </div>\n" +
21198     "       </b2b-flyout-content>\n" +
21199     "   </b2b-flyout>\n" +
21200     "</div>");
21201 }]);
21202
21203 angular.module("b2bTemplate/audioRecorder/audioRecorder.html", []).run(["$templateCache", function($templateCache) {
21204   $templateCache.put("b2bTemplate/audioRecorder/audioRecorder.html",
21205     "<div class=\"b2b-audio-recorder row\">\n" +
21206     "   <div class=\"b2b-elapsed-time span11\">\n" +
21207     "       <div ng-if=\"isRecording\">\n" +
21208     "           <span style=\"padding-right: 25px;\">{{config.whileRecordingMessage}}</span>\n" +
21209     "           <span>{{timeFormatter(elapsedTime)}}</span>\n" +
21210     "       </div>\n" +
21211     "       <span ng-if=\"!isRecording\">{{config.startRecordingMessage}}</span>\n" +
21212     "   </div>      \n" +
21213     "   <div class=\"b2b-controls\" title=\"{{isRecording ? 'Stop' : 'REC'}}\" b2b-accessibility-click=\"13,32\" ng-click=\"toggleRecording()\" role=\"button\">\n" +
21214     "           <i ng-if=\"isRecording\" class=\"icoControls-stop\" ></i>\n" +
21215     "           <i ng-if=\"!isRecording\" class=\"icoControls-record\"></i>\n" +
21216     "    </div>\n" +
21217     "</div>");
21218 }]);
21219
21220 angular.module("b2bTemplate/backToTop/backToTop.html", []).run(["$templateCache", function($templateCache) {
21221   $templateCache.put("b2bTemplate/backToTop/backToTop.html",
21222     "<button class=\"btn-arrow b2b-backtotop-button\" type=\"button\" aria-label=\"Back to top\">\n" +
21223     "    <div class=\"btn-secondary b2b-top-btn\">\n" +
21224     "        <i class=\"icoControls-upPRIMARY\" role=\"img\"></i>\n" +
21225     "    </div>\n" +
21226     "</button>\n" +
21227     "");
21228 }]);
21229
21230 angular.module("b2bTemplate/boardstrip/b2bAddBoard.html", []).run(["$templateCache", function($templateCache) {
21231   $templateCache.put("b2bTemplate/boardstrip/b2bAddBoard.html",
21232     "<div tabindex=\"0\" role=\"menuitem\" b2b-accessibility-click=\"13,32\" ng-click=\"addBoard()\" aria-label=\"Add Board\" class=\"boardstrip-item--add\">\n" +
21233     "    <div class=\"centered\"><i aria-hidden=\"true\" class=\"icoControls-add-maximize\"></i> Add board</div>\n" +
21234     "</div> ");
21235 }]);
21236
21237 angular.module("b2bTemplate/boardstrip/b2bBoard.html", []).run(["$templateCache", function($templateCache) {
21238   $templateCache.put("b2bTemplate/boardstrip/b2bBoard.html",
21239     "<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" +
21240     "    <div ng-transclude></div>\n" +
21241     "    <div class=\"board-caret\" ng-if=\"getCurrentIndex()===boardIndex\">\n" +
21242     "        <div class=\"board-caret-indicator\"></div>\n" +
21243     "        <div class=\"board-caret-arrow-up\"></div>\n" +
21244     "    </div>\n" +
21245     "</li>");
21246 }]);
21247
21248 angular.module("b2bTemplate/boardstrip/b2bBoardstrip.html", []).run(["$templateCache", function($templateCache) {
21249   $templateCache.put("b2bTemplate/boardstrip/b2bBoardstrip.html",
21250     "<div class=\"b2b-boardstrip\">\n" +
21251     "   <div class=\"boardstrip-reel\" role=\"menu\">\n" +
21252     "       <div class=\"prev-items\">\n" +
21253     "           <!-- <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" +
21254     "           <button class=\"btn-arrow arrow\" b2b-accessibility-click=\"13,32\" ng-click=\"prevBoard()\" ng-disabled=\"!isPrevBoard()\">\n" +
21255     "               <div class=\"btn btn-small btn-alt\"><i class=\"icon-primary-left\"></i>\n" +
21256     "               </div>\n" +
21257     "               <span class=\"offscreen-text\">Previous boards</span>\n" +
21258     "           </button>\n" +
21259     "       </div>\n" +
21260     "       <div b2b-add-board on-add-board=\"onAddBoard()\"></div>\n" +
21261     "       <div class=\"board-viewport\"><ul role=\"menu\" class=\"boardstrip-container\" ng-transclude></ul></div>\n" +
21262     "       <div class=\"next-items\">\n" +
21263     "           <!-- <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" +
21264     "           <button class=\"btn-arrow arrow\" b2b-accessibility-click=\"13,32\" ng-click=\"nextBoard()\" ng-disabled=\"!isNextBoard()\">\n" +
21265     "               <div class=\"btn btn-small btn-alt\"><i class=\"icon-primary-right\"></i>\n" +
21266     "               </div>\n" +
21267     "               <span class=\"offscreen-text\">Next boards</span>\n" +
21268     "           </button>\n" +
21269     "       </div>\n" +
21270     "   </div>\n" +
21271     "</div>\n" +
21272     "");
21273 }]);
21274
21275 angular.module("b2bTemplate/calendar/datepicker-popup.html", []).run(["$templateCache", function($templateCache) {
21276   $templateCache.put("b2bTemplate/calendar/datepicker-popup.html",
21277     "<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" +
21278     "    <div class=\"datepicker-days\" style=\"display: block;\">\n" +
21279     "        <div ng-repeat=\"header in headers\" class=\"text-left\" style=\"width: 100%;\" b2b-append-element=\"header\"></div>\n" +
21280     "        <table class=\"table-condensed\">\n" +
21281     "            <thead>\n" +
21282     "                <tr>\n" +
21283     "                    <th id=\"prev\" class=\"prev\" tabindex=\"0\" b2b-accessibility-click=\"13\" 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" +
21284     "                    <th id=\"month\" tabindex=\"-1\" aria-label=\"{{title}}\" class=\"datepicker-switch\" colspan=\"{{rows[0].length - 2}}\">{{title}}</th>\n" +
21285     "                    <th id=\"next\" class=\"next\" tabindex=\"0\" b2b-accessibility-click=\"13\" 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" +
21286     "                </tr>\n" +
21287     "                <tr ng-show=\"labels.length > 0\">\n" +
21288     "                    <th id=\"{{label.post}}\" class=\"dow\" ng-repeat=\"label in labels\" aria-hidden=\"true\"><span aria-hidden=\"true\">{{label.pre}}</span></th>\n" +
21289     "                </tr>\n" +
21290     "            </thead>\n" +
21291     "            <tbody>\n" +
21292     "                <tr ng-repeat=\"row in rows\">\n" +
21293     "                    <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" +
21294     "                        <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" +
21295     "                </tr>\n" +
21296     "            </tbody>\n" +
21297     "            <tfoot>\n" +
21298     "                <tr ng-repeat=\"footer in footers\">\n" +
21299     "                    <th colspan=\"7\" class=\"text-left\" style=\"width: 278px;\" b2b-append-element=\"footer\"></th>\n" +
21300     "                </tr>\n" +
21301     "            </tfoot>\n" +
21302     "        </table>\n" +
21303     "    </div>\n" +
21304     "</div>");
21305 }]);
21306
21307 angular.module("b2bTemplate/calendar/datepicker.html", []).run(["$templateCache", function($templateCache) {
21308   $templateCache.put("b2bTemplate/calendar/datepicker.html",
21309     "<div>\n" +
21310     "    <span class=\"icon-primary-calendar span12\" ng-class=\"{'disabled': ngDisabled}\" ng-transclude></span>\n" +
21311     "</div>");
21312 }]);
21313
21314 angular.module("b2bTemplate/coachmark/coachmark.html", []).run(["$templateCache", function($templateCache) {
21315   $templateCache.put("b2bTemplate/coachmark/coachmark.html",
21316     "<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" +
21317     "   <i class=\"b2b-coachmark-caret\"></i>\n" +
21318     "   <div class=\"b2b-coachmark-header\">\n" +
21319     "       <div class=\"b2b-coachmark-countlabel\"><span ng-if=\"coachmarkIndex !== 0\">{{coachmarkIndex}} of {{(coachmarks.length-1)}}<span></div>\n" +
21320     "       <div class=\"corner-button\">\n" +
21321     "           <button type=\"button\" ng-focus=\"closeButtonFocus()\" class=\"close\" title=\"close\" aria-label=\"Close\" ng-click=\"closeCoachmark()\"></button>\n" +
21322     "       </div>\n" +
21323     "   </div>\n" +
21324     "   <div class=\"b2b-coachmark-content\">   \n" +
21325     "       <i class=\"icon-misc-dimmer\"></i>\n" +
21326     "       <div class=\"b2b-coachmark-content-header\"><span class=\"offscreen-text\">{{currentCoachmark.offscreenText}}</span>{{currentCoachmark.contentHeader}}</div>\n" +
21327     "       <div class=\"b2b-coachmark-description\">{{currentCoachmark.content}}</div>\n" +
21328     "       <div class=\"b2b-coachmark-btn-group\">\n" +
21329     "           <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" +
21330     "           <button class=\"btn btn-alt\" ng-if=\"currentCoachmark.buttonLabel !== '' && currentCoachmark.buttonLabel !== undefined\" ng-click=\"actionCoachmark(currentCoachmark.buttonLabel)\">{{currentCoachmark.buttonLabel}}</button>\n" +
21331     "       </div>  \n" +
21332     "   </div>  \n" +
21333     "</div>");
21334 }]);
21335
21336 angular.module("b2bTemplate/dropdowns/b2bDropdownDesktop.html", []).run(["$templateCache", function($templateCache) {
21337   $templateCache.put("b2bTemplate/dropdowns/b2bDropdownDesktop.html",
21338     "<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" +
21339     "    <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-focus=\"focused=true\" ng-blur=\"setBlur(); focused=false\" ng-class=\"{'active': toggleFlag, 'closed': !toggleFlag, 'large': (dropdownSize === 'large'), 'focused':focused}\" style=\"width:100%;\" value=\"{{currentSelected.text}}\" ng-show=\"isInputDropdown\" aria-describedby=\"{{dropdownDescribedBy}}\" readonly=\"readonly\">\n" +
21340     "    <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" +
21341     "    <div ng-class=\"{'selectWrapper': (isInputDropdown), 'moduleWrapper': (!isInputDropdown)}\">\n" +
21342     "        <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" +
21343     "        <ul class=\"module-optinalcta\" ng-if=\"toggleFlag && optionalCta\" tabindex=\"-1\" aria-hidden=\"false\">\n" +
21344     "            <li class=\"module-list-item\" tabindex=\"-1\" role=\"menuitem\" value=\"\" aria-label=\"Optinal CTA\" aria-selected=\"true\">\n" +
21345     "                <span class=\"module-data\" b2b-append-element=\"optionalCta\"></span>\n" +
21346     "            </li>\n" +
21347     "        </ul>\n" +
21348     "</div>\n" +
21349     "<i class=\"icon-primary-down\" aria-hidden=\"true\"></i>\n" +
21350     "</span>    ");
21351 }]);
21352
21353 angular.module("b2bTemplate/dropdowns/b2bDropdownGroupDesktop.html", []).run(["$templateCache", function($templateCache) {
21354   $templateCache.put("b2bTemplate/dropdowns/b2bDropdownGroupDesktop.html",
21355     "<li b2b-dropdown-group-desktop class=\"optgroup-wrapper\">{{groupHeader}}\n" +
21356     "    <ul class=\"optgroup\" role=\"group\" aria-label=\"{{groupHeader}}\"></ul>\n" +
21357     "</li>");
21358 }]);
21359
21360 angular.module("b2bTemplate/dropdowns/b2bDropdownListDesktop.html", []).run(["$templateCache", function($templateCache) {
21361   $templateCache.put("b2bTemplate/dropdowns/b2bDropdownListDesktop.html",
21362     "<li b2b-dropdown-list-desktop b2b-key-item b2b-accessibility-click=\"13\" aria-selected=\"{{currentSelected.value === dropdownListValue}}\" ng-class=\"{'awd-select-list-item': (isInputDropdown), 'module-list-item': (!isInputDropdown)}\" tabindex=\"0\" role=\"{{isInputDropdown?'option':'menuitem'}}\" ng-click=\"selectDropdownItem()\"></li>");
21363 }]);
21364
21365 angular.module("b2bTemplate/fileUpload/fileUpload.html", []).run(["$templateCache", function($templateCache) {
21366   $templateCache.put("b2bTemplate/fileUpload/fileUpload.html",
21367     "<label class=\"b2b-file-container\">\n" +
21368     "   <span class=\"b2b-upload-link\" ng-transclude></span>\n" +
21369     "   <input type=\"file\" b2b-file-change>\n" +
21370     "</label>");
21371 }]);
21372
21373 angular.module("b2bTemplate/flyout/flyout.html", []).run(["$templateCache", function($templateCache) {
21374   $templateCache.put("b2bTemplate/flyout/flyout.html",
21375     "<span class=\"b2b-flyout\"  b2b-flyout-trap-focus-inside>\n" +
21376     "    <span ng-transclude></span>\n" +
21377     "</span>");
21378 }]);
21379
21380 angular.module("b2bTemplate/flyout/flyoutContent.html", []).run(["$templateCache", function($templateCache) {
21381   $templateCache.put("b2bTemplate/flyout/flyoutContent.html",
21382     "<div class=\"b2b-flyout-container\" aria-live=\"polite\" aria-atomic=\"false\" ng-class=\"{'b2b-flyout-left':horizontalPlacement==='left',\n" +
21383     "                'b2b-flyout-center':horizontalPlacement==='center', \n" +
21384     "                'b2b-flyout-right':horizontalPlacement==='right',\n" +
21385     "                'b2b-flyout-centerLeft':horizontalPlacement==='centerLeft',\n" +
21386     "                'b2b-flyout-centerRight':horizontalPlacement==='centerRight',  \n" +
21387     "                'b2b-flyout-above':verticalPlacement==='above', \n" +
21388     "                'b2b-flyout-below':verticalPlacement==='below',\n" +
21389     "                'open-flyout': openFlyout,\n" +
21390     "                'b2b-close-flyout': !openFlyout}\">\n" +
21391     "    <i class=\"b2b-flyout-caret\" ng-class=\"{'open-flyout': openFlyout, \n" +
21392     "                                   'b2b-flyout-caret-above':verticalPlacement==='above',\n" +
21393     "                                   'b2b-flyout-caret-below':verticalPlacement==='below'}\"></i>\n" +
21394     "    <span ng-transclude></span>\n" +
21395     "</div>");
21396 }]);
21397
21398 angular.module("b2bTemplate/footer/footer_column_switch_tpl.html", []).run(["$templateCache", function($templateCache) {
21399   $templateCache.put("b2bTemplate/footer/footer_column_switch_tpl.html",
21400     "<div class=\"footer-columns \" ng-class=\"{'five-column':footerColumns===5, 'four-column':footerColumns===4, 'three-column':footerColumns===3}\" ng-repeat=\"item in footerLinkItems\">\n" +
21401     "    <h3 class=\"b2b-footer-header\">{{item.categoryName}}</h3>\n" +
21402     "    <ul>\n" +
21403     "        <li ng-repeat=\"i in item.values\">\n" +
21404     "            <a href=\"{{i.href}}\" title=\"{{item.categoryName}} - {{i.displayLink}}\">{{i.displayLink}}</a>  \n" +
21405     "        </li>\n" +
21406     "    </ul>\n" +
21407     "\n" +
21408     "</div>\n" +
21409     "\n" +
21410     "<div ng-transclude></div>\n" +
21411     "");
21412 }]);
21413
21414 angular.module("b2bTemplate/horizontalTable/horizontalTable.html", []).run(["$templateCache", function($templateCache) {
21415   $templateCache.put("b2bTemplate/horizontalTable/horizontalTable.html",
21416     "<div class=\"b2b-horizontal-table\">\n" +
21417     "    <div class=\"b2b-horizontal-table-arrows row span12\">\n" +
21418     "       <div class=\"span4\">\n" +
21419     "           <button class=\"btn-arrow left\" type=\"button\" ng-click=\"moveViewportLeft()\" ddh-accessibility-click=\"13,32\" ng-disabled=\"disableLeft\"><div class=\"btn btn-alt\"><i class=\"icon-primary-left\"></i></div>Previous Set</button>\n" +
21420     "        </div>\n" +
21421     "        \n" +
21422     "        <span class=\"span5 b2b-horizontal-table-column-info\" aria-live=\"polite\" tabindex=\"-1\">\n" +
21423     "           Displaying {{getColumnSet()[0]}} - {{getColumnSet()[1]}} of {{numOfCols}} (total) columns\n" +
21424     "        </span>\n" +
21425     "        \n" +
21426     "        <div class=\"span3\">\n" +
21427     "           <button class=\"btn-arrow right\" ng-click=\"moveViewportRight()\" ddh-accessibility-click=\"13,32\" ng-disabled=\"disableRight\" type=\"button\">Next Set<div class=\"btn btn-alt\"><i class=\"icon-primary-right\"></i></div></button>\n" +
21428     "       </div>\n" +
21429     "    </div>\n" +
21430     "    <div class=\"b2b-horizontal-table-inner-container\">\n" +
21431     "        <span ng-transclude></span>\n" +
21432     "    </div>\n" +
21433     "</div>\n" +
21434     "\n" +
21435     "");
21436 }]);
21437
21438 angular.module("b2bTemplate/hourPicker/b2bHourpicker.html", []).run(["$templateCache", function($templateCache) {
21439   $templateCache.put("b2bTemplate/hourPicker/b2bHourpicker.html",
21440     "<div class=\"hp-container\">\n" +
21441     "    <div class=\"hp-selected\">\n" +
21442     "        <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" +
21443     "    </div>\n" +
21444     "    <div b2b-hourpicker-panel></div>\n" +
21445     "</div>");
21446 }]);
21447
21448 angular.module("b2bTemplate/hourPicker/b2bHourpickerPanel.html", []).run(["$templateCache", function($templateCache) {
21449   $templateCache.put("b2bTemplate/hourPicker/b2bHourpickerPanel.html",
21450     "<form name=\"{{'hourpickerForm' + $id}}\">\n" +
21451     "    <div class=\"hp-checkbox\" role=\"group\">\n" +
21452     "        <label class=\"checkbox\" for=\"checkbox_{{dayOption.title}}_{{$id}}\" aria-label=\"{{dayOption.title}}\" ng-repeat=\"dayOption in hourpicker.dayOptions\">\n" +
21453     "            <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" +
21454     "        </label>\n" +
21455     "    </div>\n" +
21456     "    <div class=\"row hp-dropdowns\">\n" +
21457     "        <div class=\"span4\">\n" +
21458     "            <label for=\"{{'hourpickerStartTime' + $id}}\">From</label>\n" +
21459     "            <select id=\"{{'hourpickerStartTime' + $parent.$id}}\" b2b-dropdown type=\"\" ng-model=\"hourpickerPanelValue.startTime\">\n" +
21460     "                <option b2b-dropdown-list value=\"\">From</option>\n" +
21461     "                <option b2b-dropdown-list option-repeat=\"startTimeOption in hourpicker.startTimeOptions\" value=\"{{startTimeOption}}\">{{startTimeOption}}</option>\n" +
21462     "            </select>\n" +
21463     "        </div>\n" +
21464     "        <div class=\"span8 radio-buttons\" role=\"radiogroup\" aria-label=\"Select AM or PM\">\n" +
21465     "            <label class=\"radio\" for=\"hourpickerStartMeridiem_AM_{{$id}}\">\n" +
21466     "                <input type=\"radio\" id=\"hourpickerStartMeridiem_AM_{{$id}}\" name=\"{{'hourpickerStartMeridiem' + $id}}\" value=\"am\" ng-model=\"hourpickerPanelValue.startMeridiem\" /><i class=\"skin\"></i><span>AM</span>\n" +
21467     "            </label>\n" +
21468     "            <label class=\"radio\" for=\"hourpickerStartMeridiem_PM_{{$id}}\">\n" +
21469     "                <input type=\"radio\" id=\"hourpickerStartMeridiem_PM_{{$id}}\" name=\"{{'hourpickerStartMeridiem' + $id}}\" value=\"pm\" ng-model=\"hourpickerPanelValue.startMeridiem\" /><i class=\"skin\"></i><span>PM</span>\n" +
21470     "            </label>\n" +
21471     "        </div>\n" +
21472     "    </div>\n" +
21473     "    <div class=\"row hp-dropdowns\">\n" +
21474     "        <div class=\"span4\">\n" +
21475     "            <label for=\"{{'hourpickerEndTime' + $id}}\">To</label>\n" +
21476     "            <select id=\"{{'hourpickerEndTime' + $parent.$id}}\" b2b-dropdown ng-model=\"hourpickerPanelValue.endTime\">\n" +
21477     "                <option b2b-dropdown-list value=\"\">To</option>\n" +
21478     "                <option b2b-dropdown-list option-repeat=\"endTimeOption in hourpicker.endTimeOptions\" value=\"{{endTimeOption}}\">{{endTimeOption}}</option>\n" +
21479     "            </select>\n" +
21480     "        </div>\n" +
21481     "        <div class=\"span8 radio-buttons\" role=\"radiogroup\" aria-label=\"Select AM or PM\">\n" +
21482     "            <label class=\"radio\" for=\"hourpickerEndMeridiem_AM_{{$id}}\">\n" +
21483     "                <input type=\"radio\" id=\"hourpickerEndMeridiem_AM_{{$id}}\" name=\"{{'hourpickerEndMeridiem' + $id}}\" value=\"am\" ng-model=\"hourpickerPanelValue.endMeridiem\" /><i class=\"skin\"></i><span>AM</span>\n" +
21484     "            </label>\n" +
21485     "            <label class=\"radio\" for=\"hourpickerEndMeridiem_PM_{{$id}}\">\n" +
21486     "                <input type=\"radio\" id=\"hourpickerEndMeridiem_PM_{{$id}}\" name=\"{{'hourpickerEndMeridiem' + $id}}\" value=\"pm\" ng-model=\"hourpickerPanelValue.endMeridiem\" /><i class=\"skin\"></i><span>PM</span>\n" +
21487     "            </label>\n" +
21488     "        </div>\n" +
21489     "    </div>\n" +
21490     "    <div class=\"row hp-buttons\">\n" +
21491     "        <div class=\"span12\">\n" +
21492     "            <div style=\"float:right\">\n" +
21493     "                <button class=\"btn btn-secondary btn-small\" ng-click=\"resetHourpickerPanelValue()\">Clear</button>\n" +
21494     "                <button class=\"btn btn-alt btn-small\" ng-disabled = \"disableAddBtn\" ng-click=\"updateHourpickerValue()\">{{hourpicker.editMode > -1 ? 'Update' : 'Add'}}</button>\n" +
21495     "            </div>\n" +
21496     "        </div>\n" +
21497     "    </div>\n" +
21498     "</form>");
21499 }]);
21500
21501 angular.module("b2bTemplate/hourPicker/b2bHourpickerValue.html", []).run(["$templateCache", function($templateCache) {
21502   $templateCache.put("b2bTemplate/hourPicker/b2bHourpickerValue.html",
21503     "<div class=\"selected-days\">\n" +
21504     "    <span class=\"day\">{{hourpickerValue.days}} &nbsp; {{hourpickerValue.startTime}} {{hourpickerValue.startMeridiem}} - {{hourpickerValue.endTime}} {{hourpickerValue.endMeridiem}}</span>\n" +
21505     "    <span style=\"float:right\">\n" +
21506     "        <i class=\"icon-misc-pen\" role=\"button\" title=\"Edit {{hourpickerValue.days}} &nbsp; {{hourpickerValue.startTime}} {{hourpickerValue.startMeridiem}} - {{hourpickerValue.endTime}} {{hourpickerValue.endMeridiem}}\" tabindex=\"0\" b2b-accessibility-click=\"13,32\" ng-click=\"editHourpickerValue(hourpickerValue.index)\"></i>\n" +
21507     "        <i class=\"icon-misc-trash\" role=\"button\" title=\"Delete {{hourpickerValue.days}} &nbsp; {{hourpickerValue.startTime}} {{hourpickerValue.startMeridiem}} - {{hourpickerValue.endTime}} {{hourpickerValue.endMeridiem}}\" tabindex=\"0\" b2b-accessibility-click=\"13,32\" ng-click=\"deleteHourpickerValue(hourpickerValue.index)\"></i>\n" +
21508     "    </span>\n" +
21509     "    <div style=\"clear:both\"></div>\n" +
21510     "</div>");
21511 }]);
21512
21513 angular.module("b2bTemplate/leftNavigation/leftNavigation.html", []).run(["$templateCache", function($templateCache) {
21514   $templateCache.put("b2bTemplate/leftNavigation/leftNavigation.html",
21515     "<div class=\"b2b-nav-menu\" ng-init=\"(showmenu = true)\" ng-class=\"{false: 'left-menu-collapsed'}[showmenu]\">\n" +
21516     "    <div class=\"b2b-subnav-container\">\n" +
21517     "        <ul class=\"b2b-subnav-content\">\n" +
21518     "                    <li>" +
21519     "                           <div ng-class=\"{true: 'leftmenu-arrow-expand', false: 'leftmenu-arrow-collapse'}[showmenu]\">"+        
21520     "                                   <a ng-click=\"toggleDrawer(showmenu);(showmenu = !showmenu) \" class=\"text-right\">" +
21521     "                                   <i ng-class=\"{true: 'icon-controls-left', false: 'icon-controls-right'}[showmenu]\">&nbsp;</i></a>" +
21522     "                           </div>"+                        
21523     "                   </li>" +
21524     "            <li ng-repeat=\"menu in menuData\" ng-click=\"!showmenu||toggleNav($index,menu.href)\">" +
21525     "                           <span ng-class=\"{true: 'menu-icon', false: 'menu-icon-collapse'}[showmenu]\"><span class=\"{{menu.imageSrc}}\"></span>&nbsp;&nbsp;</span>" +
21526     "                           <a ng-class=\"{expand: isOpen($index)}\" ng-if=\"showmenu\"  aria-label=\"{{menu.name}}\" title=\" \" aria-expanded=\"{{(idx==$index)?true:false;}}\" href=\"javascript:void(0);\">" +
21527     "                                   {{menu.name}}" +
21528     "                                   <i aria-hidden=\"true\" ng-if=\"(menu.menuItems.length > 0)\" class=\"b2b-icon-primary-plus-minus\"ng-class=\"idx==$index ? 'icon-primary-expanded' : 'icon-primary-collapsed'\"></i>" +
21529     "                           </a>\n" +
21530     "                           <div role=\"region\" aria-hidden=\"{{(isOpen($index))?false:true;}}\">\n" +
21531     "                   <ul ng-class=\"{expand: idx==$index}\">\n" +
21532     "                     <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" +
21533     "                           </ul>\n" +
21534     "                           </div>\n" +
21535     "            </li>\n" +
21536     "        </ul>\n" +
21537     "    </div>\n" +
21538     "</div>");
21539 }]);
21540
21541 angular.module("b2bTemplate/listbox/listbox.html", []).run(["$templateCache", function($templateCache) {
21542   $templateCache.put("b2bTemplate/listbox/listbox.html",
21543     "<div class=\"b2b-list-box\" tabindex=\"0\" role=\"listbox\" ng-transclude>\n" +
21544     "</div>");
21545 }]);
21546
21547 angular.module("b2bTemplate/modalsAndAlerts/b2b-backdrop.html", []).run(["$templateCache", function($templateCache) {
21548   $templateCache.put("b2bTemplate/modalsAndAlerts/b2b-backdrop.html",
21549     "<div class=\"b2b-modal-backdrop fade in hidden-by-modal\" aria-hidden=\"true\" tabindex=\"-1\"></div>");
21550 }]);
21551
21552 angular.module("b2bTemplate/modalsAndAlerts/b2b-window.html", []).run(["$templateCache", function($templateCache) {
21553   $templateCache.put("b2bTemplate/modalsAndAlerts/b2b-window.html",
21554     "<div class=\"modalwrapper active {{windowClass}}\" ng-class=\"{'modal-landscape': isModalLandscape}\" role=\"{{isNotifDialog?'alertdialog':'dialog'}}\" tabindex=\"-1\" aria-labelledby=\"{{title}}\" aria-describedby=\"{{content}}\">\n" +
21555     "    <div class=\"modal fade in {{sizeClass}}\" ng-transclude></div>\n" +
21556     "</div>");
21557 }]);
21558
21559 angular.module("b2bTemplate/monthSelector/monthSelector-popup.html", []).run(["$templateCache", function($templateCache) {
21560   $templateCache.put("b2bTemplate/monthSelector/monthSelector-popup.html",
21561     "<div id=\"monthselector{{$id}}\" class=\"datepicker dropdown-menu monthselector\" \n" +
21562     "     ng-class=\"{'datepicker-dropdown datepicker-orient-top': !inline, 'datepicker-orient-left': !inline && orientation === 'left', 'datepicker-orient-right': !inline && orientation === 'right'}\" \n" +
21563     "     ng-style=\"{position: inline && 'relative', 'z-index': inline && '0', top: !inline && position.top + 'px' || 0, left: !inline && position.left + 'px'}\" \n" +
21564     "     style=\"display: block;\" aria-hidden=\"false\" role=\"dialog presentation\" tabindex=\"-1\">\n" +
21565     "    <div class=\"datepicker-days\" style=\"display: block;\">\n" +
21566     "        <span class=\"offscreen-text\" aria-live=\"polite\" aria-atomic=\"true\">{{title}} displaying</span>\n" +
21567     "        <table class=\"table-condensed\" role=\"grid\">\n" +
21568     "            <thead>\n" +
21569     "                <tr ng-repeat=\"header in headers\">\n" +
21570     "                    <th colspan=\"7\" class=\"text-left\" style=\"width: 278px;\" b2b-append-element=\"header\"></th>\n" +
21571     "                </tr>\n" +
21572     "                <tr>\n" +
21573     "                    <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" +
21574     "                    <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" +
21575     "                    <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" +
21576     "                </tr>\n" +
21577     "                <tr ng-show=\"labels.length > 0\">\n" +
21578     "                    <th id=\"{{label.post}}\" class=\"dow\" ng-repeat=\"label in labels\" aria-hidden=\"true\"><span aria-hidden=\"true\">{{label.pre}}</span></th>\n" +
21579     "                </tr>\n" +
21580     "            </thead>\n" +
21581     "            <tbody b2b-key type=\"table\" columns=\"4\" >\n" +
21582     "                <tr ng-repeat=\"row in rows\">\n" +
21583     "                    <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" +
21584     "                        <div aria-hidden=\"true\"  tabindex=\"-1\" class=\"show-date\" ng-if=\"!(dt.oldMonth || dt.nextMonth)\">{{dt.label | limitTo: 3}}</div>\n" +
21585     "                    </td>\n" +
21586     "                </tr>\n" +
21587     "            </tbody>\n" +
21588     "            <tfoot>\n" +
21589     "                <tr ng-repeat=\"footer in footers\">\n" +
21590     "                    <th colspan=\"7\" class=\"text-left\" b2b-append-element=\"footer\"></th>\n" +
21591     "                </tr>\n" +
21592     "            </tfoot>\n" +
21593     "        </table>\n" +
21594     "    </div>\n" +
21595     "</div>");
21596 }]);
21597
21598 angular.module("b2bTemplate/monthSelector/monthSelector.html", []).run(["$templateCache", function($templateCache) {
21599   $templateCache.put("b2bTemplate/monthSelector/monthSelector.html",
21600     "<div>\n" +
21601     "    <span class=\"icon-primary-calendar span12\" ng-class=\"{'disabled': ngDisabled}\" ng-transclude></span>\n" +
21602     "</div>");
21603 }]);
21604
21605 angular.module("b2bTemplate/monthSelector/monthSelectorLink.html", []).run(["$templateCache", function($templateCache) {
21606   $templateCache.put("b2bTemplate/monthSelector/monthSelectorLink.html",
21607     "<div>\n" +
21608     "    <span class=\"span12\" ng-transclude></span>\n" +
21609     "</div>");
21610 }]);
21611
21612 angular.module("b2bTemplate/pagination/b2b-pagination.html", []).run(["$templateCache", function($templateCache) {
21613   $templateCache.put("b2bTemplate/pagination/b2b-pagination.html",
21614     "<div class=\"b2b-pager\">\n" +
21615     "    <div ng-if=\"notMobile && totalPages > 1\">\n" +
21616     "        <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" +
21617     "            <i class=\"icon-primary-left\"></i>\n" +
21618     "        </a>\n" +
21619     "        <a tabindex=\"{{currentPage === 1 ? -1 : 0}}\" ng-class=\"{'b2b-pager__item--noclick': currentPage === 1}\" aria-selected=\"{{checkSelectedPage(page)}}\" 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)\">\n" +
21620     "            1<span class=\"offscreen-text\" ng-if=\"currentPage === 1\"> is selected</span>\n" +
21621     "        </a>\n" +
21622     "        <a tabindex=\"{{currentPage === 2 ? -1 : 0}}\" aria-selected=\"{{checkSelectedPage(page)}}\" ng-class=\"{'b2b-pager__item--noclick': currentPage === 2}\" class=\"b2b-pager__item b2b-pager__item--link\" title=\"Page 2{{checkSelectedPage(page) ? ' selected' : '' }}\" ng-if=\"totalPages > 10 && currentPage > 6\" b2b-accessibility-click=\"13,32\" ng-click=\"selectPage(2, $event)\">2<span class=\"offscreen-text\" ng-if=\"currentPage === 2\"> is selected</span></a>\n" +
21623     "\n" +
21624     "        <span class=\"b2b-pager__item\" ng-if=\"totalPages > 10 && currentPage > 6\">...</span>\n" +
21625     "\n" +
21626     "        <a 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-accessibility-click=\"13,32\" ng-click=\"!checkSelectedPage(page) && selectPage(page, $event)\">{{page}}<span class=\"offscreen-text\" ng-if=\"currentPage === page\"> is selected</span></a>\n" +
21627     "\n" +
21628     "        <span class=\"b2b-pager__item\" ng-if=\"totalPages > 10 && currentPage <= totalPages - 5\">...</span>\n" +
21629     "\n" +
21630     "        <a tabindex=\"{{checkSelectedPage(page) ? -1 : 0}}\" href=\"javascript:void(0)\" ng-class=\"{'b2b-pager__item--noclick': checkSelectedPage(page)}\" aria-selected=\"{{checkSelectedPage(page)}}\" class=\"b2b-pager__item b2b-pager__item--link\" title=\"Page {{totalPages-1}}\" ng-if=\"totalPages > 10 && currentPage <= totalPages - 5\" b2b-accessibility-click=\"13,32\" ng-click=\"selectPage(totalPages-1, $event)\">{{totalPages-1}}<span class=\"offscreen-text\" ng-if=\"currentPage === totalPages-1\"> is selected</span></a>\n" +
21631     "\n" +
21632     "        <a tabindex=\"{{currentPage === totalPages ? -1 : 0}}\" href=\"javascript:void(0)\" ng-class=\"{'b2b-pager__item--noclick': currentPage === totalPages}\" aria-selected=\"{{checkSelectedPage(page)}}\" class=\"b2b-pager__item b2b-pager__item--link\" title=\"Page {{totalPages}}\" ng-if=\"totalPages > 10 && currentPage <= totalPages - 5\" b2b-accessibility-click=\"13,32\" ng-click=\"selectPage(totalPages, $event)\">{{totalPages}}<span class=\"offscreen-text\" ng-if=\"currentPage === totalPages\"> is selected</span></a>\n" +
21633     "\n" +
21634     "        <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" +
21635     "            <i class=\"icon-primary-right\"></i>\n" +
21636     "        </a>\n" +
21637     "        \n" +
21638     "        <span class=\"fieldLabel\" ng-show=\"totalPages > 10 && showInput === true\">    \n" +
21639     "            <label for=\"{{inputId}}\">Go to Page:</label>\n" +
21640     "            <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" +
21641     "            <button class=\"btn-arrow\" ng-click=\"gotoBtnClick()\" ng-disabled=\"$parent.gotoPage !== 0 || $parent.gotoPage !== undefined\" aria-label=\"Go to\">\n" +
21642     "                <div class=\"btn btn-small btn-secondary\">\n" +
21643     "                    <i class=\"icon-primary-right\"></i>\n" +
21644     "                </div>\n" +
21645     "            </button>\n" +
21646     "        </span>\n" +
21647     "    </div>\n" +
21648     "    <div ng-if=\"isMobile && totalPages > 1\" ng-swipe-right=\"prev()\" ng-swipe-left=\"next()\" ng-class=\"isMobile ? 'b2b-mobile-view': '' \">\n" +
21649     "        <a 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" +
21650     "    </div>\n" +
21651     "</div>\n" +
21652     "");
21653 }]);
21654
21655 angular.module("b2bTemplate/paneSelector/paneSelector.html", []).run(["$templateCache", function($templateCache) {
21656   $templateCache.put("b2bTemplate/paneSelector/paneSelector.html",
21657     "<div class=\"panes\" ng-transclude></div>");
21658 }]);
21659
21660 angular.module("b2bTemplate/paneSelector/paneSelectorPane.html", []).run(["$templateCache", function($templateCache) {
21661   $templateCache.put("b2bTemplate/paneSelector/paneSelectorPane.html",
21662     "<div class=\"pane-block\" ng-transclude></div>");
21663 }]);
21664
21665 angular.module("b2bTemplate/profileCard/profileCard-addUser.html", []).run(["$templateCache", function($templateCache) {
21666   $templateCache.put("b2bTemplate/profileCard/profileCard-addUser.html",
21667     "<div  class=\"span3 b2b-profile-card b2b-add-user\">\n" +
21668     "    <div class=\"atcenter\">\n" +
21669     "        <div class=\"circle\"><i class=\"icon-primary-add-maximize\"></i></div>\n" +
21670     "        <div>Create new user</div>\n" +
21671     "    </div>\n" +
21672     "</div>");
21673 }]);
21674
21675 angular.module("b2bTemplate/profileCard/profileCard.html", []).run(["$templateCache", function($templateCache) {
21676   $templateCache.put("b2bTemplate/profileCard/profileCard.html",
21677     "<div class=\"span3 b2b-profile-card\">\n" +
21678     "    <div class=\"top-block\">\n" +
21679     "       <div class=\"profile-image\">\n" +
21680     "            <img ng-if=\"image\" profile-name=\"{{profile.name}}\" ng-src=\"{{profile.img}}\" alt=\"{{profile.name}}\">\n" +
21681     "            <span ng-if=\"!image\" class=\"default-img\">{{initials}}</span>\n" +
21682     "\n" +
21683     "            <h4 class=\"name\">{{profile.name}}</h4>\n" +
21684     "\n" +
21685     "            <p class=\"status\">\n" +
21686     "                <span class=\"status-icon\" ng-class=\"{'status-green':colorIcon==='green','status-red':colorIcon==='red','status-blue':colorIcon==='blue','status-yellow':colorIcon==='yellow'}\">   \n" +
21687     "                </span>\n" +
21688     "                <span>{{profile.state}}<span ng-if=\"badge\" class=\"status-badge\">Admin</span></span>\n" +
21689     "            </p>\n" +
21690     "        </div>\n" +
21691     "    </div>\n" +
21692     "    <div class=\"bottom-block\">\n" +
21693     "         <div class=\"profile-details\">\n" +
21694     "            <label>Username</label>\n" +
21695     "            <div ng-if=\"shouldClip(profile.userName)\" ng-mouseover=\"showUserNameTooltip = true;\" ng-mouseleave=\"showUserNameTooltip = false;\">\n" +
21696     "                <div ng-if=\"shouldClip(profile.userName)\" class=\"tooltip\" b2b-tooltip show-tooltip=\"showUserNameTooltip\">\n" +
21697     "                    {{profile.userName.slice(0, 25)+'...'}}\n" +
21698     "                    <div class=\"arrow\"></div>\n" +
21699     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +
21700     "                        <div class=\"tooltip-size-control\">\n" +
21701     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +
21702     "                                {{profile.userName}}\n" +
21703     "                            </div>\n" +
21704     "                        </div>\n" +
21705     "                    </div>\n" +
21706     "                </div>\n" +
21707     "            </div>\n" +
21708     "            <div ng-if=\"!shouldClip(profile.userName)\">\n" +
21709     "                {{profile.userName}}\n" +
21710     "            </div>\n" +
21711     "            <label>Email</label>\n" +
21712     "            <div ng-if=\"shouldClip(profile.email)\" ng-mouseover=\"showEmailTooltip = true;\" ng-mouseleave=\"showEmailTooltip = false;\">\n" +
21713     "                <div ng-if=\"shouldClip(profile.email)\" class=\"tooltip\" data-placement=\"bottom\" b2b-tooltip show-tooltip=\"showEmailTooltip\">\n" +
21714     "                    {{profile.email.slice(0, 25)+'...'}}\n" +
21715     "                    <div class=\"arrow\"></div>\n" +
21716     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +
21717     "                        <div class=\"tooltip-size-control\">\n" +
21718     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +
21719     "                                {{profile.email}}\n" +
21720     "                            </div>\n" +
21721     "                        </div>\n" +
21722     "                    </div>\n" +
21723     "                </div>\n" +
21724     "            </div>\n" +
21725     "            <div ng-if=\"!shouldClip(profile.email)\">\n" +
21726     "                {{profile.email}}\n" +
21727     "            </div>\n" +
21728     "            <label>Role</label>\n" +
21729     "            <div ng-if=\"shouldClip(profile.role)\" ng-mouseover=\"showRoleTooltip = true;\" ng-mouseleave=\"showRoleTooltip = false;\">\n" +
21730     "                <div ng-if=\"shouldClip(profile.role)\" class=\"tooltip\" b2b-tooltip show-tooltip=\"showRoleTooltip\">\n" +
21731     "                    {{profile.role.slice(0, 25)+'...'}}\n" +
21732     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +
21733     "                        <div class=\"tooltip-size-control\">\n" +
21734     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +
21735     "                                {{profile.role}}\n" +
21736     "                            </div>\n" +
21737     "                        </div>\n" +
21738     "                    </div>\n" +
21739     "                </div>\n" +
21740     "            </div>\n" +
21741     "            <div ng-if=\"!shouldClip(profile.role)\">\n" +
21742     "                {{profile.role}}\n" +
21743     "            </div>\n" +
21744     "            <label>Last login</label>\n" +
21745     "            <div ng-if=\"shouldClip(profile.lastLogin)\" ng-mouseover=\"showLastLoginTooltip = true;\" ng-mouseleave=\"showLastLoginTooltip = false;\">\n" +
21746     "                <div ng-if=\"shouldClip(profile.lastLogin)\" class=\"tooltip\" b2b-tooltip show-tooltip=\"showLastLoginTooltip\">\n" +
21747     "                    {{profile.lastLogin.slice(0, 25)+'...'}}\n" +
21748     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +
21749     "                        <div class=\"tooltip-size-control\">\n" +
21750     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +
21751     "                                {{profile.lastLogin}}\n" +
21752     "                            </div>\n" +
21753     "                        </div>\n" +
21754     "                    </div>\n" +
21755     "                </div>\n" +
21756     "            </div>\n" +
21757     "            <div ng-if=\"!shouldClip(profile.lastLogin)\">\n" +
21758     "                {{profile.lastLogin}}\n" +
21759     "            </div>\n" +
21760     "         </div>\n" +
21761     "    </div>\n" +
21762     "</div>");
21763 }]);
21764
21765 angular.module("b2bTemplate/searchField/searchField.html", []).run(["$templateCache", function($templateCache) {
21766   $templateCache.put("b2bTemplate/searchField/searchField.html",
21767     "<div class=\"search-bar\">\n" +
21768     "    <div class='input-container' ng-blur=\"blurInput()\">\n" +
21769     "        <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}}\"  aria-live=\"assertive\"/>\n" +
21770     "            <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" +
21771     "    </div>\n" +
21772     "    <div class=\"search-suggestion-wrapper\" ng-if=\"filterList.length >=0\" ng-show=\"showListFlag\">\n" +
21773     "        <ul class=\"search-suggestion-list\" role=\"listbox\">      \n" +
21774     "            <li class=\"no-result\" ng-if=\"filterList.length == 0 && configObj.display\">{{configObj.resultText}}</li>\n" +
21775     "            <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" +
21776     "                {{item.title}}     \n" +
21777     "            </li>\n" +
21778     "        </ul>\n" +
21779     "    </div>\n" +
21780     "</div>");
21781 }]);
21782
21783 angular.module("b2bTemplate/seekBar/seekBar.html", []).run(["$templateCache", function($templateCache) {
21784   $templateCache.put("b2bTemplate/seekBar/seekBar.html",
21785     "<div class=\"b2b-seek-bar-container\" ng-class=\"{vertical:verticalSeekBar}\">\n" +
21786     "    <div class=\"b2b-seek-bar-track-container\">\n" +
21787     "        <div class=\"b2b-seek-bar-track\"></div>\n" +
21788     "        <div class=\"b2b-seek-bar-track-fill\"></div>\n" +
21789     "    </div>\n" +
21790     "    <div class=\"b2b-seek-bar-knob-container\" role=\"menu\"  >\n" +
21791     "        <div class=\"b2b-seek-bar-knob\" tabindex=\"0\" role=\"menuitem\"></div>\n" +
21792     "    </div>\n" +
21793     "</div>");
21794 }]);
21795
21796 angular.module("b2bTemplate/slider/slider.html", []).run(["$templateCache", function($templateCache) {
21797   $templateCache.put("b2bTemplate/slider/slider.html",
21798     "<div class=\"b2b-slider-container\" ng-class=\"{'vertical':verticalSlider}\">\n" +
21799     "    <div class=\"slider-track-container\">\n" +
21800     "        <div class=\"slider-track\"></div>\n" +
21801     "        <div class=\"slider-track-fill\" ng-style=\"{backgroundColor:trackFillColor}\"></div>\n" +
21802     "    </div>\n" +
21803     "    <div class=\"slider-knob-container\" ng-class=\"{'slider-knob-hidden':hideKnob}\">\n" +
21804     "        <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" +
21805     "    </div>\n" +
21806     "</div>");
21807 }]);
21808
21809 angular.module("b2bTemplate/spinButton/spinButton.html", []).run(["$templateCache", function($templateCache) {
21810   $templateCache.put("b2bTemplate/spinButton/spinButton.html",
21811     "<div class=\"btn-group btn-spinbutton-toggle\" ng-class=\"{'disabled': disabledFlag}\">\n" +
21812     "    <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" +
21813     "    <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" +
21814     "    <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" +
21815     "</div>");
21816 }]);
21817
21818 angular.module("b2bTemplate/statusTracker/statusTracker.html", []).run(["$templateCache", function($templateCache) {
21819   $templateCache.put("b2bTemplate/statusTracker/statusTracker.html",
21820     "<div class=\"b2b-status-tracker row\">\n" +
21821     "   <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" +
21822     "       <div class=\"btn btn-small btn-secondary\">\n" +
21823     "           <i class=\"icon-primary-left\"></i>\n" +
21824     "       </div>\n" +
21825     "   </button>\n" +
21826     "   <div ng-repeat=\"status in statuses\" class=\"b2b-status-tracker-step\" ng-class=\"{ 'complete' : status.complete, 'current' : currentStatus($index)}\" ng-show=\"isInViewport($index)\">\n" +
21827     "       <p class=\"b2b-status-tracker-heading\">{{status.heading}}</p>\n" +
21828     "       <div class=\"progress\">\n" +
21829     "           <div class=\"progress-bar\">\n" +
21830     "               <span class=\"hidden-spoken\">\n" +
21831     "                   {{status.complete ? 'Complete' : 'Incomplete'}}\n" +
21832     "               </span>\n" +
21833     "           </div>\n" +
21834     "       </div>\n" +
21835     "       <div class=\"b2b-status-tracker-estimate\">\n" +
21836     "           <i ng-show=\"status.estimate !== '' && status.estimate !== undefined\" ng-class=\"status.complete ? 'icoControls-approval' : 'icon-misc-time'\"></i> {{status.complete ? 'Complete' : status.estimate}}\n" +
21837     "           &nbsp;\n" +
21838     "       </div>\n" +
21839     "       \n" +
21840     "       <div class=\"b2b-status-tracker-description\">\n" +
21841     "           {{status.description}}\n" +
21842     "       </div>\n" +
21843     "   </div>\n" +
21844     "   <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" +
21845     "       <div class=\"btn btn-small btn-secondary\">\n" +
21846     "           <i class=\"icon-primary-right\"></i>\n" +
21847     "       </div>\n" +
21848     "   </button>\n" +
21849     "</div>");
21850 }]);
21851
21852 angular.module("b2bTemplate/stepTracker/stepTracker.html", []).run(["$templateCache", function($templateCache) {
21853   $templateCache.put("b2bTemplate/stepTracker/stepTracker.html",
21854     "<div class=\"b2b-step-tracker\">\n" +
21855     "    <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" +
21856     "       <div class=\"btn btn-left btn-small btn-secondary\"><i class=\"icon-primary-left\"></i></div>\n" +
21857     "   </button>\n" +
21858     "    <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" +
21859     "       <div class=\"btn btn-small btn-right btn-secondary\"><i class=\"icon-primary-right\"></i></div>\n" +
21860     "   </button>\n" +
21861     "    <ul class=\"b2b-steps\">\n" +
21862     "        <li ng-class=\"{'b2b-step-done':$index < currentIndex - 1 ,'b2b-step-on':$index == currentIndex - 1}\" \n" +
21863     "            ng-repeat=\"stepsItem in stepsItemsObject\" ng-show=\"isInViewport($index)\">\n" +
21864     "           <p class=\"b2b-step-text\" data-sm-text=\"{{stepsItem.dataMobile}}\" data-large-text=\"{{stepsItem.dataDesktop}}\">{{stepsItem.text}}</p>\n" +
21865     "            <span class=\"hidden-spoken\">\n" +
21866     "                {{($index < currentIndex - 1)? 'Complete. '+stepsItem.text+' '+stepsItem.dataMobile:''}} \n" +
21867     "                {{($index == currentIndex - 1)? 'In Progress. '+stepsItem.text+' '+stepsItem.dataMobile:''}} \n" +
21868     "                {{($index > currentIndex - 1)? 'Incomplete. '+stepsItem.text+' '+stepsItem.dataMobile:''}}\n" +
21869     "            </span>\n" +
21870     "        </li>\n" +
21871     "    </ul>\n" +
21872     "</div>");
21873 }]);
21874
21875 angular.module("b2bTemplate/switches/switches-spanish.html", []).run(["$templateCache", function($templateCache) {
21876   $templateCache.put("b2bTemplate/switches/switches-spanish.html",
21877     "<div class=\"switch-overlay\" aria-hidden=\"true\">\n" +
21878     "    <span class=\"btn-slider-on\"><span class=\"hidden-spoken\">seleccione para hacer </span><i class=\"activo\">activo</i></span>\n" +
21879     "    <span class=\"switch-handle\"></span>\n" +
21880     "    <span class=\"btn-slider-off\"><span class=\"hidden-spoken\">seleccione para hacer </span><i class=\"inactivo\">inactivo</i></span>\n" +
21881     "</div>");
21882 }]);
21883
21884 angular.module("b2bTemplate/switches/switches.html", []).run(["$templateCache", function($templateCache) {
21885   $templateCache.put("b2bTemplate/switches/switches.html",
21886     "<div class=\"switch-overlay\" aria-hidden=\"true\">\n" +
21887     "    <span class=\"btn-slider-on\">On</span>\n" +
21888     "    <span class=\"switch-handle\"></span>\n" +
21889     "    <span class=\"btn-slider-off\">Off</span>\n" +
21890     "</div>");
21891 }]);
21892
21893 angular.module("b2bTemplate/tableMessages/tableMessage.html", []).run(["$templateCache", function($templateCache) {
21894   $templateCache.put("b2bTemplate/tableMessages/tableMessage.html",
21895     "<div class=\"b2b-table-message\">\n" +
21896     "    <div class=\"b2b-message\" ng-if=\"msgType === 'noMatchingResults'\">\n" +
21897     "        <div class=\"b2b-magnify-glass\"></div>\n" +
21898     "        <div>\n" +
21899     "            <div ng-transclude></div>\n" +
21900     "        </div>\n" +
21901     "    </div>\n" +
21902     "    <div class=\"b2b-message\" ng-if=\"msgType == 'infoCouldNotLoad'\">\n" +
21903     "        <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" +
21904     "        <div>Oops!</div>\n" +
21905     "        <div>The information could not load at this time.</div>\n" +
21906     "        <div>Please <a href=\"javascript:void(0)\" title=\"Refresh the page\" ng-click=\"refreshAction($event)\">refresh the page</a>\n" +
21907     "        </div>\n" +
21908     "    </div>\n" +
21909     "    <div class=\"b2b-message\" ng-if=\"msgType == 'magnifySearch'\">\n" +
21910     "        <div class=\"b2b-magnify-glass\"></div>\n" +
21911     "        <div>\n" +
21912     "            <p class=\"b2b-message-title\">Please input values to\n" +
21913     "                <br/> begin your search.</p>\n" +
21914     "        </div>\n" +
21915     "    </div>\n" +
21916     "    <div class=\"b2b-message\" ng-if=\"msgType === 'loadingTable'\">\n" +
21917     "        <div class=\"icon-primary-spinner-ddh b2b-loading-dots\"></div>\n" +
21918     "        <div ng-transclude></div>\n" +
21919     "    </div>\n" +
21920     "</div>\n" +
21921     "");
21922 }]);
21923
21924 angular.module("b2bTemplate/tableScrollbar/tableScrollbar.html", []).run(["$templateCache", function($templateCache) {
21925   $templateCache.put("b2bTemplate/tableScrollbar/tableScrollbar.html",
21926     "<div class=\"b2b-table-scrollbar\">\n" +
21927     "    <div class=\"b2b-scrollbar-arrows\">\n" +
21928     "        <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" +
21929     "        <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" +
21930     "    </div>\n" +
21931     "    <div class=\"b2b-table-inner-container\">\n" +
21932     "        <span ng-transclude></span>\n" +
21933     "    </div>\n" +
21934     "</div>");
21935 }]);
21936
21937 angular.module("b2bTemplate/tables/b2bTable.html", []).run(["$templateCache", function($templateCache) {
21938   $templateCache.put("b2bTemplate/tables/b2bTable.html",
21939     "<table ng-class=\"{'striped': responsive, 'complex-table': responsive && active}\" ng-transclude></table>");
21940 }]);
21941
21942 angular.module("b2bTemplate/tables/b2bTableBody.html", []).run(["$templateCache", function($templateCache) {
21943   $templateCache.put("b2bTemplate/tables/b2bTableBody.html",
21944     "<td ng-hide=\"isHidden()\" ng-transclude></td>");
21945 }]);
21946
21947 angular.module("b2bTemplate/tables/b2bTableHeaderSortable.html", []).run(["$templateCache", function($templateCache) {
21948   $templateCache.put("b2bTemplate/tables/b2bTableHeaderSortable.html",
21949     "<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" +
21950     "    <span ng-transclude></span>\n" +
21951     "    <i ng-class=\"{'icon-primary-arrows-sort-arrow active': sortPattern === 'ascending', 'icon-primary-arrows-sort-arrow active down': sortPattern === 'descending'}\"></i>\n" +
21952     "</th>");
21953 }]);
21954
21955 angular.module("b2bTemplate/tables/b2bTableHeaderUnsortable.html", []).run(["$templateCache", function($templateCache) {
21956   $templateCache.put("b2bTemplate/tables/b2bTableHeaderUnsortable.html",
21957     "<th scope=\"col\" ng-hide=\"isHidden()\" ng-transclude></th>");
21958 }]);
21959
21960 angular.module("b2bTemplate/tabs/b2bTab.html", []).run(["$templateCache", function($templateCache) {
21961   $templateCache.put("b2bTemplate/tabs/b2bTab.html",
21962     "<li role=\"tab\" aria-selected=\"{{isTabActive()}}\" aria-controls=\"{{tabPanelId}}\" class=\"tab\" \n" +
21963     "    ng-class=\"{'active': isTabActive()}\" ng-click=\"clickTab()\" ng-hide=\"tabItem.disabled\">\n" +
21964     "    <a href=\"javascript:void(0)\"  tabindex=\"{{(isTabActive() && tabItem.disabled)?-1:0}}\"\n" +
21965     "       ng-disabled=\"tabItem.disabled\" aria-expanded=\"{{(isTabActive() && !tabItem.disabled)}}\" \n" +
21966     "       b2b-accessibility-click=\"13,32\" ng-transclude></a>\n" +
21967     "    <span class=\"hidden-spoken\" ng-if=\"isTabActive()\">Active tab</span>\n" +
21968     "</li>");
21969 }]);
21970
21971 angular.module("b2bTemplate/tabs/b2bTabset.html", []).run(["$templateCache", function($templateCache) {
21972   $templateCache.put("b2bTemplate/tabs/b2bTabset.html",
21973     "<ul class=\"tabs promo-tabs\" role=\"tablist\" ng-transclude></ul>");
21974 }]);
21975
21976 angular.module("b2bTemplate/treeNav/groupedTree.html", []).run(["$templateCache", function($templateCache) {
21977   $templateCache.put("b2bTemplate/treeNav/groupedTree.html",
21978     "<ul role=\"group\">\n" +
21979     "    <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" +
21980     "        <ul role=\"group\">\n" +
21981     "            <b2b-member ng-repeat='member in value.childArray' member='member' time-delay='{{timeDelay}}' group-it='groupIt'></b2b-member>\n" +
21982     "        </ul>\n" +
21983     "    </li>\n" +
21984     "</ul>");
21985 }]);
21986
21987 angular.module("b2bTemplate/treeNav/treeMember.html", []).run(["$templateCache", function($templateCache) {
21988   $templateCache.put("b2bTemplate/treeNav/treeMember.html",
21989     "<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" +
21990     "    <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" +
21991     "        <span class=\"{{!member.child?'end':''}} b2b-tree-node-icon\">\n" +
21992     "            <i class=\"b2b-tree-expandCollapse-icon\" ng-class=\"{'icon-primary-expanded':member.active}\"></i>\n" +
21993     "        </span>\n" +
21994     "         <div id=\"description_{{$id}}\" class=\"offscreen-text\">\n" +
21995     "           {{member.descriptionText}}\n" +
21996     "        </div>\n" +
21997     "        <div class=\"b2b-tree-tooltip\" ng-if=\"member.showTooltip\">\n" +
21998     "           <span class=\"b2b-tree-arrow-left\"></span>\n" +
21999     "           <div class=\"b2b-tree-tooltip-content\">\n" +
22000     "               {{member.tooltipContent}}\n" +
22001     "           </div>  \n" +
22002     "        </div>\n" +
22003     "    </a>\n" +
22004     "</li>");
22005 }]);
22006
22007 angular.module("b2bTemplate/treeNav/ungroupedTree.html", []).run(["$templateCache", function($templateCache) {
22008   $templateCache.put("b2bTemplate/treeNav/ungroupedTree.html",
22009     "<ul role=\"{{setRole}}\"><b2b-member ng-repeat='member in collection' member='member' group-it='groupIt'></b2b-member></ul>");
22010 }]);
22011
22012 angular.module("b2bTemplate/treeNodeCheckbox/groupedTree.html", []).run(["$templateCache", function($templateCache) {
22013   $templateCache.put("b2bTemplate/treeNodeCheckbox/groupedTree.html",
22014     "<ul role=\"group\">\n" +
22015     "    <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" +
22016     "        <span class=\"ng-hide\">\n" +
22017     "            <label class=\"checkbox\">\n" +
22018     "                <input type=\"checkbox\" tabindex=\"-1\" class=\"treeCheckBox grpTreeCheckbox\" style=\"margin-top:2px;\"/><i class=\"skin\"></i><span> {{(key)?key:''}}</span>\n" +
22019     "            </label>\n" +
22020     "        </span>\n" +
22021     "        <span>\n" +
22022     "            {{(key)?key:''}}    \n" +
22023     "        </span>\n" +
22024     "        <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" +
22025     "        <ul role=\"group\">\n" +
22026     "            <b2b-tree-member ng-repeat='member in value.childArray' member='member' group-it='groupIt'></b2b-tree-member>\n" +
22027     "        </ul>\n" +
22028     "    </li>\n" +
22029     "</ul>");
22030 }]);
22031
22032 angular.module("b2bTemplate/treeNodeCheckbox/treeMember.html", []).run(["$templateCache", function($templateCache) {
22033   $templateCache.put("b2bTemplate/treeNodeCheckbox/treeMember.html",
22034     "<li role=\"treeitem\" aria-expanded=\"{{(member.active?true:false)}}\" aria-label=\"{{member.name}}\" ng-class=\"{'bg':member.selected}\"  b2b-tree-node-link>\n" +
22035     "    <a tabindex=\"-1\" title=\"{{member.name}}\" href=\"javascript:void(0)\" ng-class=\"{'active':member.active}\">\n" +
22036     "       <span ng-show=\"member.displayCheckbox\">\n" +
22037     "               <label class=\"checkbox\">\n" +
22038     "                <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" +
22039     "            </label>\n" +
22040     "        </span>\n" +
22041     "       <span ng-show=\"!member.displayCheckbox\">\n" +
22042     "           {{member.name}} \n" +
22043     "       </span>\n" +
22044     "        <span class=\"nodeIcon {{!member.child?'end':''}}\">\n" +
22045     "            <i class=\"expandCollapseIcon\" ng-class=\"{'icon-primary-expanded':member.active}\"></i>\n" +
22046     "        </span>\n" +
22047     "    </a>\n" +
22048     "</li>");
22049 }]);
22050
22051 angular.module("b2bTemplate/treeNodeCheckbox/ungroupedTree.html", []).run(["$templateCache", function($templateCache) {
22052   $templateCache.put("b2bTemplate/treeNodeCheckbox/ungroupedTree.html",
22053     "<ul role=\"{{setRole}}\"><b2b-tree-member ng-repeat='member in collection' member='member' group-it='groupIt'></b2b-tree-member></ul>");
22054 }]);