'use strict';

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

/*!
 * Ark Core v1.0.1-13 (2019-01-16)
 * http://ark.genesys.com/
 * Copyright (c) 2019 Ark Team at Genesys; */

(function (angular) {
  'use strict';

  angular.module('underscore', []).factory('_', function () {
    return window._; // assumes underscore has already been loaded on the page
  });
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core.utils', []);

  angular.module('ark.core', ['ark.core.templates', 'ark.core.utils', 'ark-ui-bootstrap', 'underscore', 'ngAnimate']);
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core.utils').filter('arkEscapeHtml', function () {
    return function (text) {
      if (text) {
        return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
      }
      return '';
    };
  });
})(angular);

(function (angular) {
  'use strict';

  // This directive allows to render the content of a JSON object inside an
  // HTML element such as <textarea>.
  // If this directive is not used, you will get `[object Object]` printed
  // From: http://stackoverflow.com/a/17904017/443600

  angular.module('ark.core.utils').directive('arkJsonText', function () {
    return {
      restrict: 'A', // only activate on element attribute
      require: 'ngModel', // get a hold of NgModelController
      link: function link(scope, element, attrs, ngModelCtrl) {
        var lastValid = void 0;

        // push() if faster than unshift(), and avail. in IE8 and earlier (unshift isn't)
        ngModelCtrl.$parsers.push(fromUser);
        ngModelCtrl.$formatters.push(toUser);

        // clear any invalid changes on blur
        element.bind('blur', function () {
          return element.val(toUser(scope.$eval(attrs.ngModel)));
        });

        // $watch(attrs.ngModel) wouldn't work if this directive created a new scope;
        // see http://stackoverflow.com/questions/14693052/watch-ngmodel-from-inside-directive-using-isolate-scope how to do it then
        scope.$watch(attrs.ngModel, function (newValue, oldValue) {
          lastValid = lastValid || newValue;

          if (newValue !== oldValue) {
            ngModelCtrl.$setViewValue(toUser(newValue));

            // TODO avoid this causing the focus of the input to be lost..
            ngModelCtrl.$render();
          }
        }, true); // MUST use objectEquality (true) here, for some reason..

        function fromUser(text) {
          // Beware: trim() is not available in old browsers
          if (!text || text.trim() === '') {
            return {};
          } else {
            try {
              lastValid = angular.fromJson(text);
              ngModelCtrl.$setValidity('invalidJson', true);
            } catch (e) {
              ngModelCtrl.$setValidity('invalidJson', false);
            }
            return lastValid;
          }
        }

        function toUser(object) {
          // better than JSON.stringify(), because it formats + filters $$hashKey etc.
          return angular.toJson(object, true);
        }
      }
    };
  });
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core.utils')

  /**
   * truncate filter provides a way to truncate a text.
   * @param  {string} value     The string that will be truncated.
   * @param  {bool}   wordwise  If the process should be aware of words so they are not cut in the middle.
   * @param  {number} max       The maximum number of characters.
   * @param  {string} tail      The character that should be appened at the end of the truncated string.
   * @return {string}  The truncated string.
   */
  .filter('truncate', function () {
    return function (value, wordwise, max, tail) {
      if (!value) {
        return '';
      }

      max = parseInt(max, 10);

      if (!max) {
        return value;
      }

      if (value.length <= max) {
        return value;
      }

      value = value.substr(0, max);

      if (wordwise) {
        var lastspace = value.lastIndexOf(' ');
        if (lastspace !== -1) {
          value = value.substr(0, lastspace);
        }
      }

      return value + (tail || '…');
    };
  });
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').controller('ArkAppLauncherCtrl', ['$scope', '$window', '$timeout', '$log', '_', 'arkNavMenuModel', function ($scope, $window, $timeout, $log, _, arkNavMenuModel) {
    var delegate = $scope.delegate;

    $scope.customAction = function customAction(item) {
      var confirmation;
      if (item.id && item.url && delegate.customAction[item.id]) {
        if (item.requireConfirmation) {
          confirmation = $window.confirm(delegate.localization.localizedStrings.ARE_YOU_SURE);
          if (confirmation) {
            delegate.customAction[item.id](item.url);
          }
        } else {
          delegate.customAction[item.id](item.url);
        }
      }
    };

    (function init() {
      var i18n = $scope.appSettings.i18n[delegate.localization.currentLanguage];
      var localization = delegate.localization;

      $scope.user = $scope.userData.user;

      $scope.usermenu = getUserMenu($scope.appSettings.usermenu, i18n);

      $scope.currentAppName = $scope.appSettings.appDisplayName;
      $scope.aboutApplication = delegate.aboutApplication;
      $scope.baseUrlAssets = $scope.appSettings.baseUrlAssets;

      function onTranslateChangeSuccess() {
        $scope.currentLanguage = _.findWhere(localization.languages, {
          id: localization.currentLanguageId
        });
        $scope.usermenu = getUserMenu($scope.appSettings.usermenu, localization.localizedStrings);
      }

      if (localization) {
        $scope.localization = localization;
        $scope.localizationIcons = {};
        _.each(localization.languages, function (item) {
          var country = /\-([^\-]*)/.exec(item.id)[1];
          $scope.localizationIcons[item.id] = 'country-' + country.toLowerCase();
        });

        // Listen when translation change
        // TODO: Refactor
        $scope.$root.$on('$translateChangeSuccess', onTranslateChangeSuccess);
        // Initial state
        onTranslateChangeSuccess();

        $scope.changeLanguage = function (langId) {
          var selectedLanguage = _.findWhere(localization.languages, {
            id: langId
          });
          if (selectedLanguage) {
            $scope.currentLanguage = selectedLanguage;
            if (localization.changeLanguage) {
              localization.changeLanguage(langId).then(function (localizedStrings) {
                localization.localizedStrings = localizedStrings;
              });
            }
          } else {
            $log.error('Could not change to language', langId, 'as it could not be found');
          }
        };
      }

      $scope.appGroups = $scope.userData.getAppGroups && $scope.userData.getAppGroups();
      // TODO: get rid of previous line and replace it with following
      // if ($scope.userData.widgets) {
      //   $scope.appGroups = _.groupBy(_.where($scope.userData.widgets, {
      //     'status': 'ok'
      //   }), 'category');
      // }
    })();

    function getUserMenu(rawUserMenu, i18n) {
      var usermenu = _.filter(arkNavMenuModel(rawUserMenu, i18n), function (elem) {
        return elem.disable !== true;
      });
      // Get rid of last element if divider
      if (usermenu[usermenu.length - 1].isDivider) {
        usermenu.splice(-1, 1);
      }
      return usermenu;
    }
  }]);
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').directive('arkAppLauncher', function () {
    return {
      templateUrl: 'ark-app-launcher/ark-app-launcher.html',
      restrict: 'E',
      transclude: false,
      replace: true,
      scope: {
        delegate: '=',
        helpmenu: '=',
        appSettings: '=',
        userData: '=',
        appLauncherEnable: '='
      },
      controller: 'ArkAppLauncherCtrl'
    };
  });
})(angular);

(function (angular) {
  // jshint camelcase: false
  // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
  'use strict';

  angular.module('ark.core').factory('arkNavMenuItemModel', function () {
    function arkNavMenuItemModel(item, i18n) {
      var processedItem;
      if (item) {
        processedItem = {};
        processedItem.id = item.id || '';
        processedItem.name = item.name || item.id || '';
        processedItem.fonticon = item.fonticon || '';
        processedItem.url = item.url || '';
        processedItem.target = item.target || '';
        processedItem.customAction = item.custom_action || false;
        processedItem.requireConfirmation = item.require_confirmation || false;
        processedItem.disable = item.disable || false;
        if (i18n && item.id && i18n[item.id]) {
          processedItem.name = i18n[item.id];
        }
        processedItem.isDivider = item.type && item.type === 'divider' || false;
      }
      return processedItem;
    }

    return arkNavMenuItemModel;
  });
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').factory('arkNavMenuModel', ['arkNavMenuItemModel', '$log', function (arkNavMenuItemModel, $log) {
    function arkNavMenu(items, i18n) {
      var i;
      var processedItems = [];
      if (items && angular.isArray(items)) {
        for (i in items) {
          if (items.hasOwnProperty(i)) {
            processedItems.push(arkNavMenuItemModel(items[i], i18n));
          }
        }
      } else {
        $log.error('arkNavMenu: items not an array');
      }
      return processedItems;
    }

    return arkNavMenu;
  }]);
})(angular);

(function (angular) {
  // jscs:disable disallowMultipleVarDecl
  'use strict';

  angular.module('ark.core').service('arkDateParser', ['$log', '$locale', 'orderByFilter', function ($log, $locale, orderByFilter) {
    // Pulled from https://github.com/mbostock/d3/blob/master/src/format/requote.js
    var SPECIAL_CHARACTERS_REGEXP = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;

    var localeId;
    var formatCodeToRegex;
    // https://stackoverflow.com/questions/29988868/why-does-parsing-a-locale-date-string-result-in-an-invalid-date
    // https://stackoverflow.com/questions/25574963/ies-tolocalestring-has-strange-characters-in-results
    var isLocaleDateParsable = !isNaN(Date.parse(new Date(1991, 11, 30).toLocaleString().replace(/[^ -~]/g, '')));
    var toLocaleStringLocale = 'en-US';
    var toLocaleStringOptions = {
      year: 'numeric',
      month: 'long',
      day: 'numeric',
      hour: '2-digit',
      minute: '2-digit',
      hour12: new Date().toLocaleString().match(/am|pm/i) || new Date().toString().match(/am|pm/i)
    };

    this.init = function () {
      localeId = $locale.id;

      this.parsers = {};

      formatCodeToRegex = [{
        key: 'yyyy',
        regex: '\\d{4}',
        apply: function apply(value) {
          this.year = +value;
        }
      }, {
        key: 'yy',
        regex: '\\d{2}',
        apply: function apply(value) {
          this.year = +value + 2000;
        }
      }, {
        key: 'y',
        regex: '\\d{1,4}',
        apply: function apply(value) {
          this.year = +value;
        }
      }, {
        key: 'M!',
        regex: '0?[1-9]|1[0-2]',
        apply: function apply(value) {
          this.month = value - 1;
        }
      }, {
        key: 'MMMM',
        regex: $locale.DATETIME_FORMATS.MONTH.join('|'),
        apply: function apply(value) {
          this.month = $locale.DATETIME_FORMATS.MONTH.indexOf(value);
        }
      }, {
        key: 'MMM',
        regex: $locale.DATETIME_FORMATS.SHORTMONTH.join('|'),
        apply: function apply(value) {
          this.month = $locale.DATETIME_FORMATS.SHORTMONTH.indexOf(value);
        }
      }, {
        key: 'MM',
        regex: '0[1-9]|1[0-2]',
        apply: function apply(value) {
          this.month = value - 1;
        }
      }, {
        key: 'M',
        regex: '[1-9]|1[0-2]',
        apply: function apply(value) {
          this.month = value - 1;
        }
      }, {
        key: 'd!',
        regex: '[0-2]?[0-9]{1}|3[0-1]{1}',
        apply: function apply(value) {
          this.date = +value;
        }
      }, {
        key: 'dd',
        regex: '[0-2][0-9]{1}|3[0-1]{1}',
        apply: function apply(value) {
          this.date = +value;
        }
      }, {
        key: 'd',
        regex: '[1-2]?[0-9]{1}|3[0-1]{1}',
        apply: function apply(value) {
          this.date = +value;
        }
      }, {
        key: 'EEEE',
        regex: $locale.DATETIME_FORMATS.DAY.join('|')
      }, {
        key: 'EEE',
        regex: $locale.DATETIME_FORMATS.SHORTDAY.join('|')
      }, {
        key: 'HH',
        regex: '(?:0|1)[0-9]|2[0-3]',
        apply: function apply(value) {
          this.hours = +value;
        }
      }, {
        key: 'hh',
        regex: '0[0-9]|1[0-2]',
        apply: function apply(value) {
          this.hours = +value;
        }
      }, {
        key: 'H',
        regex: '1?[0-9]|2[0-3]',
        apply: function apply(value) {
          this.hours = +value;
        }
      }, {
        key: 'h',
        regex: '[0-9]|1[0-2]',
        apply: function apply(value) {
          this.hours = +value;
        }
      }, {
        key: 'mm',
        regex: '[0-5][0-9]',
        apply: function apply(value) {
          this.minutes = +value;
        }
      }, {
        key: 'm',
        regex: '[0-9]|[1-5][0-9]',
        apply: function apply(value) {
          this.minutes = +value;
        }
      }, {
        key: 'sss',
        regex: '[0-9][0-9][0-9]',
        apply: function apply(value) {
          this.milliseconds = +value;
        }
      }, {
        key: 'ss',
        regex: '[0-5][0-9]',
        apply: function apply(value) {
          this.seconds = +value;
        }
      }, {
        key: 's',
        regex: '[0-9]|[1-5][0-9]',
        apply: function apply(value) {
          this.seconds = +value;
        }
      }, {
        key: 'a',
        regex: $locale.DATETIME_FORMATS.AMPMS.join('|'),
        apply: function apply(value) {
          if (this.hours === 12) {
            this.hours = 0;
          }

          if (value === 'PM') {
            this.hours += 12;
          }
        }
      }, {
        key: 'Z',
        regex: '[+-]\\d{4}',
        apply: function apply(value) {
          var matches = value.match(/([+-])(\d{2})(\d{2})/),
              sign = matches[1],
              hours = matches[2],
              minutes = matches[3];
          this.hours += toInt(sign + hours);
          this.minutes += toInt(sign + minutes);
        }
      }, {
        key: 'ww',
        regex: '[0-4][0-9]|5[0-3]'
      }, {
        key: 'w',
        regex: '[0-9]|[1-4][0-9]|5[0-3]'
      }];
      // TODO: Not supported till Angular 1.3.15
      // {
      //  key: 'GGGG',
      //  regex: $locale.DATETIME_FORMATS.ERANAMES.join('|').replace(/\s/g, '\\s')
      // },
      // {
      //  key: 'GGG',
      //  regex: $locale.DATETIME_FORMATS.ERAS.join('|')
      // },
      // {
      //  key: 'GG',
      //  regex: $locale.DATETIME_FORMATS.ERAS.join('|')
      // },
      // {
      //  key: 'G',
      //  regex: $locale.DATETIME_FORMATS.ERAS.join('|')
      // }
    };

    this.init();

    function createParser(format) {
      var map = [],
          regex = format.split('');

      // check for literal values
      var quoteIndex = format.indexOf('`');
      if (quoteIndex > -1) {
        var inLiteral = false;
        format = format.split('');
        for (var i = quoteIndex; i < format.length; i++) {
          if (inLiteral) {
            if (format[i] === '`') {
              if (i + 1 < format.length && format[i + 1] === '\`') {
                // escaped backtick
                format[i + 1] = '$';
                regex[i + 1] = '';
              } else {
                // end of literal
                regex[i] = '';
                inLiteral = false;
              }
            }
            format[i] = '$';
          } else if (format[i] === '`') {
            // start of literal
            format[i] = '$';
            regex[i] = '';
            inLiteral = true;
          }
        }

        format = format.join('');
      }

      angular.forEach(formatCodeToRegex, function (data) {
        var index = format.indexOf(data.key);

        if (index > -1) {
          format = format.split('');

          regex[index] = '(' + data.regex + ')';
          format[index] = '$'; // Custom symbol to define consumed part of format
          for (var i = index + 1, n = index + data.key.length; i < n; i++) {
            regex[i] = '';
            format[i] = '$';
          }
          format = format.join('');

          map.push({
            index: index,
            apply: data.apply,
            matcher: data.regex
          });
        }
      });

      return {
        regex: new RegExp('^' + regex.join('') + '$'),
        map: orderByFilter(map, 'index')
      };
    }

    this.parse = function (input, format, baseDate) {
      if (!angular.isString(input) || !format) {
        return input;
      }

      format = $locale.DATETIME_FORMATS[format] || format;
      format = format.replace(SPECIAL_CHARACTERS_REGEXP, '\\$&');

      if ($locale.id !== localeId) {
        this.init();
      }

      if (!this.parsers[format]) {
        this.parsers[format] = createParser(format);
      }

      var parser = this.parsers[format],
          regex = parser.regex,
          map = parser.map,
          results = input.match(regex),
          tzOffset = false;
      if (results && results.length) {
        var fields, dt;
        if (angular.isDate(baseDate) && !isNaN(baseDate.getTime())) {
          fields = {
            year: baseDate.getFullYear(),
            month: baseDate.getMonth(),
            date: baseDate.getDate(),
            hours: baseDate.getHours(),
            minutes: baseDate.getMinutes(),
            seconds: baseDate.getSeconds(),
            milliseconds: baseDate.getMilliseconds()
          };
        } else {
          if (baseDate) {
            $log.warn('dateparser:', 'baseDate is not a valid date');
          }
          fields = {
            year: 1900,
            month: 0,
            date: 1,
            hours: 0,
            minutes: 0,
            seconds: 0,
            milliseconds: 0
          };
        }

        for (var i = 1, n = results.length; i < n; i++) {
          var mapper = map[i - 1];
          if (mapper.matcher === 'Z') {
            tzOffset = true;
          }

          if (mapper.apply) {
            mapper.apply.call(fields, results[i]);
          }
        }

        var datesetter = tzOffset ? Date.prototype.setUTCFullYear : Date.prototype.setFullYear;
        var timesetter = tzOffset ? Date.prototype.setUTCHours : Date.prototype.setHours;

        if (isValid(fields.year, fields.month, fields.date)) {
          if (angular.isDate(baseDate) && !isNaN(baseDate.getTime()) && !tzOffset) {
            dt = new Date(baseDate);
            datesetter.call(dt, fields.year, fields.month, fields.date);
            timesetter.call(dt, fields.hours, fields.minutes, fields.seconds, fields.milliseconds);
          } else {
            dt = new Date(0);
            datesetter.call(dt, fields.year, fields.month, fields.date);
            timesetter.call(dt, fields.hours || 0, fields.minutes || 0, fields.seconds || 0, fields.milliseconds || 0);
          }
        }

        return dt;
      }
    };

    this.toLocaleString = function (date, locale, options) {
      var localeString;
      if (!isLocaleDateParsable || locale || options) {
        localeString = new Date(date).toLocaleString(locale || toLocaleStringLocale, options || toLocaleStringOptions);
      } else {
        localeString = new Date(date).toLocaleString();
      }
      // in IE there's additional symbol that makes date unparseable
      return localeString.replace(/[^ -~]/g, '');
    };

    // Check if date is valid for specific month (and year for February).
    // Month: 0 = Jan, 1 = Feb, etc
    function isValid(year, month, date) {
      if (date < 1) {
        return false;
      }

      if (month === 1 && date > 28) {
        return date === 29 && (year % 4 === 0 && year % 100 !== 0 || year % 400 === 0);
      }

      if (month === 3 || month === 5 || month === 8 || month === 10) {
        return date < 31;
      }

      return true;
    }

    function toInt(str) {
      return parseInt(str, 10);
    }
  }]);
})(angular);

// jshint -W097
'use strict';

angular.module('ark.core').directive('arkDatepickerPopupWrap', ['$templateCache', function ($templateCache) {
  return {
    restrict: 'EA',
    replace: true,
    transclude: true,
    template: $templateCache.get('ark-datepicker/ark-datepicker-popup-wrap.html'),
    link: function link(scope, element) {
      element.bind('click', function (event) {
        event.preventDefault();
        event.stopPropagation();
      });
    }
  };
}]);

// jshint -W097
'use strict';

angular.module('ark.core').constant('arkDatepickerPopupConfig', {
  datepickerPopup: 'yyyy-MM-dd',
  currentText: 'Today',
  clearText: 'Clear',
  closeText: 'Done',
  closeOnDateSelection: true,
  appendToBody: false,
  showButtonBar: false
});

// jshint -W097
// jscs:disable disallowMultipleVarDecl
'use strict';

angular.module('ark.core').directive('arkDatepickerPopup', ['$compile', '$parse', '$document', '$position', '$timeout', 'dateFilter', 'arkDatepickerPopupConfig', 'arkDateParser', function ($compile, $parse, $document, $position, $timeout, dateFilter, arkDatepickerPopupConfig, arkDateParser) {
  return {
    restrict: 'EA',
    require: 'ngModel',
    scope: {
      isOpen: '=?',
      currentText: '@',
      clearText: '@',
      closeText: '@',
      dateDisabled: '&',
      ngDisabled: '=?'
    },
    link: function link(scope, element, attrs, ngModel) {
      var dateFormat,
          closeOnDateSelection = angular.isDefined(attrs.closeOnDateSelection) ? scope.$parent.$eval(attrs.closeOnDateSelection) : arkDatepickerPopupConfig.closeOnDateSelection,
          appendToBody = angular.isDefined(attrs.datepickerAppendToBody) ? scope.$parent.$eval(attrs.datepickerAppendToBody) : arkDatepickerPopupConfig.appendToBody,
          timepickerEnabled = scope.$eval(attrs.timepickerMode),
          timezoneEnabled = scope.$eval(attrs.timezoneMode),
          dateTimeDefault;

      if (attrs.dateTimeDefault === 'today') {
        dateTimeDefault = new Date();
        dateTimeDefault.setSeconds(0);
      } else if (!isNaN(new Date(attrs.dateTimeDefault))) {
        dateTimeDefault = new Date(attrs.dateTimeDefault);
      } else {
        dateTimeDefault = null;
      }

      scope.showButtonBar = angular.isDefined(attrs.showButtonBar) ? scope.$parent.$eval(attrs.showButtonBar) : arkDatepickerPopupConfig.showButtonBar;

      scope.getText = function (key) {
        return scope[key + 'Text'] || arkDatepickerPopupConfig[key + 'Text'];
      };

      attrs.$observe('arkDatepickerPopup', function (value) {
        dateFormat = value || arkDatepickerPopupConfig.datepickerPopup;
        ngModel.$render();
      });

      // popup element used to display calendar
      var popupEl = angular.element('<div ark-datepicker-popup-wrap><div ark-datepicker></div></div>');
      popupEl.attr({
        'ng-model': 'date',
        'ng-change': 'dateSelection()'
      });

      function cameltoDash(string) {
        return string.replace(/([A-Z])/g, function ($1) {
          return '-' + $1.toLowerCase();
        });
      }

      // datepicker element
      var datepickerEl = angular.element(popupEl.children()[0]);
      if (attrs.datepickerOptions) {
        angular.forEach(scope.$parent.$eval(attrs.datepickerOptions), function (value, option) {
          datepickerEl.attr(cameltoDash(option), value);
        });
      }

      angular.forEach(['minDate', 'maxDate'], function (key) {
        if (attrs[key]) {
          scope.$parent.$watch($parse(attrs[key]), function (value) {
            scope[key] = value;
          });
          datepickerEl.attr(cameltoDash(key), key);
        }
      });

      // Apply attributes from input to datepicker element
      if (attrs.dateDisabled) {
        datepickerEl.attr('date-disabled', 'dateDisabled({ date: date, mode: mode })');
      }
      if (attrs.timepickerMode) {
        datepickerEl.attr('timepicker-mode', attrs.timepickerMode);
      }
      if (attrs.timezoneMode) {
        datepickerEl.attr('timezone-mode', attrs.timezoneMode);
      }
      if (attrs.dateTimeDefault) {
        datepickerEl.attr('date-time-default', attrs.dateTimeDefault);
      }

      // TODO: reverse from dateFilter string to Date object
      function parseDate(viewValue) {
        if (!viewValue) {
          ngModel.$setValidity('date', true);
          return null;
        } else if (angular.isDate(viewValue) && !isNaN(viewValue)) {
          ngModel.$setValidity('date', true);
          return viewValue;
        } else if (angular.isString(viewValue)) {
          var date = arkDateParser.parse(viewValue, dateFormat, scope.date) || new Date(viewValue);
          if (isNaN(date)) {
            ngModel.$setValidity('date', false);
            return undefined;
          } else {
            ngModel.$setValidity('date', true);
            return date;
          }
        } else {
          ngModel.$setValidity('date', false);
          return undefined;
        }
      }
      ngModel.$parsers.unshift(parseDate);

      // Inner change
      scope.dateSelection = function (dt) {
        if (angular.isDefined(dt)) {
          scope.date = dt;
          if (timepickerEnabled && timezoneEnabled && dt !== null) {
            // format date string for timezoneEnabled
            scope.prevTimezone = angular.isUndefined(scope.prevTimezone) ? 'GMT-04:00' : scope.prevTimezone;
            ngModel.$setViewValue(arkDateParser.toLocaleString(dt) + ' ' + scope.prevTimezone);
          } else if (timepickerEnabled && dt !== null) {
            // format date string for timepickerEnabled
            ngModel.$setViewValue(arkDateParser.toLocaleString(dt));
          } else {
            // format date string for default
            ngModel.$setViewValue(dt);
          }
        } else {
          ngModel.$setViewValue(scope.date);
        }

        ngModel.$render();

        if (closeOnDateSelection && !(timepickerEnabled || timezoneEnabled)) {
          scope.isOpen = false;
        }
      };

      element.bind('input change keyup', function () {
        scope.$evalAsync(function () {
          scope.date = ngModel.$modelValue;
        });
      });

      // Outter change
      ngModel.$render = function () {
        var date;
        if (!timepickerEnabled && !timezoneEnabled) {
          date = ngModel.$viewValue ? dateFilter(new Date(ngModel.$viewValue), dateFormat) : '';
          scope.date = parseDate(ngModel.$viewValue);
        } else if (timepickerEnabled) {
          date = ngModel.$viewValue ? ngModel.$viewValue : '';
          scope.date = parseDate(ngModel.$modelValue);
        } else {
          date = ngModel.$viewValue ? ngModel.$viewValue : '';
        }
        element.val(date);
      };

      var documentClickBind = function documentClickBind(event) {
        if (scope.isOpen && event.target !== element[0]) {
          scope.$evalAsync(function () {
            scope.isOpen = false;
          });
        }
      };

      var openCalendar = function openCalendar() {
        scope.$evalAsync(function () {
          scope.isOpen = true;
        });
      };

      scope.$watch('isOpen', function (value) {
        if (value) {
          scope.position = appendToBody ? $position.offset(element) : $position.position(element);
          scope.position.top = scope.position.top + element.prop('offsetHeight');

          $document.bind('click', documentClickBind);
          element.unbind('focus', openCalendar);
          element[0].focus();
        } else {
          $document.unbind('click', documentClickBind);
          element.bind('focus', openCalendar);
        }
      });

      scope.$watch('ngDisabled', function () {
        if (scope.ngDisabled) {
          $timeout(function () {
            scope.select(null);
          });
        } else if (attrs.timepickerMode) {
          scope.select(dateTimeDefault);
        }
      });

      scope.select = function (date) {
        if (date === 'today') {
          var today = new Date();

          if (angular.isDate(ngModel.$modelValue) || timezoneEnabled && ngModel.$viewValue !== null && angular.isDate(new Date(ngModel.$viewValue.toString().split('GMT')[0]))) {
            // Checking for valid time before timezone to preserve with date select

            var potentialTimeZone = ngModel.$viewValue.toString().split('GMT')[1] ? ngModel.$viewValue.toString().split('GMT')[1] : scope.prevTimezone;
            scope.prevTimezone = potentialTimeZone ? 'GMT' + potentialTimeZone : 'GMT-04:00'; // Set to GMT-04:00 if undefined
            date = timezoneEnabled ? new Date(ngModel.$viewValue.split(' GMT')[0]) : new Date(ngModel.$modelValue);
            date.setFullYear(today.getFullYear(), today.getMonth(), today.getDate());
          } else {

            if (timezoneEnabled && angular.isUndefined(scope.prevTimezone)) {
              scope.prevTimezone = 'GMT-04:00';
            } // If no prev when select is called, default
            date = new Date(today.setHours(0, 0, 0, 0));
          }
        }

        scope.dateSelection(date);
      };

      var $popup = $compile(popupEl)(scope);
      if (appendToBody) {
        $document.find('body').append($popup);
      } else {
        element.after($popup);
      }

      scope.$on('$destroy', function () {
        $popup.remove();
        element.unbind('focus', openCalendar);
        $document.unbind('click', documentClickBind);
      });
    }
  };
}]);

// jshint -W097
'use strict';

angular.module('ark.core').constant('arkDatepickerConfig', {
  formatDay: 'd',
  formatMonth: 'MMMM',
  formatYear: 'yyyy',
  formatDayHeader: 'E',
  formatDayTitle: 'MMMM yyyy',
  formatMonthTitle: 'yyyy',
  datepickerMode: 'day',
  minMode: 'day',
  maxMode: 'year',
  showWeeks: false,
  startingDay: 0,
  yearRange: 20,
  minDate: null,
  maxDate: null
});

// jshint -W097
// jscs:disable disallowMultipleVarDecl
'use strict';

angular.module('ark.core').controller('ArkDatepickerCtrl', ['$scope', '$attrs', '$parse', '$interpolate', '$log', '$timeout', 'dateFilter', 'arkDatepickerConfig', '_', 'arkDateParser', function ($scope, $attrs, $parse, $interpolate, $log, $timeout, dateFilter, arkDatepickerConfig, _, arkDateParser) {
  $scope.timepickerEnabled = $scope.$eval($scope.timepickerMode) || false;
  $scope.timezoneEnabled = $scope.$eval($scope.timezoneMode) || false;

  var self = this,
      ngModelCtrl = {
    $setViewValue: angular.noop
  }; // nullModelCtrl;

  // Configuration attributes
  angular.forEach(['formatDay', 'formatMonth', 'formatYear', 'formatDayHeader', 'formatDayTitle', 'formatMonthTitle', 'minMode', 'maxMode', 'showWeeks', 'startingDay', 'yearRange'], function (key, index) {
    self[key] = angular.isDefined($attrs[key]) ? index < 8 ? $interpolate($attrs[key])($scope.$parent) : $scope.$parent.$eval($attrs[key]) : arkDatepickerConfig[key];
  });

  // Watchable attributes
  angular.forEach(['minDate', 'maxDate'], function (key) {
    if ($attrs[key]) {
      $scope.$parent.$watch($parse($attrs[key]), function (value) {
        self[key] = value ? new Date(value) : null;
        self.refreshView();
      });
    } else {
      self[key] = arkDatepickerConfig[key] ? new Date(arkDatepickerConfig[key]) : null;
    }
  });

  this.currentCalendarDate = angular.isDefined($attrs.initDate) ? $scope.$parent.$eval($attrs.initDate) : new Date();

  this.init = function (ngModelCtrl_) {
    ngModelCtrl = ngModelCtrl_;

    ngModelCtrl.$render = function () {
      self.render();
    };
  };

  this.render = function () {
    if (ngModelCtrl.$modelValue) {
      if ($scope.timezoneEnabled) {
        $scope.prevDate = new Date(ngModelCtrl.$modelValue.toString().split(' GMT')[0]);
      }
      var date = $scope.timezoneEnabled ? $scope.prevDate : new Date(ngModelCtrl.$modelValue);
      var isValid = !isNaN(date);

      if (isValid) {
        $scope.date = date;
        this.currentCalendarDate = date;
      } else {
        $log.error('Datepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.');
      }
      ngModelCtrl.$setValidity('date', isValid);
    }
    this.refreshView();
  };

  this.refreshView = function () {
    if (this.mode) {
      this._refreshView();
      var date;
      if ($scope.timezoneEnabled) {
        date = $scope.prevDate;
      } else {
        date = ngModelCtrl.$modelValue ? new Date(ngModelCtrl.$modelValue) : null;
      }
      ngModelCtrl.$setValidity('date-disabled', !date || this.mode && !this.isDisabled(date));
    }
  };

  this.createDateObject = function (date, format) {
    var model;
    if ($scope.timezoneEnabled) {
      model = $scope.prevDate;
    } else {
      model = ngModelCtrl.$modelValue ? new Date(ngModelCtrl.$modelValue) : null;
    }
    return {
      date: date,
      label: dateFilter(date, format),
      selected: model && this.compare(date, model) === 0,
      disabled: this.isDisabled(date),
      current: this.compare(date, new Date()) === 0
    };
  };

  this.isDisabled = function (date) {
    return this.minDate && this.compare(date, this.minDate) < 0 || this.maxDate && this.compare(date, this.maxDate) > 0 || $scope.dateDisabled && $scope.dateDisabled({
      date: date,
      mode: $scope.datepickerMode
    });
  };

  // Split array into smaller arrays
  this.split = function (arr, size) {
    var arrays = [];
    while (arr.length > 0) {
      arrays.push(arr.splice(0, size));
    }
    return arrays;
  };

  $scope.select = function (date) {
    if ($scope.datepickerMode === self.minMode) {
      var dt = ngModelCtrl.$modelValue ? new Date(ngModelCtrl.$modelValue) : new Date(0, 0, 0, 0, 0, 0, 0);
      dt.setFullYear(date.getFullYear(), date.getMonth(), date.getDate());
      if ($scope.timepickerEnabled && $scope.date) {
        dt.setHours($scope.date.getHours());
        dt.setMinutes($scope.date.getMinutes());
      }
      $scope.date = dt;

      var localeString = arkDateParser.toLocaleString(dt);

      // Remove 'at' and 'EDT' from Safari formatted strings
      localeString = localeString.replace(' at', '').replace(' EDT', '');

      if ($scope.timepickerEnabled && $scope.timezoneEnabled) {
        // format date string for timezoneEnabled
        ngModelCtrl.$setViewValue(localeString + ' ' + $scope.timeData.timeZone);
      } else if ($scope.timepickerEnabled) {
        // format date string for timepickerEnabled
        ngModelCtrl.$setViewValue(localeString);
      } else {
        // format date string for default
        ngModelCtrl.$setViewValue(dt);
      }
      ngModelCtrl.$render();
    } else {
      self.currentCalendarDate = date;
      $scope.datepickerMode = self.mode.previous;
    }
  };

  $scope.move = function (direction) {
    var year = self.currentCalendarDate.getFullYear() + direction * (self.mode.step.years || 0),
        month = self.currentCalendarDate.getMonth() + direction * (self.mode.step.months || 0);
    self.currentCalendarDate.setFullYear(year, month, 1);
    self.refreshView();
  };

  $scope.toggleMode = function () {
    $scope.datepickerMode = $scope.datepickerMode === self.maxMode ? self.minMode : self.mode.next;
  };

  // timepicker controller resources
  $scope.hourList = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'];
  $scope.minuteList = ['00', '05', '10', '15', '20', '25', '30', '35', '40', '45', '50', '55'];
  $scope.timeZoneList = ['GMT-12:00', 'GMT-11:00', 'GMT-10:00', 'GMT-09:00', 'GMT-08:00', 'GMT-07:00', 'GMT-06:00', 'GMT-05:00', 'GMT-04:30', 'GMT-04:00', 'GMT-03:30', 'GMT-03:00', 'GMT-02:00', 'GMT-01:00', 'GMT+00:00', 'GMT+01:00', 'GMT+02:00', 'GMT+03:00', 'GMT+03:30', 'GMT+04:00', 'GMT+05:00', 'GMT+05:30', 'GMT+05:45', 'GMT+06:00', 'GMT+06:30', 'GMT+07:00', 'GMT+08:00', 'GMT+09:00', 'GMT+09:30', 'GMT+10:00', 'GMT+11:00', 'GMT+12:00', 'GMT+13:00'];
  $scope.showHourList = false;
  $scope.showMinuteList = false;
  $scope.showTimeZoneList = false;
  $scope.timeZoneShow = false;

  // initialize timeData object for two-way data binding within child scopes (i.e. within ng-if)
  $scope.timeData = {
    hour: 0,
    minute: 0,
    noon: 'AM',
    timeZone: 'GMT-04:00'
  };

  var controller = this;

  this.updateTime = function (hour, minute, noon) {
    $scope.timeData.hour = hour;
    $scope.timeData.minute = minute;
    $scope.timeData.noon = noon;
  };

  // watches for changes to timeData variables
  $scope.$watchCollection('[timeData.hour, timeData.minute, timeData.noon, timeData.timeZone]', function () {
    if (!$scope.isInvalidHour() && !$scope.isInvalidMinute() && !$scope.isInvalidNoon()) {
      var newDate = $scope.date ? angular.copy($scope.date) : new Date();
      var hours = parseInt($scope.timeData.hour, 10);
      var minutes = parseInt($scope.timeData.minute, 10);
      if ($scope.timeData.noon === 'PM') {
        if (hours < 12) {
          hours = hours + 12;
        }
      } else if (hours === 12) {
        hours = 0;
      }
      newDate.setHours(hours);
      newDate.setMinutes(minutes);
      $scope.date = newDate;
      $scope.select(newDate);
    }
  });

  // Hour Section
  $scope.isInvalidHour = function () {
    return controller.isInvalidHour($scope.timeData.hour, $scope.timeData.noon);
  };

  controller.isInvalidHour = function (hour, noon) {
    return !hour || isNaN(hour) || hour.indexOf('.') !== -1 || hour.length > 2 || noon === 'AM' && (parseInt(hour, 10) > 12 || parseInt(hour, 10) < 0) || noon === 'PM' && (parseInt(hour, 10) > 12 || parseInt(hour, 10) < 1);
  };

  $scope.validateHour = function () {
    if ($scope.isInvalidHour()) {
      $scope.timeData.hour = $scope.prevHour;
    } else {
      $scope.prevHour = $scope.timeData.hour;
    }
    $scope.showHourList = false;
  };

  $scope.addHour = function () {
    if ($scope.timeData.noon === 'AM') {
      if ($scope.timeData.hour === '11') {
        $scope.timeData.noon = 'PM';
        $scope.timeData.hour = '12';
      } else {
        $scope.timeData.hour = parseInt($scope.timeData.hour, 10) % 12 + 1 + '';
      }
    } else {
      if ($scope.timeData.hour === '11') {
        $scope.timeData.noon = 'AM';
      }
      $scope.timeData.hour = parseInt($scope.timeData.hour, 10) % 12 + 1 + '';
    }
    $scope.prevHour = $scope.timeData.hour;
    $scope.prevNoon = $scope.timeData.noon;
  };

  $scope.minusHour = function () {
    if ($scope.timeData.noon === 'AM') {
      if ($scope.timeData.hour === '00' || $scope.timeData.hour === '0' || $scope.timeData.hour === '12') {
        $scope.timeData.noon = 'PM';
        $scope.timeData.hour = '11';
      } else {
        $scope.timeData.hour = parseInt($scope.timeData.hour, 10) - 1 + '';
      }
    } else {
      if ($scope.timeData.hour === '12') {
        $scope.timeData.noon = 'AM';
      }
      $scope.timeData.hour = $scope.timeData.hour === '01' || $scope.timeData.hour === '1' ? $scope.timeData.hour = '12' : parseInt($scope.timeData.hour, 10) - 1 + '';
    }
    $scope.prevHour = $scope.timeData.hour;
    $scope.prevNoon = $scope.timeData.noon;
  };

  // Minute section
  $scope.isInvalidMinute = function () {
    return controller.isInvalidMinute($scope.timeData.minute);
  };

  controller.isInvalidMinute = function (minute) {
    return !minute || isNaN(minute) || minute.indexOf('.') !== -1 || minute.length > 2 || parseInt(minute, 10) > 59 || parseInt(minute, 10) < 0;
  };

  $scope.formatNumber = function (input) {
    if (input.length === 1) {
      input = '0' + input;
    }
    return input;
  };

  $scope.addMinute = function () {
    if ($scope.timeData.minute === '59') {
      $scope.addHour();
    }
    $scope.timeData.minute = $scope.formatNumber((parseInt($scope.timeData.minute, 10) + 1) % 60 + '');
    $scope.prevMinute = $scope.timeData.minute;
  };

  $scope.minusMinute = function () {
    if ($scope.timeData.minute === '0' || $scope.timeData.minute === '00') {
      $scope.minusHour();
    }
    $scope.timeData.minute = $scope.formatNumber((parseInt($scope.timeData.minute, 10) + 59) % 60 + '');
    $scope.prevMinute = $scope.timeData.minute;
  };

  $scope.validateMinute = function () {
    if ($scope.isInvalidMinute()) {
      $scope.timeData.minute = $scope.prevMinute;
    } else {
      $scope.timeData.minute = $scope.formatNumber($scope.timeData.minute);
      $scope.prevMinute = $scope.timeData.minute;
    }
    $scope.showMinuteList = false;
  };

  // AM/PM section
  $scope.changeNoon = function () {
    if ($scope.timeData.noon === 'AM') {
      if ($scope.timeData.hour === '0' || $scope.timeData.hour === '00') {
        $scope.timeData.hour = '12';
        $scope.prevHour = $scope.timeData.hour;
      }
      $scope.timeData.noon = 'PM';
    } else {
      $scope.timeData.noon = 'AM';
    }
    $scope.prevNoon = $scope.timeData.noon;
  };

  $scope.validateNoon = function () {
    if (!$scope.isInvalidNoon()) {
      if ($scope.timeData.noon.toLowerCase() === 'pm' && $scope.timeData.hour === '0') {
        $scope.timeData.hour = '12';
        $scope.prevHour = $scope.timeData.hour;
      }
      $scope.timeData.noon = $scope.timeData.noon.toUpperCase();
      $scope.prevNoon = $scope.timeData.noon;
    } else {
      $scope.timeData.noon = $scope.prevNoon;
    }
  };

  $scope.isInvalidNoon = function () {
    return controller.isInvalidNoon($scope.timeData.noon);
  };
  // returns bool
  controller.isInvalidNoon = function (noon) {
    return noon.toUpperCase() !== 'AM' && noon.toUpperCase() !== 'PM';
  };

  // Timezone Section
  $scope.isInvalidTimeZone = function () {
    return !_.contains($scope.timeZoneList, $scope.timeData.timeZone);
  };

  $scope.validateTimeZone = function () {
    if ($scope.isInvalidTimeZone()) {
      $scope.timeData.timeZone = $scope.prevTimeZone;
    } else {
      $scope.prevTimeZone = $scope.timeData.timeZone;
    }
    $scope.showTimeZoneList = false;
  };

  $scope.addTimeZone = function () {
    if ($scope.timeZoneIndex > 0) {
      $scope.timeZoneIndex--;
    }
    $scope.timeData.timeZone = $scope.timeZoneList[$scope.timeZoneIndex];
    $scope.prevTimeZone = $scope.timeData.timeZone;
  };

  $scope.minusTimeZone = function () {
    if ($scope.timeZoneIndex < $scope.timeZoneList.length - 1) {
      $scope.timeZoneIndex++;
    }
    $scope.timeData.timeZone = $scope.timeZoneList[$scope.timeZoneIndex];
    $scope.prevTimeZone = $scope.timeData.timeZone;
  };

  // UI section
  $scope.showHour = function () {
    $scope.showHourList = true;
  };

  $scope.showMinute = function () {
    $scope.showMinuteList = true;
  };

  $scope.showTimeZone = function () {
    $scope.showTimeZoneList = true;
  };

  $scope.toggleTimeZone = function () {
    $scope.timeZoneShow = !$scope.timeZoneShow;
  };

  $scope.selectHour = function (item) {
    $scope.timeData.hour = item;
    $scope.prevHour = item;
  };

  $scope.selectMinute = function (item) {
    $scope.timeData.minute = item;
    $scope.prevMinute = item;
  };

  $scope.selectTimeZone = function (item, index) {
    $scope.timeData.timeZone = item;
    $scope.prevTimeZone = item;
    $scope.timeZoneIndex = index;
  };

  $scope.initializeTimeVars = function () {
    if ($scope.dateTimeDefault && $scope.dateTimeDefault.toLowerCase() === 'today') {
      $scope.date = new Date();
    } else if ($scope.dateTimeDefault) {
      var dateTimeDefault = new Date($scope.dateTimeDefault);
      if (!isNaN(dateTimeDefault)) {
        $scope.date = angular.copy(dateTimeDefault);
      } else {
        $scope.date = new Date();
        ngModelCtrl.$setViewValue('');
      }
    } else {
      $scope.date = new Date();
      ngModelCtrl.$setViewValue('');
    }

    $scope.timeZoneIndex = 9;
    $scope.prevTimeZone = $scope.timeZoneList[$scope.timeZoneIndex];
    $scope.timeData.timeZone = $scope.timeZoneList[$scope.timeZoneIndex];

    var hours = $scope.date.getHours();
    var minutes = $scope.date.getMinutes();
    var noon;
    if (hours >= 12) {
      noon = 'PM';
      if (hours > 12) {
        hours = hours - 12;
      }
    } else {
      noon = 'AM';
    }
    if (minutes < 10) {
      minutes = '0' + minutes;
    }
    $scope.prevHour = hours.toString();
    $scope.timeData.hour = hours.toString();
    $scope.prevMinute = minutes.toString();
    $scope.timeData.minute = minutes.toString();
    $scope.prevNoon = noon;
    $scope.timeData.noon = noon;

    if ($scope.initialized) {
      $scope.select($scope.date);
    }
  };

  (function init() {
    $scope.initialized = false;
    if ($scope.timepickerEnabled && !$scope.ngDisabled) {
      $scope.initializeTimeVars();
    }
    $scope.datepickerMode = $scope.datepickerMode || arkDatepickerConfig.datepickerMode;

    $timeout(function () {
      $scope.initialized = true;
    });
  })();
}]);

(function (angular) {
  'use strict';

  angular.module('ark.core').constant('arkDatepickerData', {
    hourList: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'],
    militaryHourList: ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24'],
    minuteList: ['00', '05', '10', '15', '20', '25', '30', '35', '40', '45', '50', '55'],
    noonList: ['AM', 'PM'],
    timeZoneList: ['GMT-12:00', 'GMT-11:00', 'GMT-10:00', 'GMT-09:00', 'GMT-08:00', 'GMT-07:00', 'GMT-06:00', 'GMT-05:00', 'GMT-04:30', 'GMT-04:00', 'GMT-03:30', 'GMT-03:00', 'GMT-02:00', 'GMT-01:00', 'GMT+00:00', 'GMT+01:00', 'GMT+02:00', 'GMT+03:00', 'GMT+03:30', 'GMT+04:00', 'GMT+05:00', 'GMT+05:30', 'GMT+05:45', 'GMT+06:00', 'GMT+06:30', 'GMT+07:00', 'GMT+08:00', 'GMT+09:00', 'GMT+09:30', 'GMT+10:00', 'GMT+11:00', 'GMT+12:00', 'GMT+13:00']
  });
})(angular);

// jshint -W097
// jscs:disable disallowMultipleVarDecl
'use strict';

angular.module('ark.core').directive('arkDatepicker', ['$templateCache', function ($templateCache) {
  return {
    restrict: 'EA',
    replace: true,
    template: $templateCache.get('ark-datepicker/ark-datepicker.html'),
    scope: {
      datepickerMode: '=?',
      dateDisabled: '&',
      timepickerMode: '@?',
      timezoneMode: '@?',
      dateTimeDefault: '@',
      ngDisabled: '=?',
      ngModel: '='
    },
    require: ['arkDatepicker', '?^ngModel'],
    controller: 'ArkDatepickerCtrl',
    link: function link(scope, element, attrs, ctrls) {
      scope.datepickerCtrl = ctrls[0];
      var ngModelCtrl = ctrls[1];

      if (ngModelCtrl) {
        scope.datepickerCtrl.init(ngModelCtrl);
      }

      scope.$watch('ngModel', function (newValue, oldValue) {
        if (typeof newValue !== 'undefined') {
          if (!isNaN(Date.parse(newValue))) {
            var newTime = new Date(newValue),
                oldTime = new Date(oldValue);
            if (newTime.toTimeString() !== oldTime.toTimeString()) {
              var hours = newTime.getHours();
              var minutes = newTime.getMinutes();
              var noon = 'AM';
              if (hours > 12) {
                hours -= 12;
                noon = 'PM';
              }
              if (hours === 12) {
                noon = 'PM';
              }
              if (hours === 0) {
                hours = 12;
              }
              if (minutes < 10) {
                minutes = '0' + minutes;
              }
              scope.datepickerCtrl.updateTime(hours.toString(), minutes.toString(), noon.toString());
            }
          }
          // else {
          //   scope.ngModel = oldValue;
          // }
        }
      });

      scope.$watch('ngDisabled', function (newValue, oldValue) {
        if (newValue === oldValue) {
          return;
        } else if (scope.ngDisabled) {
          ngModelCtrl.$setViewValue('');
        } else if (scope.initialized && scope.timepickerEnabled) {
          scope.initializeTimeVars();
        }
      });
    }
  };
}]);

// jshint -W097
// jscs:disable disallowMultipleVarDecl
'use strict';

angular.module('ark.core').directive('arkDaypicker', ['dateFilter', '$templateCache', function (dateFilter, $templateCache) {
  return {
    restrict: 'EA',
    replace: true,
    template: $templateCache.get('ark-datepicker/ark-daypicker.html'),
    require: '^arkDatepicker',
    link: function link(scope, element, attrs, ctrl) {
      scope.showWeeks = ctrl.showWeeks;

      ctrl.mode = {
        step: {
          months: 1
        },
        next: 'month'
      };

      function getDaysInMonth(year, month) {
        return new Date(year, month, 0).getDate();
      }

      function getDates(startDate, n) {
        var dates = new Array(n),
            current = new Date(startDate),
            i = 0;
        current.setHours(12); // Prevent repeated dates because of timezone bug
        while (i < n) {
          dates[i++] = new Date(current);
          current.setDate(current.getDate() + 1);
        }
        return dates;
      }

      ctrl._refreshView = function () {

        var year = ctrl.currentCalendarDate.getFullYear(),
            month = ctrl.currentCalendarDate.getMonth(),
            firstDayOfMonth = new Date(year, month, 1),
            difference = ctrl.startingDay - firstDayOfMonth.getDay(),
            numDisplayedFromPreviousMonth = difference > 0 ? 7 - difference : -difference,
            firstDate = new Date(firstDayOfMonth),
            numDates = 0;

        if (numDisplayedFromPreviousMonth > 0) {
          firstDate.setDate(-numDisplayedFromPreviousMonth + 1);
          numDates += numDisplayedFromPreviousMonth; // Previous
        }

        numDates += getDaysInMonth(year, month + 1); // Current
        numDates += (7 - numDates % 7) % 7; // Next

        var days = getDates(firstDate, numDates);

        for (var i = 0; i < numDates; i++) {
          days[i] = angular.extend(ctrl.createDateObject(days[i], ctrl.formatDay), {
            secondary: days[i].getMonth() !== month
          });
        }

        scope.labels = new Array(7);

        for (var j = 0; j < 7; j++) {

          if (ctrl.formatDayHeader === 'E') {

            // Substring grabs just the first character. This is to match AW design mockups
            scope.labels[j] = dateFilter(days[j].date, 'EEE').substr(0, 1);
          } else {

            scope.labels[j] = dateFilter(days[j].date, ctrl.formatDayHeader);
          }
        }

        scope.title = dateFilter(ctrl.currentCalendarDate, ctrl.formatDayTitle);
        scope.rows = ctrl.split(days, 7);

        if (scope.showWeeks) {
          scope.weekNumbers = [];
          var weekNumber = getISO8601WeekNumber(scope.rows[0][0].date),
              numWeeks = scope.rows.length;
          while (scope.weekNumbers.push(weekNumber++) < numWeeks) {} // jshint noempty:false
        }
      };

      ctrl.compare = function (date1, date2) {
        return new Date(date1.getFullYear(), date1.getMonth(), date1.getDate()) - new Date(date2.getFullYear(), date2.getMonth(), date2.getDate());
      };

      function getISO8601WeekNumber(date) {
        var checkDate = new Date(date);
        checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); // Thursday
        var time = checkDate.getTime();
        checkDate.setMonth(0); // Compare with Jan 1
        checkDate.setDate(1);
        return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
      }

      ctrl.refreshView();
    }
  };
}]);

// jshint -W097
// jscs:disable disallowMultipleVarDecl
'use strict';

angular.module('ark.core').directive('arkMonthpicker', ['dateFilter', '$templateCache', function (dateFilter, $templateCache) {
  return {
    restrict: 'EA',
    replace: true,
    template: $templateCache.get('ark-datepicker/ark-monthpicker.html'),
    require: '^arkDatepicker',
    link: function link(scope, element, attrs, ctrl) {
      ctrl.mode = {
        step: {
          years: 1
        },
        previous: 'day',
        next: 'year'
      };

      ctrl._refreshView = function () {
        var months = new Array(12),
            year = ctrl.currentCalendarDate.getFullYear();

        for (var i = 0; i < 12; i++) {
          months[i] = ctrl.createDateObject(new Date(year, i, 1), ctrl.formatMonth);
        }

        scope.title = dateFilter(ctrl.currentCalendarDate, ctrl.formatMonthTitle);
        scope.rows = ctrl.split(months, 3);
      };

      ctrl.compare = function (date1, date2) {
        return new Date(date1.getFullYear(), date1.getMonth()) - new Date(date2.getFullYear(), date2.getMonth());
      };

      ctrl.refreshView();
    }
  };
}]);

// jshint -W097
// jscs:disable disallowMultipleVarDecl
'use strict';

angular.module('ark.core').directive('arkYearpicker', ['dateFilter', '$templateCache', function (dateFilter, $templateCache) {
  return {
    restrict: 'EA',
    replace: true,
    template: $templateCache.get('ark-datepicker/ark-yearpicker.html'),
    require: '^arkDatepicker',
    link: function link(scope, element, attrs, ctrl) {
      ctrl.mode = {
        step: {
          years: ctrl.yearRange
        },
        previous: 'month'
      };

      ctrl._refreshView = function () {
        var range = this.mode.step.years,
            years = new Array(range),
            start = parseInt((ctrl.currentCalendarDate.getFullYear() - 1) / range, 10) * range + 1;

        for (var i = 0; i < range; i++) {
          years[i] = ctrl.createDateObject(new Date(start + i, 0, 1), ctrl.formatYear);
        }

        scope.title = [years[0].label, years[range - 1].label].join(' - ');
        scope.rows = ctrl.split(years, 5);
      };

      ctrl.compare = function (date1, date2) {
        return date1.getFullYear() - date2.getFullYear();
      };

      ctrl.refreshView();
    }
  };
}]);

(function (angular) {
  // jscs:disable
  'use strict';

  angular.module('ark.core').factory('$position', ['$document', '$window', function ($document, $window) {
    function getStyle(el, cssprop) {
      if (el.currentStyle) {
        // IE
        return el.currentStyle[cssprop];
      } else if ($window.getComputedStyle) {
        return $window.getComputedStyle(el)[cssprop];
      }
      // finally try and get inline style
      return el.style[cssprop];
    }

    /**
     * Checks if a given element is statically positioned
     * @param element - raw DOM element
     */
    function isStaticPositioned(element) {
      return (getStyle(element, 'position') || 'static') === 'static';
    }

    /**
     * returns the closest, non-statically positioned parentOffset of a given element
     * @param element
     */
    var parentOffsetEl = function parentOffsetEl(element) {
      var docDomEl = $document[0];
      var offsetParent = element.offsetParent || docDomEl;
      while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent)) {
        offsetParent = offsetParent.offsetParent;
      }
      return offsetParent || docDomEl;
    };

    return {
      /**
       * Provides read-only equivalent of jQuery's position function:
       * http://api.jquery.com/position/
       */
      position: function position(element) {
        var elBCR = this.offset(element);
        var offsetParentBCR = {
          top: 0,
          left: 0
        };
        var offsetParentEl = parentOffsetEl(element[0]);
        if (offsetParentEl !== $document[0]) {
          offsetParentBCR = this.offset(angular.element(offsetParentEl));
          offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop;
          offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft;
        }

        var boundingClientRect = element[0].getBoundingClientRect();
        return {
          width: boundingClientRect.width || element.prop('offsetWidth'),
          height: boundingClientRect.height || element.prop('offsetHeight'),
          top: elBCR.top - offsetParentBCR.top,
          left: elBCR.left - offsetParentBCR.left
        };
      },

      /**
       * Provides read-only equivalent of jQuery's offset function:
       * http://api.jquery.com/offset/
       */
      offset: function offset(element) {
        var boundingClientRect = element[0].getBoundingClientRect();
        return {
          width: boundingClientRect.width || element.prop('offsetWidth'),
          height: boundingClientRect.height || element.prop('offsetHeight'),
          top: boundingClientRect.top + ($window.pageYOffset || $document[0].documentElement.scrollTop),
          left: boundingClientRect.left + ($window.pageXOffset || $document[0].documentElement.scrollLeft)
        };
      },

      /**
       * Provides coordinates for the targetEl in relation to hostEl
       */
      positionElements: function positionElements(hostEl, targetEl, positionStr, appendToBody) {

        var positionStrParts = positionStr.split('-');
        var pos0 = positionStrParts[0],
            pos1 = positionStrParts[1] || 'center';

        var hostElPos, targetElWidth, targetElHeight, targetElPos;

        hostElPos = appendToBody ? this.offset(hostEl) : this.position(hostEl);

        targetElWidth = targetEl.prop('offsetWidth');
        targetElHeight = targetEl.prop('offsetHeight');

        var shiftWidth = {
          center: function center() {
            return hostElPos.left + hostElPos.width / 2 - targetElWidth / 2;
          },
          left: function left() {
            return hostElPos.left;
          },
          right: function right() {
            return hostElPos.left + hostElPos.width;
          }
        };

        var shiftHeight = {
          center: function center() {
            return hostElPos.top + hostElPos.height / 2 - targetElHeight / 2;
          },
          top: function top() {
            return hostElPos.top;
          },
          bottom: function bottom() {
            return hostElPos.top + hostElPos.height;
          }
        };

        switch (pos0) {
          case 'right':
            targetElPos = {
              top: shiftHeight[pos1](),
              left: shiftWidth[pos0]()
            };
            break;
          case 'left':
            targetElPos = {
              top: shiftHeight[pos1](),
              left: hostElPos.left - targetElWidth
            };
            break;
          case 'bottom':
            targetElPos = {
              top: shiftHeight[pos0](),
              left: shiftWidth[pos1]()
            };
            break;
          default:
            targetElPos = {
              top: hostElPos.top - targetElHeight,
              left: shiftWidth[pos1]()
            };
            break;
        }

        return targetElPos;
      }
    };
  }]);
})(angular);

(function (angular) {
  'use strict';

  var ArkExpandablePanelComponent = {
    bindings: {
      expanded: '=?',
      side: '@?'
    },
    transclude: true,
    templateUrl: 'ark-expandable-panel/ark-expandable-panel.html',
    controller: function () {
      function ArkExpandablePanelController() {
        _classCallCheck(this, ArkExpandablePanelController);
      }

      _createClass(ArkExpandablePanelController, [{
        key: '$onInit',
        value: function $onInit() {
          this.expanded = this.expanded === undefined ? true : this.expanded;
          this.side = this.side || 'right';
        }
      }, {
        key: 'togglePanel',
        value: function togglePanel() {
          this.expanded = !this.expanded;
        }
      }, {
        key: 'otherSide',
        value: function otherSide(side) {
          return side === 'left' ? 'right' : 'left';
        }
      }]);

      return ArkExpandablePanelController;
    }()
  };

  angular.module('ark.core').component('arkExpandablePanel', ArkExpandablePanelComponent);
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').controller('ArkFilterBarCtrl', ['$scope', function ($scope) {
    var ctrl = this;

    ctrl.i18n = {
      'SEARCH': 'Search',
      'SEARCH_FOR': 'Search for',
      'NOT_FOUND': 'not found'
    };

    $scope.hasContent = false;
    $scope.isSearching = false;
    $scope.displayDropdown = false;
    $scope.items = [];

    $scope.clearInputText = function () {
      $scope.searchText = '';
    };

    $scope.isActive = function (matchIndex) {
      return $scope.active === matchIndex;
    };

    $scope.selectActive = function (matchIndex) {
      $scope.active = matchIndex;
    };

    $scope.selectMatch = function (activeIndex) {
      $scope.select(activeIndex);
    };

    $scope.resetItems = function () {
      $scope.items = [];
      $scope.active = -1;
      $scope.isSearching = false;
      $scope.displayDropdown = false;
    };

    $scope.select = function (selectedIndex) {
      var selectedItem = $scope.items[selectedIndex];

      $scope.selectFunction({
        item: selectedItem
      });
      $scope.clickedItem = true;
      $scope.prevSearchText = selectedItem;
      $scope.searchText = selectedItem;
      $scope.isSearching = false;
      $scope.displayDropdown = false;
    };

    $scope.searchForContent = function (searchText) {
      $scope.isSearching = true;

      $scope.prevSearchText = searchText;
      $scope.filterFunction({
        searchText: $scope.searchText,
        callback: function callback(data) {
          $scope.items = $scope.itemsLength ? data.slice(0, parseInt($scope.itemsLength)) : data.slice(0, 3);
          $scope.isSearching = false;
          $scope.displayDropdown = true;
        }
      });
    };

    (function init() {
      updateLocale();
      $scope.$watch('locale', updateLocale, true);
    })();

    function updateLocale() {
      angular.extend(ctrl.i18n, $scope.locale);
    }
  }]);
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').directive('arkFilterBar', ['$timeout', function ($timeout) {
    return {
      restrict: 'E',
      scope: {
        itemsLength: '@listLength',
        filterFunction: '&',
        selectFunction: '&',
        delay: '@searchDelay',
        ngDisabled: '=?',
        locale: '='
      },
      controller: 'ArkFilterBarCtrl',
      controllerAs: 'ctrl',
      templateUrl: 'ark-filter-bar/ark-filter-bar.html',
      require: 'ngModel',
      link: function link($scope, element, attrs, ngModelCtrl) {
        $scope.newSearchText = '';
        $scope.showSearchIcon = $scope.$eval(attrs.filterBarIcon) !== false;
        var minSearch = $scope.$eval(attrs.typeaheadMinLength) || 1;
        var isEditable = $scope.$eval(attrs.typeaheadEditable) !== false;
        var focusFirst = $scope.$eval(attrs.typeaheadFocusFirst) !== false;
        var HOT_KEYS = [9, 13, 27, 38, 40];

        $scope.$watch('searchText', function (newVal) {
          ngModelCtrl.$setViewValue(newVal);
        });

        $scope.$watch('ngDisabled', function (newValue, oldValue) {
          if (newValue === oldValue) {
            return;
          } else if ($scope.ngDisabled) {
            $scope.clearInputText();
          }
        });

        // plug into $parsers pipeline to open a typeahead on view changes initiated from DOM
        // $parsers kick-in on all the changes coming from the view as well as manually triggered by $setViewValue
        ngModelCtrl.$parsers.unshift(function (newVal) {
          if (!$scope.clickedItem) {
            if (!newVal) {
              $scope.hasContent = false;
              $scope.displayDropdown = false;
            } else if (minSearch > $scope.searchText.length && $scope.searchText.length > 0) {
              $scope.hasContent = true;
              $scope.displayDropdown = false;
            } else {
              $scope.hasContent = true;
              $scope.newSearchText = newVal;

              var delay = $scope.delay ? parseInt($scope.delay) : 500;
              $timeout(function () {
                if ($scope.newSearchText === newVal && $scope.searchText) {
                  $scope.active = focusFirst ? 0 : -1;
                  $scope.searchForContent(newVal);
                }
              }, delay);
            }
          } else {
            $scope.clickedItem = false;
            ngModelCtrl.$setValidity('editable', true);
            return newVal;
          }

          if (isEditable) {
            return newVal;
          } else if (!newVal) {
            // Reset in case user had typed something previously.
            ngModelCtrl.$setValidity('editable', true);
            return newVal;
          } else {
            ngModelCtrl.$setValidity('editable', false);
            return undefined;
          }
        });

        // bind keyboard events: arrows up(38) / down(40), enter(13) and tab(9), esc(27)
        element.bind('keydown', function (evt) {
          // select is focused and a non-hot-key was pressed or no search results are displayed
          if ($scope.items.length === 0 || HOT_KEYS.indexOf(evt.which) === -1) {
            return;
          }

          // if there's nothing selected (i.e. focusFirst) and enter is hit, don't do anything
          if ($scope.active === -1 && (evt.which === 13 || evt.which === 9)) {
            return;
          }

          evt.preventDefault();

          if (evt.which === 40) {
            $scope.active = $scope.active > -1 ? ($scope.active + 1) % $scope.items.length : 0;
            $scope.$digest();
          } else if (evt.which === 38) {
            $scope.active = ($scope.active > 0 ? $scope.active : $scope.items.length) - 1;
            $scope.$digest();
          } else if (evt.which === 13 || evt.which === 9) {
            $scope.$apply(function () {
              $scope.select($scope.active);
            });
          } else if (evt.which === 27) {
            evt.stopPropagation();

            $scope.resetItems();
            $scope.$digest();
          }
        });
      }
    };
  }]);
})(angular);

(function (angular) {
  'use strict';

  var ArkFooterComponent = {
    bindings: {
      tenantLogoLink: '@',
      genesysLogoLink: '@',
      termsAndConditions: '@',
      privacyPolicy: '@',
      hidePoweredBy: '<',
      appVersion: '<',
      locale: '<'
    },
    templateUrl: 'ark-footer/ark-footer.html',
    controller: function () {
      function ArkFooterController() {
        _classCallCheck(this, ArkFooterController);
      }

      _createClass(ArkFooterController, [{
        key: '$onInit',
        value: function $onInit() {
          this.currentYear = new Date().getFullYear();
          this.localeDefault = {
            'COPYRIGHT': 'Genesys',
            'PRIVACY_POLICY': 'Privacy Policy',
            'TERMS_OF_USE': 'Terms of Use',
            'POWERED_BY': 'Powered by Genesys'
          };
          this.i18n = angular.extend({}, this.localeDefault, this.locale);
        }
      }, {
        key: '$onChanges',
        value: function $onChanges(changes) {
          if (changes && changes.locale && !changes.locale.isFirstChange() && changes.locale.currentValue !== changes.locale.previousValue) {
            this.i18n = angular.extend({}, this.localeDefault, changes.locale.currentValue);
          }
        }
      }]);

      return ArkFooterController;
    }()
  };

  angular.module('ark.core').component('arkFooter', ArkFooterComponent);
})(angular);

(function () {
  'use strict';

  angular.module('ark-loading-bar', ['ark.loadingBarInterceptor']);

  /**
   * loadingBarInterceptor service
   *
   * Registers itself as an Angular interceptor and listens for XHR requests.
   */
  angular.module('ark.loadingBarInterceptor', ['ark.loadingBarProvider']).config(['$httpProvider', function ($httpProvider) {

    var interceptor = ['$q', '$cacheFactory', '$timeout', '$rootScope', '$log', 'arkLoadingBar', function ($q, $cacheFactory, $timeout, $rootScope, $log, arkLoadingBar) {

      /**
       * The total number of requests made
       */
      var reqsTotal = 0;

      /**
       * The number of requests completed (either successfully or not)
       */
      var reqsCompleted = 0;

      /**
       * The amount of time spent fetching before showing the loading bar
       */
      var latencyThreshold = arkLoadingBar.latencyThreshold;

      /**
       * $timeout handle for latencyThreshold
       */
      var startTimeout;

      /**
       * calls arkLoadingBar.complete() which removes the
       * loading bar from the DOM.
       */
      function setComplete() {
        $timeout.cancel(startTimeout);
        arkLoadingBar.complete();
        reqsCompleted = 0;
        reqsTotal = 0;
      }

      /**
       * Determine if the response has already been cached
       *
       * @param  {Object}  config the config option from the request
       * @return {Boolean} retrns true if cached, otherwise false
       */
      function isCached(config) {
        var cache;
        var defaultCache = $cacheFactory.get('$http');
        var defaults = $httpProvider.defaults;

        // Choose the proper cache source. Borrowed from angular: $http service
        if ((config.cache || defaults.cache) && config.cache !== false && (config.method === 'GET' || config.method === 'JSONP')) {
          cache = angular.isObject(config.cache) ? config.cache : angular.isObject(defaults.cache) ? defaults.cache : defaultCache;
        }

        var cached = cache !== undefined ? cache.get(config.url) !== undefined : false;

        if (config.cached !== undefined && cached !== config.cached) {
          return config.cached;
        }
        config.cached = cached;
        return cached;
      }

      return {
        'request': function request(config) {
          // Check to make sure this request hasn't already been cached and that
          // the requester didn't explicitly ask us to ignore this request:
          if (!config.ignoreLoadingBar && !isCached(config)) {
            $rootScope.$broadcast('arkLoadingBar:loading', {
              url: config.url
            });
            if (reqsTotal === 0) {
              startTimeout = $timeout(function () {
                arkLoadingBar.start();
              }, latencyThreshold);
            }
            reqsTotal++;
            arkLoadingBar.set(reqsCompleted / reqsTotal);
          }
          return config;
        },

        'response': function response(_response) {
          if (!_response || !_response.config) {
            $log.error('Broken interceptor detected: Config object not supplied in response:\n https://github.com/chieffancypants/angular-loading-bar/pull/50');
            return _response;
          }

          if (!_response.config.ignoreLoadingBar && !isCached(_response.config)) {
            reqsCompleted++;
            $rootScope.$broadcast('arkLoadingBar:loaded', {
              url: _response.config.url,
              result: _response
            });
            if (reqsCompleted >= reqsTotal) {
              setComplete();
            } else {
              arkLoadingBar.set(reqsCompleted / reqsTotal);
            }
          }
          return _response;
        },

        'responseError': function responseError(rejection) {
          if (!rejection || !rejection.config) {
            $log.error('Broken interceptor detected: Config object not supplied in rejection:\n https://github.com/chieffancypants/angular-loading-bar/pull/50');
            return $q.reject(rejection);
          }

          if (!rejection.config.ignoreLoadingBar && !isCached(rejection.config)) {
            reqsCompleted++;
            $rootScope.$broadcast('arkLoadingBar:loaded', {
              url: rejection.config.url,
              result: rejection
            });
            if (reqsCompleted >= reqsTotal) {
              setComplete();
            } else {
              arkLoadingBar.set(reqsCompleted / reqsTotal);
            }
          }
          return $q.reject(rejection);
        }
      };
    }];

    $httpProvider.interceptors.push(interceptor);
  }]);

  /**
   * Loading Bar
   *
   * This service handles adding and removing the actual element in the DOM.
   * Generally, best practices for DOM manipulation is to take place in a
   * directive, but because the element itself is injected in the DOM only upon
   * XHR requests, and it's likely needed on every view, the best option is to
   * use a service.
   */
  angular.module('ark.loadingBarProvider', []).provider('arkLoadingBar', function () {

    this.autoIncrement = true;
    this.includeSpinner = false;
    this.includeBar = true;
    this.latencyThreshold = 100;
    this.startSize = 0.02;
    this.parentSelector = 'body';
    this.spinnerTemplate = '<div id="loading-bar-spinner"><div class="spinner-icon"></div></div>';
    this.loadingBarTemplate = '<div id="loading-bar"><div class="bar"><div class="peg"></div></div></div>';

    this.$get = ['$injector', '$document', '$timeout', '$rootScope', function ($injector, $document, $timeout, $rootScope) {

      var $animate;
      var $parentSelector = this.parentSelector;
      var loadingBarContainer = angular.element(this.loadingBarTemplate);
      var loadingBar = loadingBarContainer.find('div').eq(0);
      var spinner = angular.element(this.spinnerTemplate);

      var incTimeout, completeTimeout;
      var started = false;
      var status = 0;

      var autoIncrement = this.autoIncrement;
      var includeSpinner = this.includeSpinner;
      var includeBar = this.includeBar;
      var startSize = this.startSize;

      /**
       * Inserts the loading bar element into the dom, and sets it to 2%
       */
      function _start() {
        if (!$animate) {
          $animate = $injector.get('$animate');
        }

        var $parent = $document.find($parentSelector).eq(0);
        $timeout.cancel(completeTimeout);

        // do not continually broadcast the started event:
        if (started) {
          return;
        }

        $rootScope.$broadcast('arkLoadingBar:started');
        started = true;

        if (includeBar) {
          $animate.enter(loadingBarContainer, $parent, angular.element($parent[0].lastChild));
        }

        if (includeSpinner) {
          $animate.enter(spinner, $parent, angular.element($parent[0].lastChild));
        }

        _set(startSize);
      }

      /**
       * Set the loading bar's width to a certain percent.
       *
       * @param {number} n - any value between 0 and 1
       */
      function _set(n) {
        if (!started) {
          return;
        }
        var pct = n * 100 + '%';
        loadingBar.css('width', pct);
        status = n;

        // increment loadingbar to give the illusion that there is always
        // progress but make sure to cancel the previous timeouts so we don't
        // have multiple incs running at the same time.
        if (autoIncrement) {
          $timeout.cancel(incTimeout);
          incTimeout = $timeout(function () {
            _inc();
          }, 250);
        }
      }

      /**
       * Increments the loading bar by a random amount
       * but slows down as it progresses
       */
      function _inc() {
        if (_status() >= 1) {
          return;
        }

        var rnd = 0;

        // TODO: do this mathmatically instead of through conditions

        var stat = _status();
        if (stat >= 0 && stat < 0.25) {
          // Start out between 3 - 6% increments
          rnd = (Math.random() * (5 - 3 + 1) + 3) / 100;
        } else if (stat >= 0.25 && stat < 0.65) {
          // increment between 0 - 3%
          rnd = Math.random() * 3 / 100;
        } else if (stat >= 0.65 && stat < 0.9) {
          // increment between 0 - 2%
          rnd = Math.random() * 2 / 100;
        } else if (stat >= 0.9 && stat < 0.99) {
          // finally, increment it .5 %
          rnd = 0.005;
        } else {
          // after 99%, don't increment:
          rnd = 0;
        }

        var pct = _status() + rnd;
        _set(pct);
      }

      function _status() {
        return status;
      }

      function _completeAnimation() {
        status = 0;
        started = false;
      }

      function _complete() {
        if (!$animate) {
          $animate = $injector.get('$animate');
        }

        $rootScope.$broadcast('arkLoadingBar:completed');
        _set(1);

        $timeout.cancel(completeTimeout);

        // Attempt to aggregate any start/complete calls within 500ms:
        completeTimeout = $timeout(function () {
          var promise = $animate.leave(loadingBarContainer, _completeAnimation);
          if (promise && promise.then) {
            promise.then(_completeAnimation);
          }
          $animate.leave(spinner);
        }, 500);
      }

      return {
        start: _start,
        set: _set,
        status: _status,
        inc: _inc,
        complete: _complete,
        autoIncrement: this.autoIncrement,
        includeSpinner: this.includeSpinner,
        latencyThreshold: this.latencyThreshold,
        parentSelector: this.parentSelector,
        startSize: this.startSize
      };
    }]; //
  }); // wtf javascript. srsly
})(); //

(function (angular) {
  'use strict';

  angular.module('ark.core').component('arkLoginWrapper', {
    transclude: true,
    bindings: {
      logoUrl: '@',
      title: '@',
      loadingTitle: '@',
      isLoading: '=',
      cssClass: '@'
    },
    templateUrl: 'ark-login/ark-login-wrapper.html'
  });
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').component('arkLogin', {
    transclude: true,
    bindings: {
      loginService: '=',
      logoUrl: '@logoLink',
      showLanguageBar: '=?',
      isPasswordMandatory: '=?',
      forgotPassword: '=?',
      emptyField: '=?',
      remoteMessageUrl: '@?',
      errorField: '@?'
    },
    controller: 'ArkLoginCtrl',
    templateUrl: 'ark-login/ark-login.html'
  });
})(angular);

(function (angular) {
  /**
   * @name ArkLoginCtrl
   * @description
   *     Provides implementation for the login Controller
   */

  'use strict';

  angular.module('ark.core').controller('ArkLoginCtrl', ['$scope', '$http', '$window', '$log', function ($scope, $http, $window, $log) {
    var ctrl = this;

    // Directive variables initizaliations
    ctrl.showLanguageBar = ctrl.showLanguageBar === undefined ? true : ctrl.showLanguageBar;
    ctrl.isPasswordMandatory = ctrl.isPasswordMandatory === undefined ? true : ctrl.isPasswordMandatory;
    if (ctrl.forgotPassword) {
      ctrl.forgotPasswordFn = typeof ctrl.forgotPassword === 'function' ? ctrl.forgotPassword : function () {
        $window.open(ctrl.forgotPassword);
      };
    }

    $scope.$watch(function () {
      return ctrl.language;
    }, function (newValue) {
      if (newValue && newValue.value) {
        ctrl.changeLanguage(newValue.value);
      }
    }, true);

    ctrl.changeLanguage = function changeLanguage(langId) {
      var loginJSON = ctrl.loginService.getLoginJSON();
      if (loginJSON && loginJSON[langId]) {
        ctrl.languageId = langId;

        ctrl.loginForm = loginJSON[langId].loginForm || loginJSON[langId].loginFormTitle; // Using loginFormTitle for backwards compatibility
        // Jun 2016, some fields were renamed, so we fall back to those in case they used
        ctrl.loginForm.login = ctrl.loginForm.login || ctrl.loginForm.button;
        ctrl.loginForm.title = ctrl.loginForm.title || ctrl.loginForm.page;

        ctrl.errorMessages = loginJSON[langId].errorMessages;
        ctrl.errorMessage = ctrl.errorMessages[ctrl.errorMsgType];

        if (ctrl.loginService.changeLanguage) {
          ctrl.loginService.changeLanguage(langId);
        }
      }
    };

    ctrl.loadLanguageMenu = function loadLanguageMenu() {
      var loginJSON = ctrl.loginService.getLoginJSON();
      var keys = Object.keys(loginJSON);
      for (var i = 0; i < keys.length; i++) {
        ctrl.languageMenu.push({
          value: keys[i],
          title: loginJSON[keys[i]].title,
          errorMessages: loginJSON[keys[i]].errorMessages
        });
      }
    };

    ctrl.login = function login() {
      ctrl.isLoading = true;
      ctrl.errorMessage = '';
      ctrl.errorMsgType = '';

      if (!ctrl.username || !ctrl.password && ctrl.isPasswordMandatory) {
        ctrl.errorMessage = ctrl.errorMessages.emptyField;
        ctrl.errorMsgType = 'emptyField';
        ctrl.isLoading = false;
        return;
      }

      ctrl.loginService.login(ctrl.username, ctrl.password, ctrl.languageId, function onError(error) {
        var foundError = ctrl.errorField && error && error[ctrl.errorField] ? error[ctrl.errorField] : 'incorrectLogin';
        ctrl.errorMessage = ctrl.errorMessages[foundError] || ctrl.errorMessages.incorrectLogin;
        ctrl.errorMsgType = foundError;
        ctrl.isLoading = false;
      });
    };

    // Load remote message if remoteMessageUrl has been provided
    ctrl.obtainRemoteMessage = function obtainRemoteMessage() {
      if (angular.isDefined(ctrl.remoteMessageUrl)) {
        $http.get(ctrl.remoteMessageUrl).then(function (response) {
          ctrl.remoteMessage = response.data;
        });
      }
    };

    // Init Controller
    (function init() {
      // Variable init
      ctrl.languageMenu = [];
      ctrl.isLoading = false;

      ctrl.loginService.init(function () {
        ctrl.loadLanguageMenu();
        ctrl.language = ctrl.languageMenu[0];
      });

      ctrl.obtainRemoteMessage();

      $log.debug('(DEPRECATED) Ark Login Component is being deprecated in favor of Ark Single Login (located in the Ark Login project), please update your project. This Ark Login Component will be removed in a future Ark Core version');
    })();
  }]);
})(angular);

(function (angular) {
  'use strict';

  /**
   * @ngdoc controller
   * @name ArkNavbarCtrl
   * @description
   *     Provides implementation for the Navigation Bar Controller
   */

  angular.module('ark.core').controller('ArkNavbarCtrl', ['$scope', '$timeout', '$injector', function ($scope, $timeout, $injector) {
    $scope.sDefaultI18n = 'en-US';
    $scope.hasContent = false;
    $scope.isSearching = false;
    $scope.displayDropdown = false;
    $scope.items = [];
    $scope.searchbar = {
      searchText: ''
    };
    $scope.isCollapsed = true;

    // Backwards support when no service is passed
    $scope.service = angular.isDefined($scope.service) ? $scope.service : $injector.get('navigationBarService');

    $scope.contextualHelpOpen = true;

    $scope.testConfig = {
      product: 'GMS',
      version: '8.5.2',
      locale: 'en-US',
      role: 'ROLE_ADMIN,ROLE_SUPERVISOR',
      panelTitle: 'GMS Help',
      width: 500,
      height: 500,
      privileges: 'privileges.admin.can-use,privileges.supervisor.can-use',
      hideCloseButton: false,
      draggable: false,
      hideWidgetTitle: false,
      staticLinks: []
    };

    GenesysArkContextualHelpLauncher.api.setConfiguration($scope.testConfig , 'GMS.Callback');

    $scope.openCloseContextualHelp = function(){
      if(!$scope.contextualHelpOpen){
        GenesysArkContextualHelpLauncher.api.openWidget();
        $scope.contextualHelpOpen = true;
      }else{
        if (GenesysArkContextualHelpLauncher.wrapper) {
          GenesysArkContextualHelpLauncher.api.closeWidget();
          $scope.contextualHelpOpen = false;
        }
        else {
          GenesysArkContextualHelpLauncher.api.openWidget();
          $scope.contextualHelpOpen = true;
        }
      }
    }

    $scope.toggleCollapse = function () {
      $scope.isCollapsed = !$scope.isCollapsed;
    };

    $scope.updateNavigation = function () {
      var oJSON = $scope.service.getNavigationJSON();
      if (oJSON) {
        $scope.navigationJSON = oJSON;
        if ($scope.navigationJSON.i18n[$scope.service.getI18n()]) {
          $scope.i18n = $scope.navigationJSON.i18n[$scope.service.getI18n()];
        } else {
          $scope.i18n = $scope.navigationJSON.i18n[$scope.sDefaultI18n];
        }
      }
    };

    $scope.matchRoute = function (sRoute) {
      if ($scope.service.matchRoute) {
        return $scope.service.matchRoute(sRoute);
      }
      return {
        module: false,
        subModule: false,
        subSubModule: false
      };
    };

    $scope.clearInputText = function () {
      $scope.searchbar.searchText = '';
    };

    $scope.clickItem = function (selectedItem) {
      $scope.search.selectFunction(selectedItem);
    };

    $scope.resetAutoClose = function (id, ev) {
      if ($scope.navigationJSON.header.allowhover) {
        angular.element(ev.currentTarget.querySelector('ul .autoclose')).css('display', '');
      }
    };

    $scope.autoClose = function (event, hasChildren) {
      if ($scope.navigationJSON.header.allowhover && !angular.isDefined(hasChildren)) {
        angular.element(event.currentTarget).parent().css('display', 'none');
      }
      if (hasChildren) {
        event.stopPropagation();
      }
    };

    $scope.autoCloseSub = function (ev) {
      if ($scope.navigationJSON.header.allowhover) {
        angular.element(ev.currentTarget).parent().parent().css('display', 'none');
      }
    };

    $scope.searchForContent = function (searchText) {
      $scope.isSearching = true;
      $scope.prevSearchText = searchText;
      $scope.search.filterFunction(searchText, function (data) {
        $scope.items = $scope.itemsLength ? data.slice(0, parseInt($scope.itemsLength)) : data.slice(0, 3);
        $scope.isSearching = false;
        $scope.displayDropdown = true;
      });
    };

    $scope.service.onJSONUpdate(function () {
      $timeout(function () {
        $scope.updateNavigation();
      });
    });

    $scope.updateNavigation();
  }]);
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').directive('arkNavbar', ['$timeout', '$templateCache', '_', 'stopCloseProvider', function ($timeout, $templateCache, _, stopCloseProvider) {
    return {
      restrict: 'E',
      scope: {
        search: '=searchAction',
        service: '=?'
      },
      transclude: false,
      replace: true,
      templateUrl: 'ark-navbar/ark-navbar.html',
      controller: 'ArkNavbarCtrl',
      link: function link($scope) {
        $scope.newSearchText = '';
        $scope.stopClose = stopCloseProvider.stopClose;
        var deferSearch = _.throttle(function (newVal) {
          if ($scope.newSearchText === newVal && $scope.searchbar.searchText) {
            $scope.searchForContent(newVal);
          }
        }, 300);
        $scope.$watch('searchbar.searchText', function (newVal) {
          if (!newVal) {
            $scope.hasContent = false;
            $scope.displayDropdown = false;
          } else {
            $scope.hasContent = true;
            $scope.newSearchText = newVal;
            deferSearch(newVal);
          }
        });
      }
    };
  }])
  // Prevent dropdown from closing when clicked on an element like an input box.
  .directive('stopClose', ['stopCloseProvider', function (stopCloseProvider) {
    return {
      restrict: 'A',
      link: function link(scope, element) {
        element.bind('click', function (event) {
          event.preventDefault();
          event.stopPropagation();
        });
        stopCloseProvider.stopClose = true;
      }
    };
  }]).service('stopCloseProvider', function () {});
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').controller('ArkNestedSearchCtrl', ['$scope', '$rootScope', '$timeout', function ($scope, $rootScope, $timeout) {
    $scope.searchResults = [];
    $scope.currSearchIndex = '';
    $scope.collapseList = [];
    $scope.showClearSearch = $scope.config.showClearSearch;

    $scope.$watch('search.searchValue', function (newValue, oldValue) {
      if (newValue !== oldValue) {
        $scope.delayPromise = $timeout(function () {
          // delayed call will finally run after 'delay' amount of ms after the
          // input stops changing
          if (newValue !== $scope.search.searchValue) {
            return;
          }

          // If newValue is null or undefined, we convert it to an empty string
          // to avoid potential problems
          newValue = newValue || '';

          // Search starts
          $scope.doSearch(newValue);

          $timeout.cancel($scope.delayPromise);
          $scope.delayPromise = null;
        }, $scope.config.delay);
      }
    });

    $scope.doSearch = function (newValue) {
      // case sensitivity is set here
      var searchValue = $scope.config.caseSensitive ? newValue : newValue.toLowerCase();

      // if the query is not the required length, just clear all results and do nothing
      if (searchValue.length < $scope.config.minChars) {
        $scope.clearSearchResults();
        $scope.lastSearch = '';
      } else if ($scope.lastSearch && $scope.lastSearch.length !== 0 && searchValue.indexOf($scope.lastSearch) === 0) {
        // if the query is a continuation of a previous query, ex. 'Suga' -> 'Sugar'
        var tempList = [];
        // loop through previous query's results
        for (var i = 0; i < $scope.searchResults.length; i++) {
          // loop through searchable fields
          for (var j = 0; j < $scope.config.searchParam.length; j++) {
            // string compare is the field value to compare the query with
            // if the field matches the query, keep it. Otherwise reset it
            if (typeof $scope.searchResults[i][0][$scope.config.searchParam[j]] === 'string') {
              var stringCompare = $scope.config.caseSensitive ? $scope.searchResults[i][0][$scope.config.searchParam[j]] : $scope.searchResults[i][0][$scope.config.searchParam[j]].toLowerCase();

              if ($scope.config.indexSensitive ? stringCompare.indexOf(searchValue) === 0 : stringCompare.indexOf(searchValue) >= 0) {
                tempList.push($scope.searchResults[i]);
                break;
              } else {
                $scope.searchResults[i][0].secondarySearchResult = false;
                $scope.searchResults[i][0].primarySearchResult = false;
                $scope.toggleExpand(false, i);
              }
            }
          }
        }
        $scope.searchResults = tempList;
        // go to first result
        $scope.switchPrimaryResult('init');
        $scope.lastSearch = searchValue;
      } else {
        $scope.clearSearchResults();
        // call the recursive search for every tree in the forest
        $scope.currDepth = 0;
        for (var k = 0; k < $scope.model.length; k++) {
          $scope.recursiveSearch($scope.model[k], searchValue, $scope.recursionResultFound);
        }
        // go to first result
        $scope.switchPrimaryResult('init');
        $scope.lastSearch = searchValue;
      }
      if ($scope.callback) {
        $scope.callback({
          results: $scope.searchResults
        });
      }
    };

    $scope.recursiveSearch = function (currNode, searchValue, callback) {
      $scope.currDepth += 1;
      // only search the fields if the node is of required depth
      if ($scope.currDepth >= $scope.config.minDepth) {
        // loop through searchable fields
        for (var i = 0; i < $scope.config.searchParam.length; i++) {
          // string compare is the field value to compare the query with
          if (typeof currNode[$scope.config.searchParam[i]] === 'string') {
            var stringCompare = $scope.config.caseSensitive ? currNode[$scope.config.searchParam[i]] : currNode[$scope.config.searchParam[i]].toLowerCase();

            if ($scope.config.indexSensitive ? stringCompare.indexOf(searchValue) === 0 : stringCompare.indexOf(searchValue) >= 0) {
              callback(currNode);
              break;
            }
          }
        }
      }
      // if the node is not expanded, push it into stack as a non-expanded parent node
      if (!currNode[$scope.config.expandedParam]) {
        $scope.collapseList.push(currNode);
      }
      // recurse
      if ($scope.currDepth <= $scope.config.maxDepth && currNode[$scope.config.subTreeParam]) {
        for (var j = 0; j < currNode[$scope.config.subTreeParam].length; j++) {
          $scope.recursiveSearch(currNode[$scope.config.subTreeParam][j], searchValue, callback);
        }
      }
      // pop the non-expanded parent node
      if (!currNode[$scope.config.expandedParam]) {
        $scope.collapseList.pop();
      }
      $scope.currDepth -= 1;
    };

    $scope.recursionResultFound = function (currNode) {
      // if the field matches the query, push the following pair:
      // ['matched node','non-expanded parentNodes']
      // set as secondary result
      var tempIndex = $scope.searchResults.push([currNode, $scope.collapseList.slice(0)]) - 1;
      currNode.secondarySearchResult = true;
      if ($scope.config.expandResults === 'find') {
        $scope.toggleExpand(true, tempIndex);
      }
    };

    $scope.switchPrimaryResult = function (option) {
      switch (option) {
        case 'init':
          // set first result as primary result
          if ($scope.searchResults.length > 0) {
            $scope.currSearchIndex = 0;
            $scope.searchResults[$scope.currSearchIndex][0].primarySearchResult = true;
          }
          break;
        case 'next':
          // next result button
          $scope.searchResults[$scope.currSearchIndex][0].primarySearchResult = false;
          $scope.toggleExpand(false, $scope.currSearchIndex);
          $scope.currSearchIndex = $scope.currSearchIndex >= 0 && $scope.currSearchIndex < $scope.searchResults.length - 1 ? $scope.currSearchIndex + 1 : 0;
          $scope.searchResults[$scope.currSearchIndex][0].primarySearchResult = true;

          break;
        case 'previous':
          // previous result button
          $scope.searchResults[$scope.currSearchIndex][0].primarySearchResult = false;
          $scope.toggleExpand(false, $scope.currSearchIndex);
          $scope.currSearchIndex = $scope.currSearchIndex > 0 ? $scope.currSearchIndex - 1 : $scope.searchResults.length - 1;
          $scope.searchResults[$scope.currSearchIndex][0].primarySearchResult = true;

          break;
      }
      $scope.toggleExpand(true, $scope.currSearchIndex);
    };

    $scope.toggleExpand = function (option, index) {
      // loop through a search results list of non-expanded parent nodes, and expand them
      if ($scope.searchResults.length > 0 && $scope.searchResults[index][1]) {
        for (var h = 0; h < $scope.searchResults[index][1].length; h++) {
          $scope.searchResults[index][1][h][$scope.config.expandedParam] = option;
        }
      }
    };

    $scope.clearSearchResults = function () {
      for (var k = 0; k < $scope.searchResults.length; k++) {
        $scope.searchResults[k][0].secondarySearchResult = false;
        $scope.searchResults[k][0].primarySearchResult = false;
        $scope.toggleExpand(false, k);
      }
      $scope.searchResults = [];
      $scope.collapseList = [];
      $scope.currSearchIndex = '';
    };

    $scope.searchKeyPress = function ($event) {
      // link up and down arrows to next and previous buttons
      if ($scope.searchResults.length) {
        if ($event.which === 40) {
          $scope.switchPrimaryResult('next');
          $event.preventDefault();
        } else if ($event.which === 38) {
          $scope.switchPrimaryResult('previous');
          $event.preventDefault();
        }
      }
    };
  }]);
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').directive('arkNestedSearch', function () {
    return {
      restrict: 'E',
      scope: {
        config: '=searchOptions',
        model: '=treeModel',
        search: '=?searchModel',
        callback: '&',
        ngDisabled: '=?'
      },
      templateUrl: 'ark-nested-search/ark-nested-search.html',
      controller: 'ArkNestedSearchCtrl',
      link: function link(scope, element, attr) {
        if (angular.isDefined(attr.placeholder)) {
          scope.placeholder = attr.placeholder;
        } else {
          scope.placeholder = 'Search Items';
        }
        // Setting Defaults
        scope.config.caseSensitive = scope.config.caseSensitive || false;
        scope.config.indexSensitive = scope.config.indexSensitive || false;
        scope.config.maxDepth = scope.config.maxDepth || Number.POSITIVE_INFINITY;
        scope.config.minDepth = scope.config.minDepth || 0;
        scope.config.expandResults = scope.config.expandResults || 'focus';
        // can be set to 'focus' or 'find'
        scope.config.searchParam = scope.config.searchParam || ['label'];
        scope.config.subTreeParam = scope.config.subTreeParam || 'items';
        scope.config.expandedParam = scope.config.expandedParam || 'expanded';
        // can be set to an array of node properties to search through aswell
        scope.config.delay = scope.config.delay || 0;
        scope.config.minChars = scope.config.minChars || 1;
        // by default the Clear Search will not be available
        scope.config.showClearSearch = scope.config.showClearSearch || false;
        // Init search object
        if (!scope.search || !scope.search.searchValue) {
          scope.search = {
            searchValue: ''
          };
        }
        // If there is an init value for searchValue, trigger search
        if (scope.search.searchValue) {
          scope.doSearch(scope.search.searchValue);
        }

        scope.$watch('ngDisabled', function (newValue, oldValue) {
          if (newValue === oldValue) {
            return;
          } else if (scope.ngDisabled) {
            scope.search.searchValue = '';
          }
        });
      }
    };
  });
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').directive('arkNestedTree', ['$rootScope', function ($rootScope) {
    return {
      restrict: 'AE',
      scope: {
        treeName: '@',
        model: '=treeModel',
        config: '=treeConfig',
        setSelection: '=',
        setCheckbox: '=',
        lazyLoading: '@useLazyLoading',
        restService: '=',
        setEdited: '=',
        startEditing: '=',
        preselectedNodeId: '=?preselectedNodeId'
      },
      templateUrl: 'ark-nested-tree/ark-nested-tree.html',
      controller: 'DropdownTreeCtrl',
      link: function link(scope, element, attr) {
        $rootScope.templateIndex = 0;
        scope.checkbox = scope.$eval(attr.checkbox) || false;
        scope.editMode = scope.$eval(attr.editMode) || false;
        scope.lazyLoading = scope.$eval(attr.lazyLoading) || false;
        scope.showBorder = angular.isDefined(attr.showBorder) ? scope.$eval(attr.showBorder) : true;
        scope.dropdownArrow = angular.isDefined(attr.dropdownArrow) ? scope.$eval(attr.dropdownArrow) : true;
        scope.highlightNode = scope.$eval(attr.highlight);
        // If the user does not specify a 'highlight', then we fall back on whether checkbox is enabled or not.
        if (scope.highlightNode === undefined) {
          scope.highlightNode = !scope.checkbox;
        }

        // Object that keeps track of tree properties
        scope.treeInfo = {
          currentSelectedNode: null
        };

        scope.element = element;
        if (scope.useLeafsOnly) {
          scope.useLeafsOnly = true;
        } else {
          scope.useLeafsOnly = false;
        }
      }
    };
  }]);
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').factory('ArkNestedTreeService', function () {
    var nestedTree = {};
    var attrTreeSortOnAdd = '';

    nestedTree._replaceNodeInTree = function _replaceNodeInTree(node, model) {
      for (var i = 0; i < model.length; i++) {
        if (typeof node.id !== 'undefined' && model[i].id === node.id) {
          model[i] = node;
          return true;
        } else if (model[i].items) {
          if (nestedTree._replaceNodeInTree(node, model[i].items)) {
            return true;
          }
        }
      }
      return false;
    };

    nestedTree._sortTree = function _sortTree(data, key) {
      return data.sort(function (a, b) {
        var x = a[key];
        var y = b[key];
        return x < y ? -1 : x > y ? 1 : 0;
      });
    };

    nestedTree.setTreeSortOnAdd = function (nodeAttribute) {
      attrTreeSortOnAdd = nodeAttribute;
    };

    // Used for augmenting nodes before rendering the
    // tree for the first time. Called from the controller
    nestedTree.augmentNode = function (node, parentNode) {
      var parentId = parentNode.id || 0;
      node.isShow = (typeof node.isShow === "undefined" || node.isShow === '') ? true : node.isShow || parentNode.isShow;
      node.expanded = node.expanded || false;
      node.parentId = parentId;
      node.isGroup = node.items ? true : false;
      node.items = node.items || [];

      var checkedCount = 0;
      var isMid = false;
      if (node.items) {
        for (var i = 0; i < node.items.length; i++) {
          nestedTree.augmentNode(node.items[i], node);
          if (node.items[i].isChecked && !node.items[i].isMid) {
            checkedCount++;
          }
          if (node.items[i].isMid) {
            isMid = true;
          }
        }
      }
      node.isMid = node.isMid || (isMid || checkedCount > 0) && checkedCount !== node.items.length || false;
      node.isChecked = parentNode.isChecked || node.isMid || node.isChecked || node.items && node.items.length > 0 && checkedCount === node.items.length || false;
    };

    nestedTree.addNode = function (node, parentNode) {
      var toSearch = null;
      var exists = false;

      if (parentNode.items && !parentNode.length) {
        toSearch = parentNode.items;
        nestedTree.augmentNode(node, parentNode);
      } else if (!parentNode.items && parentNode.length) {
        toSearch = parentNode;
        nestedTree.augmentNode(node, parentNode);
      }

      if (toSearch) {
        for (var i = 0; i < toSearch.length; i++) {
          if (toSearch[i].id === node.id) {
            exists = true;
            break;
          }
        }

        if (!exists) {
          toSearch.push(node);
          if (attrTreeSortOnAdd) {
            toSearch = nestedTree._sortTree(toSearch, attrTreeSortOnAdd);
          }
        }
      }
      // Expand parent node
      parentNode.expanded = true;
    };

    nestedTree.deleteNode = function (nodeId, parentNode, recursively) {
      var toSearch = null;
      if (parentNode) {
        if (parentNode.items && !parentNode.length) {
          toSearch = parentNode.items;
        } else if (!parentNode.items && parentNode.length) {
          toSearch = parentNode;
        }
        for (var i = 0; i < toSearch.length; i++) {
          if (nodeId === toSearch[i].id) {
            toSearch.splice(i, 1);
            return true;
          } else if (recursively && toSearch[i].items) {
            if (nestedTree.deleteNode(nodeId, toSearch[i], recursively)) {
              return true;
            }
          }
        }
      }
      return false;
    };

    nestedTree.updateNode = function (newNode, nodeToBeUpdated, model, attributesToUpdate) {
      if (attributesToUpdate && attributesToUpdate.length > 0) {
        angular.forEach(attributesToUpdate, function (key) {
          nodeToBeUpdated[key] = newNode[key];
        });

        nestedTree._replaceNodeInTree(nodeToBeUpdated, model);
      }
    };

    return nestedTree;
  });
})(angular);

(function (angular) {
  /*
    @license Angular Treeview version 0.1.6
    ⓒ 2013 AHN JAE-HA http://github.com/eu81273/angular.treeview
    License: MIT
  */

  // jshint funcscope:true
  // jshint shadow:true

  'use strict';

  angular.module('ark.core').directive('treeAutofocus', ['$timeout', function ($timeout) {
    return {
      link: function link(scope, element, attrs) {
        var focusValue = attrs.treeAutofocus;
        if (focusValue) {
          $timeout(function () {
            element[0].focus();
          });
        }
      }
    };
  }]).directive('treeEnter', function () {
    return function (scope, element, attrs) {
      element.bind('keydown keypress', function (event) {
        if (event.which === 13) {
          scope.$apply(function () {
            scope.$eval(attrs.treeEnter);
          });
          event.preventDefault();
        }
      });
    };
  }).directive('treeModel', ['$compile', '$log', '$templateCache', '$rootScope', function ($compile, $log, $templateCache, $rootScope) {
    return {
      restrict: 'AE',
      link: function link(scope, element, attrs) {
        var defaultTreeConfig = {
          'use-inline-controls': false,
          'enable-add-group-control': true,
          'add-group-icon': 'icon-folder-add',
          'add-group-callback': null,
          'enable-add-item-control': true,
          'add-item-icon': 'icon-add',
          'add-item-callback': null,
          'enable-delete-item-control': true,
          'delete-item-icon': 'icon-trash',
          'delete-item-callback': null,
          'allow-folder-edition': true,
          'max-group-depth': 3
        };
        scope.tempCheckedOptions = [];

        var treeId = attrs.treeId;
        // tree model
        var treeModel = attrs.treeModel || 'model';
        var nodeId = attrs.nodeId || 'id';
        var nodeLeafIds = attrs.nodeLeafIds || 'leafIds';
        var nodeLabel = attrs.nodeLabel || 'label';
        var nodeIcon = attrs.nodeIcon || 'icon';
        var nodeChildren = attrs.nodeChildren || 'items';
        var numOfChildren = attrs.numOfChildren || 'numberOfItems';
        var treeName = attrs.treeName || '';
        var selectorIndex = attrs.selectorIndex || '0';
        var nodeHtmlContent = attrs.nodeHtmlContent || 'htmlContent';
        var maxChildHeight = attrs.maxChildHeight || 'maxHeight';
        var levelDepth = parseInt(attrs.levelDepth) + 1;
        var treeConfig = angular.extend(defaultTreeConfig, scope.config || {});
        // var parentId = parseInt(attrs.parentId) || '0';
        var selectedShowCondition = '(node.isChecked || !selectedOnly) && node.isShow';
        var showExpandCollapseCondition = '(dropdownArrow && !node.unselectable && (node.' + numOfChildren + ' || node.' + nodeChildren + '.length))';
        var previousNodeEditingValue = {};

        // tree template
        var template = '<ul ng-class="{\'default-cursor\': editMode, \'max-height-set\': node.' + maxChildHeight + ' && (node.' + numOfChildren + ' > node.' + maxChildHeight + ' || node.' + nodeChildren + '.length > node.' + maxChildHeight + ')}" ng-style="{\'max-height\': {{ (node.' + maxChildHeight + ' * 23.45) | number:0 }} + \'px\'}">' + '<li ng-repeat="node in ' + treeModel + '" ng-class="{\'first-depth\' : ' + levelDepth + ' === 1}">' + '<div class="node-row-container" ng-init="initSelectedNode(node)" ng-class="{\'node-selected\': node.isSelected && highlightNode, \'highlight-node\': highlightNode, \'unselectable\' : node.unselectable}" ng-click="setSelectedNode();" >' + '<span class="blank" ng-show="(' + levelDepth + ' === 1 && !' + showExpandCollapseCondition + ' && ' + selectedShowCondition + ') || (' + levelDepth + '!== 1 && (!dropdownArrow || node.unselectable) && (node.' + numOfChildren + ' || node.' + nodeChildren + '.length))"><span class="blank fonticon icon-chevron-left"></span></span>' + '<span class="elbow" ng-show="' + levelDepth + ' !== 1 && !node.' + nodeChildren + '.length && !node.' + numOfChildren + ' && ' + selectedShowCondition + '"><span class="elbow fonticon icon-chevron-left"></span></span>' + '<span class="collapsed" ng-show="' + showExpandCollapseCondition + ' && !node.expanded && ' + selectedShowCondition + '" ng-click="' + treeId + '.selectNode(node); $event.stopPropagation()"><span class="collapsed fonticon icon-dropdown-arrow"></span></span>' + '<span class= "expanded" ng-show="' + showExpandCollapseCondition + ' && node.expanded  && ' + selectedShowCondition + '" ng-click="' + treeId + '.selectNode(node); $event.stopPropagation()"><span class="expanded fonticon icon-dropdown-arrow"></span></span>' + '<span ng-if="(checkbox) || (!checkbox && node.needCheckbox)">' + '<span ng-if="node.needCheckbox !== false">' + '<span class="triCheckbox" ng-show="' + selectedShowCondition + '" ng-class="{\'mid\' : node.isMid, \'checked\' : node.isChecked}" ng-click="(' + scope.useLeafsOnly + ' && node.' + numOfChildren + ') ||' + treeId + '.selectCheckbox(node); $event.stopPropagation()">' + '<span class="fonticon" ng-show="' + !scope.useLeafsOnly + ' || !node.' + numOfChildren + '" ng-class="{\'icon-checkbox\' : !node.isChecked && !node.isMid, \'icon-checkbox-tick\' : node.isChecked && !node.isMid, \'icon-select-yes\' : node.isChecked && node.isMid, \'unselectable\' : node.unselectable}"></span>' + '<span class="fonticon" ng-show="' + scope.useLeafsOnly + ' && node.' + numOfChildren + '" ng-class="{\'icon-folder\' : !node.expanded, \'icon-folder-open\' : node.expanded}" ng-click="' + treeId + '.selectNode(node); $event.stopPropagation()"></span></span>' + '</span>' + '</span>' + '<span ng-if="(checkbox && (node.needCheckbox === false))" class="need-checkbox-off-padding"></span>' + '<span ng-if="!node.' + nodeHtmlContent + '" class="node-label" ng-show="' + selectedShowCondition + ' && !editMode" ng-click="' + treeId + '.selectNode(node); $event.stopPropagation()"><span class="nodeLabel" ng-class="{primarySearchResult: node.primarySearchResult, secondarySearchResult: node.secondarySearchResult, \'unselectable\' : node.unselectable}"><span ng-if="hasIcons()" class="fonticon {{node.' + nodeIcon + '}}" ng-class="{\'unselectable\' : node.unselectable}"></span>{{node.' + nodeLabel + '}}</span></span>' + '<span ng-if="node.' + nodeHtmlContent + '" class="node-label" ng-init="createLabelTemplate(node)" ng-show="' + selectedShowCondition + ' && !editMode" ng-click="' + treeId + '.selectNode(node); $event.stopPropagation()"><span class="nodeLabel" ng-class="{primarySearchResult: node.primarySearchResult, secondarySearchResult: node.secondarySearchResult, \'unselectable\' : node.unselectable}"><span ng-if="hasIcons()" class="fonticon {{node.' + nodeIcon + '}}" ng-class="{\'unselectable\' : node.unselectable}"></span><span ng-include="node.templateUrl" ng-class="{\'unselectable\' : node.unselectable}"></span></span></span>' + '<span ng-if="editMode" class="edit-wrapper" ng-init="node.isEditing=((node.isNew) ? true:false)"><input class="form-control" type="text" ng-model="node.' + nodeLabel + '" tree-enter="setEditMode(node.isEditing)" ng-if="node.isEditing" ng-blur="setEditMode(node.isEditing)" tree-autofocus="true"/><span class="edit-label" ng-click="setEditMode(node.isEditing); $event.stopPropagation()" ng-if="!node.isEditing" ng-class="{primarySearchResult: node.primarySearchResult, secondarySearchResult: node.secondarySearchResult, \'unselectable\' : node.unselectable}"><span ng-if="hasIcons()" class="fonticon {{node.' + nodeIcon + '}}" ng-class="{\'unselectable\' : node.unselectable}"></span>{{node.' + nodeLabel + '}}</span></span>' + '<span class="inline-controls" ng-show="' + treeConfig['use-inline-controls'] + '">' + '<a class="pull-right inline-control-icon" ng-show="' + treeConfig['enable-delete-item-control'] + '"><span class="fonticon ' + treeConfig['delete-item-icon'] + '" ng-click="deleteNode(); $event.stopPropagation()"></span></a>' + '<a class="pull-right inline-control-icon" ng-show="{{' + (treeConfig['enable-add-group-control'] && levelDepth < treeConfig['max-group-depth']) + ' && node.isGroup }}"><span class="fonticon ' + treeConfig['add-group-icon'] + '" ng-click="addGroupToNode(); $event.stopPropagation()"></span></a>' + '<a class="pull-right inline-control-icon" ng-show="{{' + (treeConfig['enable-add-item-control'] && levelDepth < treeConfig['max-group-depth']) + ' && node.isGroup }}"><span class="fonticon ' + treeConfig['add-item-icon'] + '" ng-click="addItemToNode(); $event.stopPropagation()"></span></a>' + '</span>' + '</div>' + '<span ng-show="node.expanded && ' + selectedShowCondition + '" tree-id="' + treeId + '" tree-model="node.' + nodeChildren + '" node-id="' + nodeId + '" node-label="' + nodeLabel + '" node-children="' + nodeChildren + '" tree-name="' + treeName + '" level-depth="' + levelDepth + '" selector-index = "' + selectorIndex + '"></span>' + '</li>' + '</ul>';

        scope.createLabelTemplate = function (node) {
          var newUrl = 'label-template' + $rootScope.templateIndex++;
          $templateCache.put(newUrl, node.htmlContent);
          node.templateUrl = newUrl;
        };

        scope.addItemToNode = function () {
          scope.node.expanded = true;
          scope.node[nodeChildren].push({
            label: '',
            parentId: scope.node.id || 0,
            isShow: true,
            isEditing: true,
            isNew: true
          });
        };

        scope.addGroupToNode = function () {
          scope.node.expanded = true;
          scope.node[nodeChildren].push({
            label: '',
            parentId: scope.node.id || 0,
            isShow: true,
            isGroup: true,
            isEditing: true,
            isNew: true,
            items: []
          });
        };

        scope.deleteNode = function () {
          if (treeConfig['delete-item-callback']) {
            treeConfig['delete-item-callback'](scope.node);
          }
        };

        scope.setEditMode = function (oldValue) {
          if (scope.node[nodeChildren] && treeConfig['allow-folder-edition'] || !scope.node[nodeChildren]) {
            scope.node.isEditing = !oldValue;
            if (oldValue) {
              if (scope.node.isNew) {
                // Give users capability to provide callbacks for when new group/item is created and has been edited.
                scope.node.isNew = false;
                if (!scope.node.isGroup && typeof treeConfig['add-item-callback'] === 'function') {
                  treeConfig['add-item-callback'](scope.node);
                } else if (scope.node.isGroup && typeof treeConfig['add-group-callback'] === 'function') {
                  treeConfig['add-group-callback'](scope.node);
                }
              } else if (typeof scope.setEdited === 'function') {
                // Give users capability to provide a callback once a node value has changed providing previous and updated node values.
                scope.setEdited(previousNodeEditingValue, scope.node);
              }
              previousNodeEditingValue = {};
            } else {
              if (typeof scope.startEditing === 'function') {
                scope.startEditing(scope.node);
              }
              previousNodeEditingValue = angular.copy(scope.node);
            }
          }
        };

        scope.hasIcons = function () {
          var toReturn = scope.node[nodeIcon] ? true : false;
          return toReturn;
        };

        scope.setSelectedNode = function () {
          if (!scope.node.unselectable) {
            // ARK Change: [ARK-1125] Add feature to unselect nodes
            if (scope.treeInfo.currentSelectedNode) {
              scope.treeInfo.currentSelectedNode.isSelected = false;
              if (scope.treeInfo.currentSelectedNode !== scope.node) {
                scope.node.isSelected = true;
                scope.treeInfo.currentSelectedNode = scope.node;
              } else {
                scope.treeInfo.currentSelectedNode = undefined;
              }
            } else {
              scope.node.isSelected = true;
              scope.treeInfo.currentSelectedNode = scope.node;
            }

            if (angular.isDefined(scope.setSelection)) {
              scope.setSelection(scope.node);
            }
          }
        };

        // initialize node as selected or unselected
        scope.initSelectedNode = function (node) {
          if (angular.isDefined(node.id) && node.id === scope.preselectedNodeId) {
            node.isSelected = true;
            scope.treeInfo.currentSelectedNode = node;
            var parentId = node.parentId;
            // expands all parents of selected node
            while (parentId !== 0) {
              parentId = expandParent(scope.model, parentId);
            }
          } else {
            node.isSelected = false;
          }
        };
        // expands parent of selected node
        var expandParent = function expandParent(object, nodeId) {
          // checks all surface level nodes for id
          for (var i = 0; i < object.length; i++) {
            if (object[i].id === nodeId) {
              object[i].expanded = true;
              return object[i].parentId;
            }
          }
          // checks items of surface level nodes for id
          for (var i = 0; i < object.length; i++) {
            if (object[i].items) {
              var returnedId = expandParent(object[i].items, nodeId);
              if (returnedId) {
                return returnedId;
              }
            }
          }
          // returns 0 if id is not found in branch
          return 0;
        };

        var expandCollapseNode = function expandCollapseNode(selectedNode) {
          if (selectedNode[nodeChildren] && selectedNode.expanded) {
            for (var i = 0; i < selectedNode[nodeChildren].length; i++) {
              selectedNode[nodeChildren][i].isShow = true;
              selectedNode[nodeChildren][i].expanded = false;
            }
          }
        };

        var addSelectedNodesToModel = function addSelectedNodesToModel(nodesList) {
          if (!angular.isArray(nodesList)) {
            return;
          }

          angular.forEach(nodesList, function (node) {
            if (!scope.useLeafsOnly) {
              if (node.isChecked && !node.isMid) {
                if (scope.useLeafIds) {
                  angular.forEach(node[nodeLeafIds], function (id) {
                    scope.model.values.push(id);
                  });
                } else {
                  scope.model.values.push(node[nodeId]);
                }
                scope.model.names.push(node[nodeLabel]);
              } else if (node.isMid) {
                addSelectedNodesToModel(node[nodeChildren]);
              }

              // useLeafsOnly: do not add ids of nodes that have children (leaf nodes only)
            } else if (node.isChecked) {
              if (!node.numberOfItems) {
                scope.model.values.push(node[nodeId]);

                if (node.externalId) {
                  scope.model.names.push(node.externalId);
                } else {
                  scope.model.names.push(node[nodeLabel]);
                }
              } else {
                addSelectedNodesToModel(node[nodeChildren]);
              }
            }
          });
        };

        // check tree id, tree model
        if (treeId && treeModel) {

          // root node
          if (attrs.filterTreeview) {

            // create tree object if not exists
            scope[treeId] = scope[treeId] || {};

            // if node head clicks,
            scope[treeId].selectNode = scope[treeId].selectNode || function (selectedNode) {
              if (!selectedNode.unselectable) {

                if (scope.treeInfo.currentSelectedNode) {
                  scope.treeInfo.currentSelectedNode.isSelected = false;
                }
                selectedNode.isSelected = true;
                scope.treeInfo.currentSelectedNode = selectedNode;

                // remove in ark code
                if (angular.isDefined(scope.setSelection)) {
                  scope.setSelection(selectedNode);
                }

                // Collapse or Expand
                selectedNode.expanded = !selectedNode.expanded;

                var hasChildrenToLoad = selectedNode[numOfChildren] > 0 && (!selectedNode[nodeChildren] || !selectedNode[nodeChildren].length);

                var useLazyLoading = scope.lazyLoading;

                if (useLazyLoading && selectedNode.expanded && hasChildrenToLoad) {
                  // lazy load node children
                  if (scope.restService) {
                    scope.restService.getNodeChildren(treeName, selectedNode[nodeId], function (nodeChildrenItems) {
                      angular.forEach(nodeChildrenItems, function (node) {
                        node.isChecked = node.isChecked || false;
                        node.isMid = node.isMid || false;
                        node.isShow = (typeof node.isShow === "undefined" || node.isShow === '') ? true : node.isShow;
                        node.expanded = node.expanded || false;
                        node.parentId = selectedNode[nodeId];

                        if (selectedNode.isChecked) {
                          node.isChecked = true;
                        }
                      });
                      selectedNode[nodeChildren] = nodeChildrenItems;
                      expandCollapseNode(selectedNode);
                    });
                  } else {
                    $log.error('No service is provided for lazy loading');
                  }
                }
              }
            };

            // update data in service (excuted any time a checkbox state is toggled)
            scope[treeId].updateSelected = scope[treeId].updateSelected || function () {
              if (scope.model.values && scope.model.names) {
                // clear the data model:
                scope.model.values.splice(0, scope.model.values.length);
                scope.model.names.splice(0, scope.model.names.length);

                // add all the selected items back to the data model:
                addSelectedNodesToModel(scope[treeModel]);
              }
            };

            // checkbox helper functions
            scope[treeId].checkBox = scope[treeId].checkBox || function (selectedNode) {
              selectedNode.isChecked = true;
              selectedNode.isMid = false;
              scope[treeId].updateSelected();
              scope.tempCheckedOptions.push({
                node: selectedNode,
                checkType: 'checked'
              });
            };

            scope[treeId].uncheckBox = scope[treeId].uncheckBox || function (selectedNode) {
              selectedNode.isChecked = false;
              selectedNode.isMid = false;
              scope[treeId].updateSelected();
              scope.tempCheckedOptions.push({
                node: selectedNode,
                checkType: 'unchecked'
              });
            };

            scope[treeId].midcheckBox = scope[treeId].midcheckBox || function (selectedNode) {
              selectedNode.isChecked = true;
              selectedNode.isMid = true;
              scope[treeId].updateSelected();
              scope.tempCheckedOptions.push({
                node: selectedNode,
                checkType: 'midchecked'
              });
            };

            // recursive functions
            scope[treeId].checkAllChildren = function (node) {
              if (node[nodeChildren]) {
                for (var i = 0; i < node[nodeChildren].length; i++) {
                  scope[treeId].checkBox(node[nodeChildren][i]);
                  scope[treeId].checkAllChildren(node[nodeChildren][i]);
                }
              }
            };

            scope[treeId].uncheckAllChildren = function (node) {
              if (node[nodeChildren]) {
                for (var i = 0; i < node[nodeChildren].length; i++) {
                  scope[treeId].uncheckBox(node[nodeChildren][i]);
                  scope[treeId].uncheckAllChildren(node[nodeChildren][i]);
                }
              }
            };

            scope[treeId].selectCheckbox = scope[treeId].selectCheckbox || function (selectedNode) {
              if (!selectedNode.unselectable) {

                if (scope.treeInfo.currentSelectedNode) {
                  scope.treeInfo.currentSelectedNode.isSelected = false;
                }
                selectedNode.isSelected = true;
                scope.treeInfo.currentSelectedNode = selectedNode;

                // if box is unchecked or midchecked
                if (!selectedNode.isChecked || selectedNode.isMid) {

                  scope[treeId].checkBox(selectedNode);

                  // recursively check all children
                  scope[treeId].checkAllChildren(selectedNode);

                  // recursive function that updates parent checkboxes when a child is checked
                  scope[treeId].checkParent = function (node, nodeChild) {
                    var isChild = false;

                    // go through every child and verify if nodeChild is one of them
                    if (node[nodeChildren]) {
                      for (var i = 0; i < node[nodeChildren].length; i++) {
                        if (node[nodeChildren][i] === nodeChild) {
                          isChild = true;
                          break;
                        }
                      }
                    }

                    // we're studying the children of the parent of the node
                    // we know that the nodeChild is checked, but his siblings might not be
                    // go through every child and verify if they are all checked
                    if (isChild) {
                      var allChecked = true;
                      if (node[nodeChildren]) {
                        for (var i = 0; i < node[nodeChildren].length; i++) {
                          if (!node[nodeChildren][i].isChecked || node[nodeChildren][i].isMid) {
                            allChecked = false;
                            break;
                          }
                        }
                      }

                      if (allChecked) {
                        scope[treeId].checkBox(node);

                        // if the checked node isn't at the root, repeat
                        var isRoot = false;
                        for (var i = 0; i < scope[treeModel].length; i++) {
                          if (node === scope[treeModel][i]) {
                            isRoot = true;
                            break;
                          }
                        }

                        if (!isRoot) {
                          for (var k = 0; k < scope[treeModel].length; k++) {
                            scope[treeId].checkParent(scope[treeModel][k], node);
                          }
                        }
                      } else {
                        scope[treeId].midcheckBox(node);

                        // if the checked node isn't at the root, repeat
                        isRoot = false;
                        for (var i = 0; i < scope[treeModel].length; i++) {
                          if (node === scope[treeModel][i]) {
                            isRoot = true;
                            break;
                          }
                        }

                        if (!isRoot) {
                          for (var k = 0; k < scope[treeModel].length; k++) {
                            scope[treeId].checkParent(scope[treeModel][k], node);
                          }
                        }
                      }

                      // if child isn't found then proceed a level deeper
                    } else if (node[nodeChildren]) {
                      for (var i = 0; i < node[nodeChildren].length; i++) {
                        scope[treeId].checkParent(node[nodeChildren][i], nodeChild);
                      }
                    }
                  };

                  // goes through each child of the root
                  for (var j = 0; j < scope[treeModel].length; j++) {
                    scope[treeId].checkParent(scope[treeModel][j], selectedNode);
                  }

                  // if box is checked
                } else if (!selectedNode.isMid) {

                  scope[treeId].uncheckBox(selectedNode);

                  // recursively uncheck all children
                  scope[treeId].uncheckAllChildren(selectedNode);

                  // recursive function that updates parent checkboxes when a child is checked
                  scope[treeId].uncheckParent = function (node, nodeChild) {
                    var isChild = false;

                    // go through every child and check if nodeChild is one of them
                    if (node[nodeChildren]) {
                      for (var i = 0; i < node[nodeChildren].length; i++) {
                        if (node[nodeChildren][i] === nodeChild) {
                          isChild = true;
                          break;
                        }
                      }
                    }

                    // go through every child and check if they are all unchecked
                    if (isChild) {
                      var allUnchecked = true;
                      if (node[nodeChildren]) {
                        for (var i = 0; i < node[nodeChildren].length; i++) {
                          if (node[nodeChildren][i].isChecked) {
                            allUnchecked = false;
                            break;
                          }
                        }
                      }

                      if (allUnchecked) {
                        scope[treeId].uncheckBox(node);

                        // if the unchecked node isn't at the root, repeat
                        var isRoot = false;
                        for (var i = 0; i < scope[treeModel].length; i++) {
                          if (node === scope[treeModel][i]) {
                            isRoot = true;
                            break;
                          }
                        }

                        if (!isRoot) {
                          for (var k = 0; k < scope[treeModel].length; k++) {
                            scope[treeId].uncheckParent(scope[treeModel][k], node);
                          }
                        }
                      } else {
                        scope[treeId].midcheckBox(node);

                        // if the unchecked node isn't at the root, repeat
                        isRoot = false;
                        for (var i = 0; i < scope[treeModel].length; i++) {
                          if (node === scope[treeModel][i]) {
                            isRoot = true;
                            break;
                          }
                        }

                        if (!isRoot) {
                          for (var k = 0; k < scope[treeModel].length; k++) {
                            scope[treeId].uncheckParent(scope[treeModel][k], node);
                          }
                        }
                      }
                      // if child isn't found then proceed a level deeper
                    } else if (node[nodeChildren]) {
                      for (var i = 0; i < node[nodeChildren].length; i++) {
                        scope[treeId].uncheckParent(node[nodeChildren][i], nodeChild);
                      }
                    }
                  };

                  // goes through each child of the root
                  for (var j = 0; j < scope[treeModel].length; j++) {
                    scope[treeId].uncheckParent(scope[treeModel][j], selectedNode);
                  }
                }

                if (angular.isDefined(scope.setCheckbox)) {
                  scope.setCheckbox(scope.tempCheckedOptions);
                }

                scope.tempCheckedOptions = [];
              }
            };
          }

          // Rendering template.
          element.html('').append($compile(template)(scope));

          // scope.nodeLabels = angular.element(element).find('.nodeLabel');
        }
      }
    };
  }]);

  // jshint funcscope:false
  // jshint shadow:false
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').controller('DropdownTreeCtrl', ['$scope', 'ArkNestedTreeService', function ($scope, ArkNestedTreeService) {
    var controller = this;

    controller.populateFilter = function populateFilter(input) {
      var result;

      if (input && input.items) {
        result = input.items;
      } else if (input && !input.items) {
        result = input;
      }

      for (var j = 0; j < result.length; j++) {
        ArkNestedTreeService.augmentNode(result[j], result);
      }

      return result;
    };

    $scope.filterData = [];

    $scope.$watch('model', function () {
      if ($scope.model) {
        $scope.filterData = controller.populateFilter($scope.model);
      }
    });
  }]);
})(angular);

(function () {
  'use strict';

  angular.module('ark.core').directive('arkSelect', ['$window', '$parse', '$q', '$select', '$parseOptions', 'arkEscapeHtmlFilter', function ($window, $parse, $q, $select, $parseOptions, arkEscapeHtmlFilter) {
    var defaults = $select.defaults;

    return {
      restrict: 'EAC',
      require: 'ngModel',
      link: function postLink(scope, element, attr, controller) {

        // Directive options
        var options = {
          scope: scope
        };
        angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'placeholder', 'multiple', 'maxLength', 'maxLengthHtml', 'allText', 'caretIcon', 'enableSelectAll', 'resize', 'dropup'], function (key) {
          if (angular.isDefined(attr[key])) {
            options[key] = attr[key];
          }
        });

        // use string regex match boolean attr falsy values, leave truthy values be
        var falseValueRegExp = /^(false|0|)$/i;
        angular.forEach(['html', 'container', 'enableSelectAll', 'sort'], function (key) {
          if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) {
            options[key] = false;
          }
        });

        // Watchable attributes
        angular.forEach(['maxSelected'], function (key) {
          if (angular.isDefined(attr[key])) {
            options[key] = attr[key];
            scope.$watch(function () {
              return attr[key];
            }, function (newValue, oldValue) {
              if (angular.isDefined(newValue)) {
                options[key] = newValue || null;
                select.$scope.$options[key] = options[key];
                if (oldValue > newValue && select.$countSelected() > newValue) {
                  select.$clearActive();
                  select.$updateActiveIndex();
                  controller.$render();
                }
              }
            });
          }
        });

        // Add support for select markup
        if (element[0].nodeName.toLowerCase() === 'select') {
          var inputEl = element;
          inputEl.css('display', 'none');
          // element = angular.element('<button type="button" class="btn btn-default"></button>');
          element = angular.element('<div class="btn-group bootstrap-select"><button type="button" class="btn btn-default dropdown-toggle selectpicker"></button></div>');
          inputEl.after(element);
        }

        scope.$watch('element.context.id', function () {
          if (element.context && element.context.id) {
            select.$updateParentId(element.context.id);
          }
        });

        if (options.enableSelectAll && options.maxSelected) {
          console.warn('Ark Select: enableSelectAll option is ignored when maxSelected is specified.');
          options.enableSelectAll = false;
        }

        // Build proper arkOptions
        /**
         * https://genesysjira.atlassian.net/browse/ARK-1514 - Ark Select: Controller 'select', required by directive 'ngOptions', can't be found
         * Using arkOptions and ngOptions allow smoothly migrate to new attribute name with backward compatibility
         * ngOptions should be market as deprecated
         */
        var parsedOptions = $parseOptions(attr.arkOptions || attr.ngOptions);

        // Initialize select
        var select = $select(element, controller, options);

        // Watch ngOptions values before filtering for changes
        var watchedOptions = parsedOptions.$match[7].trim();
        scope.$watch(watchedOptions, function () {
          // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue);
          parsedOptions.valuesFn(scope, controller).then(function (values) {
            select.update(values);
            controller.$render();
          });
        }, true);

        // Watch model for changes
        scope.$watch(attr.ngModel, function () {
          // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue);
          select.$updateActiveIndex();
          controller.$render();
        }, true);

        // Model rendering in view
        controller.$render = function () {
          // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);
          var selected, index;
          if (options.multiple && angular.isArray(controller.$modelValue)) {
            selected = controller.$modelValue.map(function (value) {
              index = select.$getIndex(value);
              return angular.isDefined(index) ? arkEscapeHtmlFilter(select.$scope.$matches[index].label) : options.placeholder;
            }).filter(angular.isDefined);
            if (selected.length > (options.maxLength || defaults.maxLength)) {
              selected = selected.length + ' ' + (attr.maxLengthHtml || defaults.maxLengthHtml);
            } else {
              selected = selected.join(', ');
            }
          } else {
            index = select.$getIndex(controller.$modelValue);
            selected = angular.isDefined(index) ? arkEscapeHtmlFilter(select.$scope.$matches[index].label) : false;
          }
          if (attr.multiple) {
            element.html('<span class="filter-option">' + (selected ? selected : attr.placeholder || defaults.placeholder) + '</span>' + '<span class="fonticon ' + (angular.isDefined(options.caretIcon) ? options.caretIcon : 'icon-pencil') + '"></span>');
          } else {
            element.html('<span class="filter-option">' + (selected ? selected : attr.placeholder || defaults.placeholder) + '</span>' + '&nbsp;<span class="fonticon ' + (angular.isDefined(options.caretIcon) ? options.caretIcon : defaults.caretIcon) + '"></span>');
          }
        };

        // Garbage collection
        scope.$on('$destroy', function () {
          // In Angular 1.2 there is a bug that can cause $destroy to be called twice
          // so we check if the select was already destroyed
          if (select) {
            select.destroy();
            options = null;
            select = null;
          }
        });
      }
    };
  }]);
})();

(function () {
  // jscs:disable
  'use strict';

  angular.module('ark.core').factory('dimensions', function () {

    // var jqLite = angular.element;
    var fn = {};

    /**
     * Test the element nodeName
     * @param element
     * @param name
     */
    var nodeName = fn.nodeName = function (element, name) {
      return element.nodeName && element.nodeName.toLowerCase() === name.toLowerCase();
    };

    /**
     * Returns the element computed style
     * @param element
     * @param prop
     * @param extra
     */
    fn.css = function (element, prop, extra) {
      var value;
      if (element.currentStyle) {
        // IE
        value = element.currentStyle[prop];
      } else if (window.getComputedStyle) {
        value = window.getComputedStyle(element)[prop];
      } else {
        value = element.style[prop];
      }
      return extra === true ? parseFloat(value) || 0 : value;
    };

    /**
     * Provides read-only equivalent of jQuery's offset function:
     * @required-by bootstrap-tooltip, bootstrap-affix
     * @url http://api.jquery.com/offset/
     * @param element
     */
    fn.offset = function (element) {
      var boxRect = element.getBoundingClientRect();
      var docElement = element.ownerDocument;
      return {
        width: boxRect.width || element.offsetWidth,
        height: boxRect.height || element.offsetHeight,
        top: boxRect.top + (window.pageYOffset || docElement.documentElement.scrollTop) - (docElement.documentElement.clientTop || 0),
        left: boxRect.left + (window.pageXOffset || docElement.documentElement.scrollLeft) - (docElement.documentElement.clientLeft || 0)
      };
    };

    /**
     * Provides read-only equivalent of jQuery's position function
     * @required-by bootstrap-tooltip, bootstrap-affix
     * @url http://api.jquery.com/offset/
     * @param element
     */
    fn.position = function (element) {

      var offsetParentRect = {
        top: 0,
        left: 0
      },
          offsetParentElement,
          offset;

      // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent
      if (fn.css(element, 'position') === 'fixed') {

        // We assume that getBoundingClientRect is available when computed position is fixed
        offset = element.getBoundingClientRect();
      } else {

        // Get *real* offsetParentElement
        offsetParentElement = offsetParent(element);
        offset = fn.offset(element);

        // Get correct offsets
        offset = fn.offset(element);
        if (!nodeName(offsetParentElement, 'html')) {
          offsetParentRect = fn.offset(offsetParentElement);
        }

        // Add offsetParent borders
        offsetParentRect.top += fn.css(offsetParentElement, 'borderTopWidth', true);
        offsetParentRect.left += fn.css(offsetParentElement, 'borderLeftWidth', true);
      }

      // Subtract parent offsets and element margins
      return {
        width: element.offsetWidth,
        height: element.offsetHeight,
        top: offset.top - offsetParentRect.top - fn.css(element, 'marginTop', true),
        left: offset.left - offsetParentRect.left - fn.css(element, 'marginLeft', true)
      };
    };

    /**
     * Returns the closest, non-statically positioned offsetParent of a given element
     * @required-by fn.position
     * @param element
     */
    var offsetParent = function offsetParentElement(element) {
      var docElement = element.ownerDocument;
      var offsetParent = element.offsetParent || docElement;
      if (nodeName(offsetParent, '#document')) {
        return docElement.documentElement;
      }
      while (offsetParent && !nodeName(offsetParent, 'html') && fn.css(offsetParent, 'position') === 'static') {
        offsetParent = offsetParent.offsetParent;
      }
      return offsetParent || docElement.documentElement;
    };

    /**
     * Provides equivalent of jQuery's height function
     * @required-by bootstrap-affix
     * @url http://api.jquery.com/height/
     * @param element
     * @param outer
     */
    fn.height = function (element, outer) {
      var value = element.offsetHeight;
      if (outer) {
        value += fn.css(element, 'marginTop', true) + fn.css(element, 'marginBottom', true);
      } else {
        value -= fn.css(element, 'paddingTop', true) + fn.css(element, 'paddingBottom', true) + fn.css(element, 'borderTopWidth', true) + fn.css(element, 'borderBottomWidth', true);
      }
      return value;
    };

    /**
     * Provides equivalent of jQuery's width function
     * @required-by bootstrap-affix
     * @url http://api.jquery.com/width/
     * @param element
     * @param outer
     */
    fn.width = function (element, outer) {
      var value = element.offsetWidth;
      if (outer) {
        value += fn.css(element, 'marginLeft', true) + fn.css(element, 'marginRight', true);
      } else {
        value -= fn.css(element, 'paddingLeft', true) + fn.css(element, 'paddingRight', true) + fn.css(element, 'borderLeftWidth', true) + fn.css(element, 'borderRightWidth', true);
      }
      return value;
    };

    return fn;
  });
})();

(function () {
  'use strict';

  angular.version.minor < 3 && angular.version.dot < 14 && angular.module('ng').factory('$$rAF', ['$window', '$timeout', function ($window, $timeout) {
    var requestAnimationFrame = $window.requestAnimationFrame || $window.webkitRequestAnimationFrame || $window.mozRequestAnimationFrame;

    var cancelAnimationFrame = $window.cancelAnimationFrame || $window.webkitCancelAnimationFrame || $window.mozCancelAnimationFrame || $window.webkitCancelRequestAnimationFrame;

    var rafSupported = !!requestAnimationFrame;

    var raf = rafSupported ? function (fn) {
      var id = requestAnimationFrame(fn);
      return function () {
        cancelAnimationFrame(id);
      };
    } : function (fn) {
      var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
      return function () {
        $timeout.cancel(timer);
      };
    };

    raf.supported = rafSupported;

    return raf;
  }]); // jshint ignore:line
})();

(function () {
  'use strict';

  angular.module('ark.core').provider('$parseOptions', function () {
    var defaults = this.defaults = {
      regexp: /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/
    };
    this.$get = ['$parse', '$q', function ($parse, $q) {
      function ParseOptionsFactory(attr, config) {
        var $parseOptions = {};

        // Common vars
        var options = angular.extend({}, defaults, config);
        $parseOptions.$values = [];

        // Private vars
        var match;
        var displayFn;
        var valueName;
        var valueFn;
        var valuesFn;

        $parseOptions.init = function () {
          $parseOptions.$match = match = attr.match(options.regexp);
          displayFn = $parse(match[2] || match[1]);
          valueName = match[4] || match[6];
          valueFn = $parse(match[2] ? match[1] : valueName);
          valuesFn = $parse(match[7]);
        };

        $parseOptions.valuesFn = function (scope, controller) {
          return $q.when(valuesFn(scope, controller)).then(function (values) {
            $parseOptions.$values = values ? parseValues(values, scope) : {};
            return $parseOptions.$values;
          });
        };

        // Private functions
        function parseValues(values, scope) {
          return values.map(function (match, index) {
            var locals = {};
            var label;
            var value;
            locals[valueName] = match;
            label = displayFn(scope, locals);
            value = valueFn(scope, locals) || index;
            return {
              label: label,
              value: value
            };
          });
        }

        $parseOptions.init();
        return $parseOptions;
      }
      return ParseOptionsFactory;
    }];
  });
})();

(function () {
  'use strict';

  angular.module('ark.core').provider('$selectTooltip', function () {
    var defaults = this.defaults = {
      animation: 'am-fade',
      prefixClass: 'tooltip',
      prefixEvent: 'tooltip',
      container: false,
      target: false,
      placement: 'top',
      template: 'ark-select/tooltip.tpl.html',
      resize: false,
      dropup: false,
      contentTemplate: false,
      trigger: 'hover focus',
      keyboard: false,
      html: false,
      show: false,
      title: '',
      type: '',
      delay: 0,
      marginValue: 2
    };

    this.$get = ['$window', '$rootScope', '$compile', '$q', '$templateCache', '$http', '$animate', 'dimensions', '$$rAF', function ($window, $rootScope, $compile, $q, $templateCache, $http, $animate, dimensions, $$rAF) {
      var trim = String.prototype.trim;
      var isTouch = false; // 'createTouch' in $window.document;
      // ARK-1787: touch support is not required. Mousedown is always fired on touch and non-touch devices
      var htmlReplaceRegExp = /ng-bind="/ig;

      function TooltipFactory(element, config) {

        var $selectTooltip = {};

        // Common vars
        var windowElement = angular.element($window);
        var nodeName = element[0].nodeName.toLowerCase();
        var options = $selectTooltip.$options = angular.extend({}, defaults, config);
        $selectTooltip.$promise = fetchTemplate(options.template);
        var scope = $selectTooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new();
        if (options.delay && angular.isString(options.delay)) {
          options.delay = parseFloat(options.delay);
        }

        // Support scope as string options
        if (options.title) {
          $selectTooltip.$scope.title = options.title;
        }

        // Provide scope helpers
        scope.$hide = function () {
          scope.$$postDigest(function () {
            $selectTooltip.hide();
          });
        };
        scope.$show = function () {
          scope.$$postDigest(function () {
            $selectTooltip.show();
          });
        };
        scope.$toggle = function () {
          scope.$$postDigest(function () {
            $selectTooltip.toggle();
          });
        };
        $selectTooltip.$isShown = scope.$isShown = false;

        // Private vars
        var timeout, hoverState;

        // Support contentTemplate option
        if (options.contentTemplate) {
          $selectTooltip.$promise = $selectTooltip.$promise.then(function (template) {
            var templateEl = angular.element(template);
            return fetchTemplate(options.contentTemplate).then(function (contentTemplate) {
              var contentEl = findElement('[ng-bind="content"]', templateEl[0]);
              if (!contentEl.length) {
                contentEl = findElement('[ng-bind="title"]', templateEl[0]);
              }
              contentEl.removeAttr('ng-bind').html(contentTemplate);
              return templateEl[0].outerHTML;
            });
          });
        }

        // Fetch, compile then initialize tooltip
        var tipLinker, tipElement, tipContainer, parentElement; // , tipTemplate;
        $selectTooltip.$promise.then(function (template) {
          if (angular.isObject(template)) {
            template = template.data;
          }
          if (options.html) {
            template = template.replace(htmlReplaceRegExp, 'ng-bind-html="');
          }
          template = trim.apply(template);
          // tipTemplate = template;
          tipLinker = $compile(template);
          $selectTooltip.init();
        });

        $selectTooltip.init = function () {

          // Options: delay
          if (options.delay && angular.isNumber(options.delay)) {
            options.delay = {
              show: options.delay,
              hide: options.delay
            };
          }

          // Replace trigger on touch devices ?
          // if(isTouch && options.trigger === defaults.trigger) {
          //   options.trigger.replace(/hover/g, 'click');
          // }

          // Options : container
          if (options.container === 'self') {
            tipContainer = element;
          } else if (options.container) {
            tipContainer = findElement(options.container);
          }

          // Options: trigger
          var triggers = options.trigger.split(' ');
          angular.forEach(triggers, function (trigger) {
            if (trigger === 'click') {
              element.on('click', $selectTooltip.toggle);
            } else if (trigger !== 'manual') {
              element.on(trigger === 'hover' ? 'mouseenter' : 'focus', $selectTooltip.enter);
              element.on(trigger === 'hover' ? 'mouseleave' : 'blur', $selectTooltip.leave);
              nodeName === 'button' && trigger !== 'hover' && element.on(isTouch ? 'touchstart' : 'mousedown', $selectTooltip.$onFocusElementMouseDown); // jshint ignore:line
            }
          });

          // Options: target
          if (options.target) {
            options.target = angular.isElement(options.target) ? options.target : findElement(options.target)[0];
          }

          // Options: show
          if (options.show) {
            scope.$$postDigest(function () {
              options.trigger === 'focus' ? element[0].focus() : $selectTooltip.show(); // jshint ignore:line
            });
          }

          // Search for container that restricts the menu position
          if (options.dropup || options.resize) {
            parentElement = getElementContainer(element[0], 'dropdown-container');
          }
        };

        $selectTooltip.destroy = function () {

          // Unbind events
          var triggers = options.trigger.split(' ');
          for (var i = triggers.length; i--;) {
            var trigger = triggers[i];
            if (trigger === 'click') {
              element.off('click', $selectTooltip.toggle);
            } else if (trigger !== 'manual') {
              element.off(trigger === 'hover' ? 'mouseenter' : 'focus', $selectTooltip.enter);
              element.off(trigger === 'hover' ? 'mouseleave' : 'blur', $selectTooltip.leave);
              nodeName === 'button' && trigger !== 'hover' && element.off(isTouch ? 'touchstart' : 'mousedown', $selectTooltip.$onFocusElementMouseDown); // jshint ignore:line
            }
          }
          windowElement.unbind('resize', $selectTooltip.setAppendedPosition);

          // Remove element
          if (tipElement) {
            tipElement.remove();
            tipElement = null;
          }

          // Cancel pending callbacks
          clearTimeout(timeout);

          // Destroy scope
          scope.$destroy();
        };

        $selectTooltip.enter = function () {

          if (!scope.dropdownMousedown) {
            clearTimeout(timeout);
            hoverState = 'in';
            if (!options.delay || !options.delay.show) {
              return $selectTooltip.show();
            }

            timeout = setTimeout(function () {
              if (hoverState === 'in') {
                $selectTooltip.show();
              }
            }, options.delay.show);
          }
        };

        $selectTooltip.setAppendedPosition = function (tipPosition) {
          var viewportTop = windowElement[0].scrollY || windowElement[0].pageYOffset; // IE 11 fallback

          // Calculating the available space from below to display menu
          var distanceToContainerBottom = parentElement.offsetHeight - (dimensions.offset(element[0]).top - dimensions.offset(parentElement).top + element[0].offsetHeight);
          var distanceToScreenBottom = windowElement[0].document.documentElement.clientHeight - (dimensions.offset(element[0]).top - viewportTop + element[0].offsetHeight);
          var distanceToBottom = Math.min(distanceToContainerBottom, distanceToScreenBottom);
          var distanceToTop, isDropUp;

          if (options.dropup) {
            // Do I need to place menu at the top?
            isDropUp = getTipHeight() + options.marginValue > distanceToBottom;

            if (isDropUp) {
              // Calculating the available space from above to display menu
              var distanceToContainerTop = dimensions.offset(element[0]).top - dimensions.offset(parentElement).top;
              var distanceToScreenTop = dimensions.offset(element[0]).top - viewportTop;
              distanceToTop = Math.min(distanceToContainerTop, distanceToScreenTop);

              if (distanceToTop > distanceToBottom) {
                if (getTipHeight() + options.marginValue > distanceToTop) {
                  // There is not enough space at the top to display the full menu
                  tipPosition.height = distanceToTop - options.marginValue + 'px';
                  tipPosition.top = parseInt(tipPosition.top) - element[0].offsetHeight - parseInt(tipPosition.height) - options.marginValue + 'px';
                  tipPosition.overflowY = 'scroll';
                } else {
                  // Display the full menu at the top
                  tipPosition.top = parseInt(tipPosition.top) - element[0].offsetHeight - getTipHeight() - options.marginValue + 'px';
                }
              } else {
                // Full menu can not be displayed, but below is more available space
                isDropUp = false;
              }
            }
            tipElement.toggleClass('dropup', isDropUp);
          }

          if (options.resize && !options.dropup || distanceToBottom >= distanceToTop) {
            // Display the menu at the bottom, but there is not enough space
            if (getTipHeight() + options.marginValue > distanceToBottom) {
              tipPosition.top = parseInt(tipPosition.top) + options.marginValue + 'px';
              tipPosition.height = distanceToBottom - options.marginValue - 2 + 'px';
              tipPosition.overflowY = 'scroll';
            }
          }

          var rightalign = tipElement.hasClass('dropdown-menu-right');
          if (rightalign) {
            tipPosition.left = 'auto';
            tipPosition.right = window.innerWidth - (parseInt(tipPosition).left + element.prop('offsetWidth')) + 'px';
          } else {
            tipPosition.right = 'auto';
          }

          return tipPosition;
        };

        $selectTooltip.setStandartPosition = function (tipPosition) {
          var viewportTop, distanceToTop, distanceToBottom, isDropUp;

          if (options.dropup) {
            viewportTop = windowElement[0].scrollY || windowElement[0].pageYOffset; // IE 11 fallback

            // Calculating the available space to display menu
            distanceToTop = dimensions.offset(element[0]).top - viewportTop;
            distanceToBottom = windowElement[0].document.documentElement.clientHeight - (dimensions.offset(element[0]).top - viewportTop + element[0].offsetHeight);
            // Do I need to place menu at the top?
            isDropUp = getTipHeight() + options.marginValue > distanceToBottom;

            if (isDropUp) {
              if (distanceToTop > distanceToBottom) {
                tipPosition.top = 'auto';
                tipPosition.bottom = '100%';
                tipPosition.marginBottom = '1px';

                // Checking the available top height for drop-up to resize.
                if (getTipHeight() + options.marginValue > distanceToTop) {
                  // There is not enough space at the top to display the full menu
                  tipPosition.height = distanceToTop - options.marginValue + 'px';
                  tipElement.css({ overflowY: 'scroll' });
                }
              }
            } else {
              // Full menu can not be displayed, but below is more available space
              isDropUp = false;
            }
            tipElement.toggleClass('dropup', isDropUp);
          }

          if (options.resize && !options.dropup || distanceToBottom >= distanceToTop) {
            // Display the menu at the bottom, but there is not enough space
            var buttonBottom = distanceToTop + element[0].offsetHeight;
            var tipBottom = buttonBottom + getTipHeight() + options.marginValue;

            if (tipBottom > windowElement[0].innerHeight) {
              tipPosition.top = parseInt(tipPosition.top) + options.marginValue + 'px';
              tipPosition.height = windowElement[0].innerHeight - buttonBottom - options.marginValue - 2 + 'px';
              tipElement.css({ overflowY: 'scroll' });
            }
          }

          var rightalign = tipElement.hasClass('dropdown-menu-right');
          if (rightalign) {
            tipPosition.left = 'auto';
            tipPosition.right = window.innerWidth - (parseInt(tipPosition.left) + element.prop('offsetWidth')) + 'px';
          } else {
            tipPosition.right = 'auto';
          }

          return tipPosition;
        };

        $selectTooltip.show = function () {
          scope.$emit(options.prefixEvent + '.show.before', $selectTooltip);
          var parent = options.container ? tipContainer : null;
          var after = options.container ? null : element;

          // Hide any existing tipElement
          if (tipElement) {
            tipElement.remove();
          }
          // Fetch a cloned element linked from template
          tipElement = $selectTooltip.$element = tipLinker(scope, function (clonedElement, scope) {}); // jshint ignore:line

          // Set the initial positioning.
          tipElement.css({
            top: '0px',
            left: '0px'
          }).addClass(options.placement);

          // Options: animation
          if (options.animation) {
            tipElement.addClass(options.animation);
          }
          // Options: type
          if (options.type) {
            tipElement.addClass(options.prefixClass + '-' + options.type);
          }

          $animate.enter(tipElement, parent, after, function () {
            scope.$emit(options.prefixEvent + '.show', $selectTooltip);
          });
          $selectTooltip.$isShown = scope.$isShown = true;
          scope.$$phase || scope.$root && scope.$root.$$phase || scope.$digest(); // jshint ignore:line
          $$rAF($selectTooltip.$applyPlacement); // var a = bodyEl.offsetWidth + 1; ?

          if (parentElement) {
            windowElement.bind('resize', $selectTooltip.setAppendedPosition);
          }

          // Bind events
          if (options.keyboard) {
            if (options.trigger !== 'focus') {
              $selectTooltip.focus();
              tipElement.on('keyup', $selectTooltip.$onKeyUp);
            } else {
              element.on('keyup', $selectTooltip.$onFocusKeyUp);
            }
          }
        };

        $selectTooltip.leave = function () {

          if (!scope.dropdownMousedown) {
            clearTimeout(timeout);
            hoverState = 'out';
            if (!options.delay || !options.delay.hide) {
              return $selectTooltip.hide();
            }
            timeout = setTimeout(function () {
              if (hoverState === 'out') {
                $selectTooltip.hide();
              }
            }, options.delay.hide);
          }
        };

        $selectTooltip.hide = function (blur) {

          if (!$selectTooltip.$isShown) {
            return;
          }
          scope.$emit(options.prefixEvent + '.hide.before', $selectTooltip);

          $animate.leave(tipElement, function () {
            scope.$emit(options.prefixEvent + '.hide', $selectTooltip);
          });

          $selectTooltip.$isShown = scope.$isShown = false;
          scope.$$phase || scope.$root && scope.$root.$$phase || scope.$digest(); // jshint ignore:line

          // Unbind events
          if (options.keyboard && tipElement !== null) {
            tipElement.off('keyup', $selectTooltip.$onKeyUp);
          }

          // Allow to blur the input when hidden, like when pressing enter key
          if (blur && options.trigger === 'focus') {
            return element[0].blur();
          }
        };

        $selectTooltip.toggle = function () {
          $selectTooltip.$isShown ? $selectTooltip.leave() : $selectTooltip.enter(); // jshint ignore:line
        };

        $selectTooltip.focus = function () {
          tipElement[0].focus();
        };

        // Protected methods

        $selectTooltip.$applyPlacement = function () {
          if (!tipElement) {
            return;
          }

          // Get the position of the tooltip element.
          var elementPosition = getPosition();
          // Get the height and width of the tooltip so we can center it.
          var tipWidth = tipElement.prop('offsetWidth');
          var tipHeight = tipElement.prop('offsetHeight');
          // Get the tooltip's top and left coordinates to center it with this directive.
          var tipPosition = getCalculatedOffset(options.placement, elementPosition, tipWidth, tipHeight);

          tipPosition.top += 'px';
          tipPosition.left += 'px';

          var css;
          // Now set the calculated positioning.
          if (parentElement) {
            css = $selectTooltip.setAppendedPosition(tipPosition);
            tipElement.css(css);
          } else {
            css = $selectTooltip.setStandartPosition(tipPosition);
            tipElement.css(css);
            tipElement.children().css(css);
          }
          tipElement.css({ display: 'block' });
        };

        $selectTooltip.$onKeyUp = function (evt) {
          evt.which === 27 && $selectTooltip.hide(); // jshint ignore:line
        };

        $selectTooltip.$onFocusKeyUp = function (evt) {
          evt.which === 27 && element[0].blur(); // jshint ignore:line
        };

        $selectTooltip.$onFocusElementMouseDown = function (evt) {
          evt.preventDefault();
          evt.stopPropagation();
          // Some browsers do not auto-focus buttons (eg. Safari)
          $selectTooltip.$isShown ? element[0].blur() : element[0].focus(); // jshint ignore:line
        };

        // Private methods

        function getElementContainer(element, id) {
          if (element.classList.contains(id) || element.getAttribute(id)) {
            return element;
          } else if (element.nodeName === 'BODY') {
            return null;
          }
          return getElementContainer(element.parentNode, id);
        }

        function getTipHeight() {
          var tipHeight;
          if (!tipElement) {
            tipElement = $selectTooltip.$element = tipLinker(scope);
          }

          tipElement.css({ display: 'inline-block' });
          tipHeight = tipElement[0].offsetHeight;
          tipElement.css({ display: 'none' });
          return tipHeight;
        }

        function getPosition() {
          if (options.container === 'body') {
            return dimensions.offset(options.target || element[0]);
          } else {
            return dimensions.position(options.target || element[0]);
          }
        }

        function getCalculatedOffset(placement, position, actualWidth, actualHeight) {
          var offset;
          var split = placement.split('-');

          switch (split[0]) {
            case 'right':
              offset = {
                top: position.top + position.height / 2 - actualHeight / 2,
                left: position.left + position.width
              };
              break;
            case 'bottom':
              offset = {
                top: position.top + position.height,
                left: position.left + position.width / 2 - actualWidth / 2
              };
              break;
            case 'left':
              offset = {
                top: position.top + position.height / 2 - actualHeight / 2,
                left: position.left - actualWidth
              };
              break;
            default:
              offset = {
                top: position.top - actualHeight,
                left: position.left + position.width / 2 - actualWidth / 2
              };
              break;
          }

          if (!split[1]) {
            return offset;
          }

          // Add support for corners @todo css
          if (split[0] === 'top' || split[0] === 'bottom') {
            switch (split[1]) {
              case 'left':
                offset.left = position.left;
                break;
              case 'right':
                offset.left = position.left + position.width - actualWidth;
            }
          } else if (split[0] === 'left' || split[0] === 'right') {
            switch (split[1]) {
              case 'top':
                offset.top = position.top - actualHeight;
                break;
              case 'bottom':
                offset.top = position.top + position.height;
            }
          }

          return offset;
        }

        return $selectTooltip;
      }

      // Helper functions

      function findElement(query, element) {
        return angular.element((element || document).querySelectorAll(query));
      }

      function fetchTemplate(template) {
        return $q.when($templateCache.get(template) || $http.get(template)).then(function (res) {
          if (angular.isObject(res)) {
            $templateCache.put(template, res.data);
            return res.data;
          }
          return res;
        });
      }

      return TooltipFactory;
    }];
  });
})();

(function () {
  'use strict';

  angular.module('ark.core').provider('$select', function () {
    var defaults = this.defaults = {
      animation: 'am-fade',

      prefixClass: 'select',
      placement: 'bottom-left',
      template: 'ark-select/ark-select.html',
      trigger: 'focus',
      container: false,
      keyboard: true,
      html: false,
      delay: 0,
      multiple: false,
      enableSelectAll: false,
      sort: false,
      caretIcon: 'icon-dropdown-arrow',
      placeholder: 'Choose among the following...',
      allText: 'All',
      maxLength: 2,
      maxLengthHtml: 'selected',
      maxSelected: -1,
      iconCheckmark: 'fonticon fonticon-ok icon-tick check-mark',
      parentId: '',
      resize: false,
      dropup: false
    };

    this.$get = ['$window', '$document', '$rootScope', '$selectTooltip', '$timeout', function ($window, $document, $rootScope, $selectTooltip, $timeout) {

      // var bodyEl = angular.element($window.document.body);
      var isTouch = false; // 'createTouch' in $window.document; ARK-1787: touch support is not required. Mousedown is always fired on touch and non-touch devices

      function SelectFactory(element, controller, config) {

        var $select = {};

        // Common vars
        var options = angular.extend({}, defaults, config);

        $select = $selectTooltip(element, options);
        var scope = $select.$scope;

        scope.$matches = [];
        scope.$activeIndex = 0;
        scope.$isMultiple = options.multiple;
        scope.$iconCheckmark = options.iconCheckmark;
        scope.$allText = options.allText;
        scope.$parentId = options.parentId;
        scope.$enableSelectAll = options.enableSelectAll;
        scope.$options = options;

        scope.$activate = function (index) {
          $timeout(function () {
            $select.activate(index);
          });
        };

        scope.$select = function (index) {
          $timeout(function () {
            $select.select(index);
          });
        };

        scope.$selectAll = function () {
          $timeout(function () {
            $select.selectAll();
          });
        };

        scope.$isVisible = function () {
          return $select.$isVisible();
        };

        scope.$isActive = function (index) {
          return $select.$isActive(index);
        };

        scope.$isMaxSelected = function () {
          return $select.$isMaxSelected();
        };

        scope.$isAllSelected = function () {
          return $select.$isAllSelected();
        };

        // Public methods

        $select.update = function (matches) {
          scope.$matches = matches;
          $select.$updateActiveIndex();
        };

        $select.activate = function (index) {
          if (options.multiple) {
            scope.$activeIndex.sort();
            $select.$isActive(index) ? scope.$activeIndex.splice(scope.$activeIndex.indexOf(index), 1) : scope.$activeIndex.push(index); // jshint ignore:line
            if (options.sort) {
              scope.$activeIndex.sort();
            }
          } else {
            scope.$activeIndex = index;
          }
          return scope.$activeIndex;
        };

        $select.select = function (index) {
          if (options.maxSelected !== -1 && scope.$activeIndex.length >= options.maxSelected && scope.$activeIndex.indexOf(index) < 0) {
            return;
          } else {
            var value = scope.$matches[index].value;
            scope.$apply(function () {
              $select.activate(index);

              if (options.multiple) {
                options.maxSelected = parseInt(options.maxSelected);
                controller.$setViewValue(scope.$activeIndex.map(function (index) {
                  return scope.$matches[index].value;
                }));
              } else {
                controller.$setViewValue(value);
                $select.hide();
              }
            });
            // Emit event
            scope.$emit('$select.select', value, index);
          }
        };

        $select.selectAll = function () {
          var shouldSelectAll = !$select.$isAllSelected();

          for (var i = 0; i < scope.$matches.length; i++) {
            if (shouldSelectAll !== scope.$activeIndex.indexOf(i) > -1) {
              // Deselect all
              $select.select(i);
            }
          }
        };

        // Protected methods

        $select.$isAllSelected = function () {
          return options.multiple && scope.$activeIndex.length === scope.$matches.length;
        };

        $select.$updateActiveIndex = function () {
          if (controller.$modelValue && scope.$matches.length) {
            if (options.multiple && angular.isArray(controller.$modelValue)) {
              var isWorking = true;
              for (var i = 0; i < controller.$modelValue.length; i++) {
                isWorking = typeof $select.$getIndex(controller.$modelValue[i]) !== 'undefined';
                if (!isWorking) {
                  break;
                }
              }
              scope.$activeIndex = isWorking ? controller.$modelValue.map(function (value) {
                return $select.$getIndex(value);
              }) : [];
            } else {
              scope.$activeIndex = $select.$getIndex(controller.$modelValue);
            }
          } else if (scope.$activeIndex >= scope.$matches.length) {
            scope.$activeIndex = options.multiple ? [] : 0;
          }
        };

        $select.$isVisible = function () {
          if (!options.minLength || !controller) {
            return scope.$matches.length;
          }
          // minLength support
          return scope.$matches.length && controller.$viewValue.length >= options.minLength;
        };

        $select.$clearActive = function () {
          if (options.multiple) {
            // remove all selected dropdown options
            scope.$activeIndex.length = 0;
            controller.$modelValue.length = 0;
          } else {
            // remove selected dropdown option
            scope.$activeIndex = 0;
            controller.$modelValue = 0;
          }
        };

        $select.$countSelected = function () {
          return scope.$activeIndex.length;
        };

        $select.$isActive = function (index) {
          if (options.multiple) {
            return scope.$activeIndex.indexOf(index) !== -1;
          } else {
            return scope.$activeIndex === index;
          }
        };

        $select.$isMaxSelected = function () {
          if (options.maxSelected !== -1) {
            return scope.$activeIndex.length >= options.maxSelected;
          }
          return false;
        };

        $select.$getIndex = function (value) {
          var l = scope.$matches.length;
          var i = l;
          if (!l) {
            return;
          }
          for (i = l; i--;) {
            if (scope.$matches[i].value === value) {
              break;
            }
          }
          if (i < 0) {
            return;
          }
          return i;
        };

        $select.$onMouseDown = function (evt) {
          // Prevent blur on mousedown on .dropdown-menu
          evt.preventDefault();
          evt.stopPropagation();
          // Emulate click for mobile devices
          if (isTouch) {
            var targetEl = angular.element(evt.target);
            targetEl.triggerHandler('click');
          }
          scope.dropdownMousedown = true;

          _.defer(function () {
            (element[0] || element).focus();
            _.defer(function () {
              scope.dropdownMousedown = false;
            });
          });
        };

        $select.$onKeyDown = function (evt) {
          if (!/(9|13|38|40)/.test(evt.keyCode)) {
            return;
          }
          evt.preventDefault();
          evt.stopPropagation();

          // Select with enter
          if (!options.multiple && (evt.keyCode === 13 || evt.keyCode === 9)) {
            return $select.select(scope.$activeIndex);
          }

          // Navigate with keyboard
          if (evt.keyCode === 38 && scope.$activeIndex > 0) {
            scope.$activeIndex--;
          } else if (evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) {
            scope.$activeIndex++;
          } else if (angular.isUndefined(scope.$activeIndex)) {
            scope.$activeIndex = 0;
          }
          scope.$digest();
        };

        $select.$updateParentId = function (parentId) {
          scope.$parentId = parentId;
        };

        // Overrides

        var _show = $select.show;
        $select.show = function () {
          _show();
          if (options.multiple) {
            $select.$element.addClass('select-multiple');
          }
          setTimeout(function () {
            $select.$element.on(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown);
            if (options.keyboard) {
              element.on('keydown', $select.$onKeyDown);
            }
          });
        };

        var _hide = $select.hide;
        $select.hide = function () {
          $select.$element.off(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown);
          if (options.keyboard) {
            element.off('keydown', $select.$onKeyDown);
          }
          _hide(true);
        };

        return $select;
      }

      SelectFactory.defaults = defaults;

      return SelectFactory;
    }];
  });
})();

(function (angular) {
  'use strict';

  angular.module('ark.core').directive('arkSideTabs', function () {
    return {
      restrict: 'E',
      scope: {
        tabsList: '=',
        switchReload: '=?',
        activeTab: '=?'
      },
      controller: ['$log', function controller($log) {
        $log.debug('(DEPRECATED) Ark Side Tabs Component has been deprecated in favor of Ark Simple Tabs, please update your project. Ark Side Tabs will be removed in a future Ark Core version');
      }],
      template: '<ark-simple-tabs type="side" tabs="tabsList" switch-reload="switchReload" active-tab="activeTab"></ark-simple-tabs>'
    };
  });
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').directive('arkSidebar', function () {
    return {
      restrict: 'AE',
      scope: {
        showSidebar: '=?',
        showShadow: '=?',
        template: '='
      },
      templateUrl: 'ark-sidebar/ark-sidebar.html',
      link: function link(scope) {
        if (scope.showShadow === undefined) {
          scope.showShadow = true;
        }
        if (scope.showSidebar === undefined) {
          scope.showSidebar = true;
        }
      }
    };
  });
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').controller('ArkSimpleTabsCtrl', ['$scope', '$templateCache', function ($scope, $templateCache) {
    var ctrl = this;

    ctrl.setActive = function setActive(indexNum) {
      $scope.selectedItemIndex = indexNum;
      $scope.activeTab = indexNum;
      $scope.selectedTemplate = $scope.tabs[indexNum].templateUrl;
    };

    ctrl.setSelectedTemplate = function setSelectedTemplate() {
      $scope.selectedItemIndex = $scope.activeTab && $scope.tabs[$scope.activeTab] ? $scope.activeTab : $scope.selectedItemIndex || 0;
      $scope.activeTab = $scope.selectedItemIndex;
      $scope.selectedTemplate = $scope.tabs[$scope.selectedItemIndex].templateUrl;
    };

    // sets initial selected template
    ctrl.setSelectedTemplate();

    // watches for changes to activeTab and sets selectedTemplate
    $scope.$watch('activeTab', ctrl.setSelectedTemplate);

    $scope.$watch('tabs', function (newValue) {
      var newTabs = [];
      var index = 0;
      newValue.forEach(function (n) {
        if (angular.isDefined(n.template)) {
          var newUrl = 'ark-simple-tab-template' + index++;
          $templateCache.put(newUrl, n.template);
          newTabs.push({
            title: n.title,
            icon: n.icon,
            templateUrl: newUrl
          });
        } else {
          newTabs.push(n);
        }
      });
      $scope.tabs = newTabs;
    }, true);
  }]);
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').directive('arkSimpleTabs', function () {
    return {
      restrict: 'E',
      scope: {
        tabs: '=',
        type: '@',
        iconsOnly: '=?',
        switchReload: '=?',
        activeTab: '=?'
      },
      controller: 'ArkSimpleTabsCtrl',
      controllerAs: 'ctrl',
      templateUrl: function templateUrl(element, attrs) {
        var type = ['simple', 'side', 'underline'].indexOf(attrs.type) >= 0 ? attrs.type : 'simple';
        return 'ark-simple-tabs/ark-' + type + '-tabs.html';
      }
    };
  });
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').controller('ArkSliderCtrl', ['$scope', function ($scope) {
    $scope.isActive = false;

    $scope.setActive = function () {
      $scope.isActive = !$scope.isActive;
    };
  }]);
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').directive('arkSlider', function () {
    return {
      restrict: 'E',
      scope: {
        showTooltip: '@',
        percentage: '@'
      },
      transclude: true,
      controller: 'ArkSliderCtrl',
      templateUrl: 'ark-slider/ark-slider.html',
      link: function link(scope, element) {
        var input = element.find('input');
        var ngModelCtrl = angular.element(input).controller('ngModel');
        scope.useTooltip = scope.$eval(scope.showTooltip) || false;
        scope.showPercentage = scope.$eval(scope.percentage) || false;
        var inputWidth = scope.useTooltip ? 100 : 85;

        angular.element(input).css('width', inputWidth + '%');

        if (!input || !ngModelCtrl || input[0].type !== 'range') {
          return;
        }

        scope.$watch(function () {
          scope.inputValue = ngModelCtrl.$viewValue;
          return ngModelCtrl.$viewValue;
        }, function (newValue) {
          if (newValue) {
            var min = parseInt(input[0].min || 0, 10);
            var max = parseInt(input[0].max || 100, 10);
            var cur = parseInt(newValue, 10);
            angular.element(element[0].querySelector('.slider-fill')).css('width', (cur - min) / (max - min) * inputWidth + '%');
          }
        });
      }
    };
  });
})(angular);

(function (window, angular) {
  // jshint -W030
  // jshint bitwise: false
  'use strict';

  var module = angular.module('ark.core');

  module.directive('arkSortableRoot', [function () {
    function shouldBeAfter(elem, pointer, isGrid) {
      return isGrid ? elem.x - pointer.x < 0 : elem.y - pointer.y < 0;
    }

    function getSortableElements(key) {
      return ROOTS_MAP[key];
    }

    function removeSortableElements(key) {
      delete ROOTS_MAP[key];
    }

    var sortingInProgress;
    var ROOTS_MAP = Object.create(null);
    // window.ROOTS_MAP = ROOTS_MAP; // for debug purposes

    return {
      restrict: 'A',
      controller: ['$scope', '$attrs', '$interpolate', '$parse', function ($scope, $attrs, $interpolate, $parse) {
        var mapKey = $interpolate($attrs.arkSortableRoot)($scope) || $scope.$id;
        if (!ROOTS_MAP[mapKey]) {
          ROOTS_MAP[mapKey] = [];
        }

        var candidates; // set of possible destinations
        var $placeholder; // placeholder element
        var $helper; // helper element - the one thats being dragged around with the mouse pointer
        var $original; // original element
        var $target; // last best candidate
        var isGrid = false;
        var onSort = $parse($attrs.arkSortableOnSort);

        // ----- hack due to https://github.com/angular/angular.js/issues/8044
        $attrs.arkSortableOnStart = $attrs.$$element[0].attributes['ark-sortable-on-start'];
        $attrs.arkSortableOnStart = $attrs.arkSortableOnStart && $attrs.arkSortableOnStart.value;

        $attrs.arkSortableOnStop = $attrs.$$element[0].attributes['ark-sortable-on-stop'];
        $attrs.arkSortableOnStop = $attrs.arkSortableOnStop && $attrs.arkSortableOnStop.value;
        // -------------------------------------------------------------------

        var onStart = $parse($attrs.arkSortableOnStart);
        var onStop = $parse($attrs.arkSortableOnStop);

        this.sortingInProgress = function () {
          return sortingInProgress;
        };

        if ($attrs.arkSortableGrid) {
          // ark-sortable-grid determined explicite
          isGrid = $attrs.arkSortableGrid === 'true' ? true : $attrs.arkSortableGrid === 'false' ? false : null;
          if (isGrid === null) {
            throw 'Invalid value of ark-sortable-grid attribute';
          }
        } else {
          // check if at least one of the lists have a grid like layout
          $scope.$watchCollection(function () {
            return getSortableElements(mapKey);
          }, function (collection) {
            isGrid = false;
            var array = collection.filter(function (item) {
              return !item.container;
            }).map(function (item) {
              return {
                part: item.getPart().id,
                y: item.element[0].getBoundingClientRect().top
              };
            });
            var dict = Object.create(null);
            array.forEach(function (item) {
              if (dict[item.part]) {
                dict[item.part].push(item.y);
              } else {
                dict[item.part] = [item.y];
              }
            });
            Object.keys(dict).forEach(function (key) {
              dict[key].sort();
              dict[key].forEach(function (item, index) {
                if (index < dict[key].length - 1) {
                  if (item > 0 && item === dict[key][index + 1]) {
                    isGrid = true;
                  }
                }
              });
            });
          });
        }

        this.$moveUpdate = function (opts, mouse, arkSortableElement, svOriginal, arkSortablePlaceholder, originatingPart, originatingIndex) {
          var svRect = arkSortableElement[0].getBoundingClientRect();
          if (opts.tolerance === 'element') {
            mouse = {
              x: ~~(svRect.left + svRect.width / 2),
              y: ~~(svRect.top + svRect.height / 2)
            };
          }

          sortingInProgress = true;
          candidates = [];
          if (!$placeholder) {
            if (arkSortablePlaceholder) {
              // custom placeholder
              $placeholder = arkSortablePlaceholder.clone();
              $placeholder.removeClass('ng-hide');
            } else {
              // default placeholder
              $placeholder = svOriginal.clone();
              $placeholder.addClass('sv-visibility-hidden');
              $placeholder.addClass('sv-placeholder');
              $placeholder.css({
                'height': svRect.height + 'px',
                'width': svRect.width + 'px'
              });
            }

            svOriginal.after($placeholder);
            svOriginal.addClass('ng-hide');

            // cache options, helper and original element reference
            $original = svOriginal;
            $helper = arkSortableElement;

            onStart($scope, {
              $helper: {
                element: $helper
              },
              $part: originatingPart.model(originatingPart.scope),
              $index: originatingIndex,
              $item: originatingPart.model(originatingPart.scope)[originatingIndex]
            });
            $scope.$root && $scope.$root.$$phase || $scope.$apply();
          }

          // ----- move the element
          // Only executes if the $helper was cloned through mousedown event handler
          if (typeof $helper[0].reposition === 'function') {
            $helper[0].reposition({
              x: mouse.x + document.body.scrollLeft - mouse.offset.x * svRect.width,
              y: mouse.y + document.body.scrollTop - mouse.offset.y * svRect.height
            });
          }

          // ----- manage candidates
          getSortableElements(mapKey).forEach(function (se) {
            if (opts.containment !== null) {
              // TODO: optimize this since it could be calculated only once when the moving begins
              if (!elementMatchesSelector(se.element, opts.containment) && !elementMatchesSelector(se.element, opts.containment + ' *')) {
                return; // element is not within allowed containment
              }
            }
            var rect = se.element[0].getBoundingClientRect();
            var center = {
              x: ~~(rect.left + rect.width / 2),
              y: ~~(rect.top + rect.height / 2)
            };

            if (!se.container && ( // not the container element
            se.element[0].scrollHeight || se.element[0].scrollWidth)) {
              // element is visible
              candidates.push({
                element: se.element,
                q: (center.x - mouse.x) * (center.x - mouse.x) + (center.y - mouse.y) * (center.y - mouse.y),
                view: se.getPart(),
                targetIndex: se.getIndex(),
                after: shouldBeAfter(center, mouse, isGrid)
              });
            }
            if (se.container && !se.element[0].querySelector('[ark-sortable-element]:not(.sv-placeholder):not(.sv-source)')) {
              // empty container
              candidates.push({
                element: se.element,
                q: (center.x - mouse.x) * (center.x - mouse.x) + (center.y - mouse.y) * (center.y - mouse.y),
                view: se.getPart(),
                targetIndex: 0,
                container: true
              });
            }
          });
          var pRect = $placeholder[0].getBoundingClientRect();
          var pCenter = {
            x: ~~(pRect.left + pRect.width / 2),
            y: ~~(pRect.top + pRect.height / 2)
          };
          candidates.push({
            q: (pCenter.x - mouse.x) * (pCenter.x - mouse.x) + (pCenter.y - mouse.y) * (pCenter.y - mouse.y),
            element: $placeholder,
            placeholder: true
          });
          candidates.sort(function (a, b) {
            return a.q - b.q;
          });

          candidates.forEach(function (cand, index) {
            if (index === 0 && !cand.placeholder && !cand.container) {
              $target = cand;
              cand.element.addClass('sv-candidate');
              if (cand.after) {
                cand.element.after($placeholder);
              } else {
                insertElementBefore(cand.element, $placeholder);
              }
            } else if (index === 0 && cand.container) {
              $target = cand;
              cand.element.append($placeholder);
            } else {
              cand.element.removeClass('sv-candidate');
            }
          });
        };

        this.$drop = function (originatingPart, index, options) {
          if (!$placeholder) {
            return;
          }

          if (options.revert) {
            var placeholderRect = $placeholder[0].getBoundingClientRect();
            var helperRect = $helper[0].getBoundingClientRect();
            var distance = Math.sqrt(Math.pow(helperRect.top - placeholderRect.top, 2) + Math.pow(helperRect.left - placeholderRect.left, 2));

            var duration = +options.revert * distance / 200; // constant speed: duration depends on distance
            duration = Math.min(duration, +options.revert); // however it's not longer that options.revert

            ['-webkit-', '-moz-', '-ms-', '-o-', ''].forEach(function (prefix) {
              if (typeof $helper[0].style[prefix + 'transition'] !== 'undefined') {
                $helper[0].style[prefix + 'transition'] = 'all ' + duration + 'ms ease';
              }
            });
            setTimeout(afterRevert, duration);
            $helper.css({
              'top': placeholderRect.top + document.body.scrollTop + 'px',
              'left': placeholderRect.left + document.body.scrollLeft + 'px'
            });
          } else {
            afterRevert();
          }

          function afterRevert() {
            sortingInProgress = false;
            $placeholder.remove();
            $helper.remove();
            $original.removeClass('ng-hide');

            candidates = void 0;
            $placeholder = void 0;
            options = void 0;
            $helper = void 0;
            $original = void 0;

            // ark-sortable-on-stop callback
            onStop($scope, {
              $part: originatingPart.model(originatingPart.scope),
              $index: index,
              $item: originatingPart.model(originatingPart.scope)[index]
            });

            if ($target) {
              $target.element.removeClass('sv-candidate');
              var spliced = originatingPart.model(originatingPart.scope).splice(index, 1);
              var targetIndex = $target.targetIndex;
              if ($target.view === originatingPart && $target.targetIndex > index) {
                targetIndex--;
              }
              if ($target.after) {
                targetIndex++;
              }
              $target.view.model($target.view.scope).splice(targetIndex, 0, spliced[0]);

              // ark-sortable-on-sort callback
              if ($target.view !== originatingPart || index !== targetIndex) {
                onSort($scope, {
                  $partTo: $target.view.model($target.view.scope),
                  $partFrom: originatingPart.model(originatingPart.scope),
                  $item: spliced[0],
                  $indexTo: targetIndex,
                  $indexFrom: index
                });
              }
            }
            $target = void 0;

            $scope.$root && $scope.$root.$$phase || $scope.$apply();
          }
        };

        this.addToSortableElements = function (se) {
          getSortableElements(mapKey).push(se);
        };
        this.removeFromSortableElements = function (se) {
          var elems = getSortableElements(mapKey);
          var index = elems.indexOf(se);
          if (index > -1) {
            elems.splice(index, 1);
            if (elems.length === 0) {
              removeSortableElements(mapKey);
            }
          }
        };
      }]
    };
  }]);

  module.directive('arkSortablePart', ['$parse', function ($parse) {
    return {
      restrict: 'A',
      require: '^arkSortableRoot',
      controller: ['$scope', function ($scope) {
        $scope.$ctrl = this;
        this.getPart = function () {
          return $scope.part;
        };
        this.$drop = function (index, options) {
          $scope.$sortableRoot.$drop($scope.part, index, options);
        };
      }],
      scope: true,
      link: function link($scope, $element, $attrs, $sortable) {
        if (!$attrs.arkSortablePart) {
          throw new Error('no model provided');
        }
        var model = $parse($attrs.arkSortablePart);
        if (!model.assign) {
          throw new Error('model not assignable');
        }

        $scope.part = {
          id: $scope.$id,
          element: $element,
          model: model,
          scope: $scope
        };
        $scope.$sortableRoot = $sortable;

        var sortablePart = {
          element: $element,
          getPart: $scope.$ctrl.getPart,
          container: true
        };
        $sortable.addToSortableElements(sortablePart);
        $scope.$on('$destroy', function () {
          $sortable.removeFromSortableElements(sortablePart);
        });
      }
    };
  }]);

  module.directive('arkSortableElement', ['$parse', function ($parse) {
    return {
      restrict: 'A',
      require: ['^arkSortablePart', '^arkSortableRoot'],
      controller: ['$scope', function ($scope) {
        $scope.$ctrl = this;
      }],
      link: function link($scope, $element, $attrs, $controllers) {
        var sortableElement = {
          element: $element,
          getPart: $controllers[0].getPart,
          getIndex: function getIndex() {
            return $scope.$index;
          }
        };
        $controllers[1].addToSortableElements(sortableElement);
        $scope.$on('$destroy', function () {
          $controllers[1].removeFromSortableElements(sortableElement);
        });

        var handle = $element;
        var startTimer;
        var clearEvent = function clearEvent() {
          clearTimeout(startTimer);
        };

        var opts = $parse($attrs.arkSortableElement)($scope);
        opts = angular.extend({}, {
          delay: 10
        }, opts);

        var event = onMousedown;
        if (opts.delay) {
          event = function event(e) {
            html.on('mouseup touchend', clearEvent);
            startTimer = setTimeout(function () {
              onMousedown(e);
            }, opts.delay);
          };
        }

        handle.on('mousedown touchstart', event);
        $scope.$watch('$ctrl.handle', function (customHandle) {
          if (customHandle) {
            clearEvent();
            handle.off('mousedown touchstart', event);
            handle = customHandle;
            handle.on('mousedown touchstart', event);
          }
        });

        var helper;
        $scope.$watch('$ctrl.helper', function (customHelper) {
          if (customHelper) {
            helper = customHelper;
          }
        });

        var placeholder;
        $scope.$watch('$ctrl.placeholder', function (customPlaceholder) {
          if (customPlaceholder) {
            placeholder = customPlaceholder;
          }
        });

        var html = angular.element(document.documentElement);

        var moveExecuted;

        function onMousedown(e) {
          touchFix(e);

          if ($controllers[1].sortingInProgress()) {
            return;
          }
          if (e.button !== 0 && e.type === 'mousedown') {
            return;
          }

          moveExecuted = false;
          var opts = $parse($attrs.arkSortableElement)($scope);
          opts = angular.extend({}, {
            tolerance: 'pointer',
            revert: 200,
            containment: 'html'
          }, opts);
          if (opts.containment) {
            var containmentRect = closestElement.call($element, opts.containment)[0].getBoundingClientRect();
          }

          var target = $element;
          var clientRect = $element[0].getBoundingClientRect();
          var clone;

          if (!helper) {
            helper = $controllers[0].helper;
          }
          if (!placeholder) {
            placeholder = $controllers[0].placeholder;
          }
          if (helper) {
            clone = helper.clone();
            clone.removeClass('ng-hide');
            clone.css({
              'left': clientRect.left + document.body.scrollLeft + 'px',
              'top': clientRect.top + document.body.scrollTop + 'px'
            });
            target.addClass('sv-visibility-hidden');
          } else {
            clone = target.clone();
            clone.addClass('sv-helper').css({
              'left': clientRect.left + document.body.scrollLeft + 'px',
              'top': clientRect.top + document.body.scrollTop + 'px',
              'width': clientRect.width + 'px'
            });
          }

          clone[0].reposition = function (coords) {
            var targetLeft = coords.x;
            var targetTop = coords.y;
            var helperRect = clone[0].getBoundingClientRect();

            var body = document.body;

            if (containmentRect) {
              if (targetTop < containmentRect.top + body.scrollTop) {
                // top boundary
                targetTop = containmentRect.top + body.scrollTop;
              }
              if (targetTop + helperRect.height > containmentRect.top + body.scrollTop + containmentRect.height) {
                // bottom boundary
                targetTop = containmentRect.top + body.scrollTop + containmentRect.height - helperRect.height;
              }
              if (targetLeft < containmentRect.left + body.scrollLeft) {
                // left boundary
                targetLeft = containmentRect.left + body.scrollLeft;
              }
              if (targetLeft + helperRect.width > containmentRect.left + body.scrollLeft + containmentRect.width) {
                // right boundary
                targetLeft = containmentRect.left + body.scrollLeft + containmentRect.width - helperRect.width;
              }
            }
            this.style.left = targetLeft - body.scrollLeft + 'px';
            this.style.top = targetTop - body.scrollTop + 'px';
          };

          var pointerOffset = {
            x: (e.clientX - clientRect.left) / clientRect.width,
            y: (e.clientY - clientRect.top) / clientRect.height
          };
          html.addClass('sv-sorting-in-progress');
          html.on('mousemove touchmove', onMousemove).on('mouseup touchend touchcancel', function mouseup() {
            html.off('mousemove touchmove', onMousemove);
            html.off('mouseup touchend', mouseup);
            html.removeClass('sv-sorting-in-progress');
            if (moveExecuted) {
              $controllers[0].$drop($scope.$index, opts);
            } else {
              $element.removeClass('sv-visibility-hidden');
            }
          });

          // onMousemove(e);
          function onMousemove(e) {
            touchFix(e);
            if (!moveExecuted) {
              $element.parent().prepend(clone);
              moveExecuted = true;
            }
            $controllers[1].$moveUpdate(opts, {
              x: e.clientX,
              y: e.clientY,
              offset: pointerOffset
            }, clone, $element, placeholder, $controllers[0].getPart(), $scope.$index);
          }
        }
      }
    };
  }]);

  module.directive('arkSortableHandle', function () {
    return {
      require: '?^arkSortableElement',
      link: function link($scope, $element, $attrs, $ctrl) {
        if ($ctrl) {
          $ctrl.handle = $element.add($ctrl.handle); // support multiple handles
        }
      }
    };
  });

  module.directive('arkSortableHelper', function () {
    return {
      require: ['?^arkSortablePart', '?^arkSortableElement'],
      link: function link($scope, $element, $attrs, $ctrl) {
        $element.addClass('sv-helper').addClass('ng-hide');
        if ($ctrl[1]) {
          $ctrl[1].helper = $element;
        } else if ($ctrl[0]) {
          $ctrl[0].helper = $element;
        }
      }
    };
  });

  module.directive('arkSortablePlaceholder', function () {
    return {
      require: ['?^arkSortablePart', '?^arkSortableElement'],
      link: function link($scope, $element, $attrs, $ctrl) {
        $element.addClass('sv-placeholder').addClass('ng-hide');
        if ($ctrl[1]) {
          $ctrl[1].placeholder = $element;
        } else if ($ctrl[0]) {
          $ctrl[0].placeholder = $element;
        }
      }
    };
  });

  angular.element(document.head).append(['<style>' + '.sv-helper{' + 'position: fixed !important;' + 'z-index: 99999;' + 'margin: 0 !important;' + '}' + '.sv-candidate{' + '}' + '.sv-placeholder{' +
  // 'opacity: 0;' +
  '}' + '.sv-sorting-in-progress{' + '-webkit-user-select: none;' + '-moz-user-select: none;' + '-ms-user-select: none;' + 'user-select: none;' + '}' + '.sv-visibility-hidden{' + 'visibility: hidden !important;' + 'opacity: 0 !important;' + '}' + '</style>'].join(''));

  function touchFix(e) {
    if (!('clientX' in e) && !('clientY' in e)) {
      var touches = e.touches || e.originalEvent.touches;
      if (touches && touches.length) {
        e.clientX = touches[0].clientX;
        e.clientY = touches[0].clientY;
      }
      e.preventDefault();
    }
  }

  function getPreviousSibling(element) {
    element = element[0];
    if (element.previousElementSibling) {
      return angular.element(element.previousElementSibling);
    } else {
      var sib = element.previousSibling;
      while (sib !== null && sib.nodeType !== 1) {
        sib = sib.previousSibling;
      }
      return angular.element(sib);
    }
  }

  function insertElementBefore(element, newElement) {
    var prevSibl = getPreviousSibling(element);
    if (prevSibl.length > 0) {
      prevSibl.after(newElement);
    } else {
      element.parent().prepend(newElement);
    }
  }

  var dde = document.documentElement;
  var matchingFunction = dde.matches ? 'matches' : dde.matchesSelector ? 'matchesSelector' : dde.webkitMatches ? 'webkitMatches' : dde.webkitMatchesSelector ? 'webkitMatchesSelector' : dde.msMatches ? 'msMatches' : dde.msMatchesSelector ? 'msMatchesSelector' : dde.mozMatches ? 'mozMatches' : dde.mozMatchesSelector ? 'mozMatchesSelector' : null;
  if (matchingFunction === null) {
    throw 'This browser doesn\'t support the HTMLElement.matches method';
  }

  function elementMatchesSelector(element, selector) {
    if (element instanceof angular.element) {
      element = element[0];
    }
    if (matchingFunction !== null) {
      return element[matchingFunction](selector);
    }
  }

  var closestElement = angular.element.prototype.closest || function (selector) {
    var el = this[0].parentNode;
    while (el !== document.documentElement && !el[matchingFunction](selector)) {
      el = el.parentNode;
    }

    if (el[matchingFunction](selector)) {
      return angular.element(el);
    } else {
      return angular.element();
    }
  };

  /*
    Simple implementation of jQuery's .add method
   */
  if (typeof angular.element.prototype.add !== 'function') {
    angular.element.prototype.add = function (elem) {
      var i;
      var res = angular.element();
      elem = angular.element(elem);
      for (i = 0; i < this.length; i++) {
        res.push(this[i]);
      }
      for (i = 0; i < elem.length; i++) {
        res.push(elem[i]);
      }
      return res;
    };
  }
})(window, window.angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').controller('ArkTagsCtrl', ['$scope', function ($scope) {
    var ctrl = this;

    ctrl.sortAlphabetically = function sortAlphabetically(a, b) {
      if (a.toLowerCase() < b.toLowerCase()) {
        return -1;
      } else if (a.toLowerCase() > b.toLowerCase()) {
        return 1;
      }
      // sanity check
      return 0;
    };

    ctrl.addTag = function addTag() {
      var index;
      if ($scope.inputTag) {
        if ((index = $scope.tagList.indexOf($scope.inputTag)) >= 0) {
          // Tag already in tag list
          $scope.inputTag = '';
          if ($scope.restartAnimation) {
            $scope.restartAnimation(index);
          }
          return;
        }
        $scope.tagList.push($scope.inputTag);
        $scope.inputTag = '';
        if ($scope.sort) {
          $scope.tagList.sort(ctrl.sortAlphabetically);
        }
      } else if ($scope.focusInputBox) {
        $scope.focusInputBox();
      }
    };

    ctrl.removeTag = function removeTag(tag) {
      var index = $scope.tagList.indexOf(tag);
      $scope.tagList.splice(index, 1);
    };

    (function init() {
      $scope.tagList = $scope.tagList || [];

      if ($scope.sort && $scope.tagList && $scope.tagList.length) {
        $scope.tagList.sort(ctrl.sortAlphabetically);
      }
    })();
  }]);
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').directive('arkTags', ['$timeout', function ($timeout) {
    return {
      restrict: 'E',
      scope: {
        tagList: '=tags',
        sort: '=?'
      },
      templateUrl: 'ark-tags/ark-tags.html',
      controller: 'ArkTagsCtrl',
      controllerAs: 'ctrl',
      link: function link(scope, element, attr, ctrl) {
        scope.focusInputBox = function focusInputBox() {
          element[0].querySelector('.input-tag').focus();
        };

        scope.restartAnimation = function restartAnimation(index) {
          var currTag = angular.element(element[0].querySelectorAll('span.tag-label')[index]).parent();
          // sanity check
          if (currTag.length) {
            currTag.removeClass('animated pulse');
            $timeout(function () {
              currTag.addClass('animated pulse');
            });
          }
        };

        angular.element(element[0].querySelector('.input-tag')).bind('keydown keypress', function (event) {
          if (event.which === 13) {
            scope.$apply(function () {
              ctrl.addTag();
            });
            event.preventDefault();
          }
        });
      }
    };
  }]);
})(angular);

(function (angular) {
  'use strict';

  // TODO: See list
  // - Rename component to ArkTimepicker (keeping name convention as ArkDatepicker)
  // - Value should be a Date Object instead of a String
  // - Code should be reused between ArkTimepicker and timepicker section in ArkDatepicker

  angular.module('ark.core').controller('ArkTimePickerCtrl', ['$scope', 'arkDatepickerData', '_', function ($scope, arkDatepickerData, _) {
    $scope.timeData = {
      hour: '',
      minute: '',
      noon: '',
      timeZone: '',
      hourList: [],
      minuteList: [],
      noonList: [],
      timeZoneList: [],
      showHourList: false,
      showMinuteList: false,
      showNoonList: false,
      showTimeZoneList: false
    };

    $scope.timeData.hourList = !$scope.militaryTime ? arkDatepickerData.hourList : arkDatepickerData.militaryHourList;
    $scope.timeData.minuteList = arkDatepickerData.minuteList;
    $scope.timeData.noonList = arkDatepickerData.noonList;
    $scope.timeData.timeZoneList = arkDatepickerData.timeZoneList;

    var controller = this;

    // Hour Section
    $scope.isInvalidHour = function () {
      return controller.isInvalidHour($scope.timeData.hour, $scope.timeData.noon);
    };

    controller.isInvalidHour = function (hour, noon) {
      return !hour || isNaN(hour) || hour.indexOf('.') !== -1 || hour.length > 2 || (noon === 'AM' && (parseInt(hour) > 12 || parseInt(hour) < 0) || noon === 'PM' && (parseInt(hour) > 12 || parseInt(hour) < 1)) && !$scope.militaryTime || parseInt(hour) > 24;
    };

    $scope.validateHour = function () {
      if ($scope.isInvalidHour()) {
        $scope.timeData.hour = $scope.prevHour;
      } else {
        $scope.prevHour = $scope.timeData.hour;
      }
      $scope.timeData.showHourList = false;
    };

    $scope.addHour = function () {
      if (!$scope.militaryTime) {
        if ($scope.timeData.noon === 'AM') {
          if ($scope.timeData.hour === '11') {
            $scope.timeData.noon = 'PM';
            $scope.timeData.hour = '12';
          } else {
            $scope.timeData.hour = parseInt($scope.timeData.hour) % 12 + 1 + '';
          }
        } else {
          if ($scope.timeData.hour === '11') {
            $scope.timeData.noon = 'AM';
          }
          $scope.timeData.hour = parseInt($scope.timeData.hour) % 12 + 1 + '';
        }
      } else if ($scope.timeData.hour === '24') {
        $scope.timeData.hour = '01';
      } else {
        $scope.timeData.hour = $scope.formatNumber(parseInt($scope.timeData.hour) + 1 + '');
      }
      $scope.prevHour = $scope.timeData.hour;
      $scope.prevNoon = $scope.timeData.noon;
    };

    $scope.minusHour = function () {
      if (!$scope.militaryTime) {
        if ($scope.timeData.noon === 'AM') {
          if ($scope.timeData.hour === '00' || $scope.timeData.hour === '0' || $scope.timeData.hour === '12') {
            $scope.timeData.noon = 'PM';
            $scope.timeData.hour = '11';
          } else {
            $scope.timeData.hour = parseInt($scope.timeData.hour) - 1 + '';
          }
        } else {
          if ($scope.timeData.hour === '12') {
            $scope.timeData.noon = 'AM';
          }
          $scope.timeData.hour = $scope.timeData.hour === '01' || $scope.timeData.hour === '1' ? $scope.timeData.hour = '12' : parseInt($scope.timeData.hour) - 1 + '';
        }
      } else if ($scope.timeData.hour === '01') {
        $scope.timeData.hour = '24';
      } else {
        $scope.timeData.hour = $scope.formatNumber(parseInt($scope.timeData.hour) - 1 + '');
      }
      $scope.prevHour = $scope.timeData.hour;
      $scope.prevNoon = $scope.timeData.noon;
    };

    // Minute section
    $scope.isInvalidMinute = function () {
      return controller.isInvalidMinute($scope.timeData.minute);
    };

    controller.isInvalidMinute = function (minute) {
      return !minute || isNaN(minute) || minute.indexOf('.') !== -1 || minute.length > 2 || parseInt(minute) > 59 || parseInt(minute) < 0;
    };

    $scope.formatNumber = function (input) {
      if (input.length === 1) {
        input = '0' + input;
      }
      return input;
    };

    $scope.addMinute = function () {
      if ($scope.timeData.minute === '59') {
        $scope.addHour();
      }
      $scope.timeData.minute = $scope.formatNumber((parseInt($scope.timeData.minute) + 1) % 60 + '');
      $scope.prevMinute = $scope.timeData.minute;
    };

    $scope.minusMinute = function () {
      if ($scope.timeData.minute === '0' || $scope.timeData.minute === '00') {
        $scope.minusHour();
      }
      $scope.timeData.minute = $scope.formatNumber((parseInt($scope.timeData.minute) + 59) % 60 + '');
      $scope.prevMinute = $scope.timeData.minute;
    };

    $scope.validateMinute = function () {
      if ($scope.isInvalidMinute()) {
        $scope.timeData.minute = $scope.prevMinute;
      } else {
        $scope.timeData.minute = $scope.formatNumber($scope.timeData.minute);
        $scope.prevMinute = $scope.timeData.minute;
      }
      $scope.timeData.showMinuteList = false;
    };

    // AM/PM section
    $scope.changeNoon = function () {
      if ($scope.timeData.noon === 'AM') {
        if ($scope.timeData.hour === '0' || $scope.timeData.hour === '00') {
          $scope.timeData.hour = '12';
          $scope.prevHour = $scope.timeData.hour;
        }
        $scope.timeData.noon = 'PM';
      } else {
        $scope.timeData.noon = 'AM';
      }
      $scope.prevNoon = $scope.timeData.noon;
    };

    $scope.validateNoon = function () {
      if ($scope.timeData.noon.toLowerCase() === 'am' || $scope.timeData.noon.toLowerCase() === 'pm') {
        if ($scope.timeData.noon.toLowerCase() === 'pm' && $scope.timeData.hour === '0') {
          $scope.timeData.hour = '12';
          $scope.prevHour = $scope.timeData.hour;
        }
        $scope.timeData.noon = $scope.timeData.noon.toUpperCase();
        $scope.prevNoon = $scope.timeData.noon;
      } else {
        $scope.timeData.noon = $scope.prevNoon;
      }
      $scope.timeData.showNoonList = false;
    };

    // returns bool
    controller.isInvalidNoon = function (noon) {
      return noon.toUpperCase() !== 'AM' && noon.toUpperCase() !== 'PM';
    };

    // Time Zone Section

    $scope.isInvalidTimeZone = function () {
      return controller.isInvalidTimeZone($scope.timeData.timeZone);
    };

    controller.isInvalidTimeZone = function (timeZone) {
      return !_.contains($scope.timeData.timeZoneList, timeZone);
    };

    $scope.validateTimeZone = function () {
      if ($scope.isInvalidTimeZone()) {
        $scope.timeData.timeZone = $scope.prevTimeZone;
      } else {
        $scope.prevTimeZone = $scope.timeData.timeZone;
      }
      $scope.timeData.showTimeZoneList = false;
    };

    $scope.addTimeZone = function () {
      if ($scope.timeZoneIndex > 0) {
        $scope.timeZoneIndex--;
      }
      $scope.timeData.timeZone = $scope.timeData.timeZoneList[$scope.timeZoneIndex];
      $scope.prevTimeZone = $scope.timeData.timeZone;
    };

    $scope.minusTimeZone = function () {
      if ($scope.timeZoneIndex < $scope.timeData.timeZoneList.length - 1) {
        $scope.timeZoneIndex++;
      }
      $scope.timeData.timeZone = $scope.timeData.timeZoneList[$scope.timeZoneIndex];
      $scope.prevTimeZone = $scope.timeData.timeZone;
    };

    // Show Hour/Minute/Noon/TimeZone
    $scope.showHour = function () {
      $scope.timeData.showHourList = true;
    };

    $scope.showMinute = function () {
      $scope.timeData.showMinuteList = true;
    };

    $scope.showNoon = function () {
      $scope.timeData.showNoonList = true;
    };

    $scope.showTimeZone = function () {
      $scope.timeData.showTimeZoneList = true;
    };
    // End Show Hour/Minute/Noon/TimeZone

    $scope.selectHour = function (item) {
      $scope.timeData.hour = item;
      $scope.prevHour = item;
    };

    $scope.selectMinute = function (item) {
      $scope.timeData.minute = item;
      $scope.prevMinute = item;
    };

    $scope.selectNoon = function (item) {
      $scope.timeData.noon = item;
      $scope.prevNoon = item;
    };

    $scope.selectTimeZone = function (item, index) {
      $scope.timeData.timeZone = item;
      $scope.prevTimeZone = item;
      $scope.timeZoneIndex = index;
    };

    // returns boolean
    controller.isInvalidFormat = function () {
      var timeString, timezoneString, times, timezoneRange, timeZone;
      if (!$scope.militaryTime && ($scope.time.split('.').length === 3 || $scope.time.split(':').length === 3)) {
        // if format is hh.mm.am
        timeString = $scope.time.split('.');
        if (timeString.length === 1) {
          timeString = $scope.time.split(':');
        }
        if ($scope.timezoneMode) {
          times = timeString[2].split('-');
          timezoneRange = '-';
          if (times.length === 1) {
            times = timeString[2].split('+');
            timezoneRange = '+';
          }
          timeString[2] = times[0];
          timezoneString = timezoneRange + times[1];
          timeZone = 'GMT' + timezoneString;
        }
        if (timeString[0].length === 1) {
          timeString[0] = '0' + timeString[0];
        }
        if (timeString[1].length === 1) {
          timeString[1] = '0' + timeString[1];
        }
        return controller.isInvalidNoon(timeString[2].toUpperCase()) || controller.isInvalidHour(timeString[0], timeString[2].toUpperCase()) || controller.isInvalidMinute(timeString[1]) || $scope.timezoneMode && controller.isInvalidTimeZone(timeZone);
      } else if ($scope.militaryTime && ($scope.time.split('.').length === 2 || $scope.time.split(':').length === 2)) {
        timeString = $scope.time.split('.');
        if (timeString.length === 1) {
          timeString = $scope.time.split(':');
        }
        if ($scope.timezoneMode) {
          times = timeString[1].split('-');
          timezoneRange = '-';
          if (times.length === 1) {
            times = timeString[1].split('+');
            timezoneRange = '+';
          }
          timeString[1] = times[0];
          timezoneString = timezoneRange + times[1];
          timeZone = 'GMT' + timezoneString;
        }
        if (timeString[0].length === 1) {
          timeString[0] = '0' + timeString[0];
        }
        if (timeString[1].length === 1) {
          timeString[1] = '0' + timeString[1];
        }
        return controller.isInvalidHour(timeString[0], 'AM') || controller.isInvalidMinute(timeString[1]) || $scope.timezoneMode && controller.isInvalidTimeZone(timeZone);
      } else {
        // if format does not contain hours, mins, noon
        return true;
      }
    };

    // void
    controller.setDefaultTime = function () {
      // set to default
      $scope.prevHour = $scope.militaryTime ? '09' : '9';
      $scope.timeData.hour = $scope.militaryTime ? '09' : '9';
      $scope.prevMinute = '00';
      $scope.timeData.minute = '00';
      $scope.prevNoon = 'AM';
      $scope.timeData.noon = 'AM';
      $scope.timeZoneIndex = 7;
      $scope.prevTimeZone = $scope.timeData.timeZoneList[$scope.timeZoneIndex];
      $scope.timeData.timeZone = $scope.timeData.timeZoneList[$scope.timeZoneIndex];
    };

    // void
    controller.displayNothing = function () {
      $scope.prevHour = '';
      $scope.timeData.hour = '';
      $scope.prevMinute = '';
      $scope.timeData.minute = '';
      $scope.prevNoon = '';
      $scope.timeData.noon = '';
      $scope.prevTimeZone = '';
      $scope.timeData.timeZone = '';
    };

    controller.removeLeadingZero = function (numString) {
      return numString.replace(/^0+/, '');
    };

    (function init() {
      if ($scope.time) {
        if (!controller.isInvalidFormat()) {
          var timeString, timezoneString, times, timezoneRange;
          if (!$scope.militaryTime && ($scope.time.split('.').length === 3 || $scope.time.split(':').length === 3)) {
            // if format is hh.mm.am
            timeString = $scope.time.split('.');
            if (timeString.length === 1) {
              timeString = $scope.time.split(':');
            }
            if ($scope.timezoneMode) {
              times = timeString[2].split('-');
              timezoneRange = '-';
              if (times.length === 1) {
                times = timeString[2].split('+');
                timezoneRange = '+';
              }
              timeString[2] = times[0];
              timezoneString = timezoneRange + times[1];
              $scope.prevTimeZone = $scope.timeData.timeZone = 'GMT' + timezoneString;
              $scope.timeZoneIndex = _.indexOf($scope.timeData.timeZoneList, $scope.timeData.timeZone);
            }
            $scope.prevHour = $scope.timeData.hour = controller.removeLeadingZero(timeString[0]);
            $scope.prevMinute = $scope.timeData.minute = timeString[1];
            $scope.prevNoon = $scope.timeData.noon = timeString[2].toUpperCase();
          } else {
            timeString = $scope.time.split('.');
            if (timeString.length === 1) {
              timeString = $scope.time.split(':');
            }
            if ($scope.timezoneMode) {
              times = timeString[1].split('-');
              timezoneRange = '-';
              if (times.length === 1) {
                times = timeString[1].split('+');
                timezoneRange = '+';
              }
              timeString[1] = times[0];
              timezoneString = timezoneRange + times[1];
              $scope.prevTimeZone = $scope.timeData.timeZone = 'GMT' + timezoneString;
              $scope.timeZoneIndex = _.indexOf($scope.timeData.timeZoneList, $scope.timeData.timeZone);
            }
            $scope.prevHour = $scope.timeData.hour = $scope.formatNumber(timeString[0]);
            $scope.prevMinute = $scope.timeData.minute = $scope.formatNumber(timeString[1]);
          }
        } else {
          // not valid, so display nothing in the component ui
          controller.displayNothing();
        }
      } else {
        controller.setDefaultTime();
      }
    })();
  }]);
})(angular);

(function (angular) {
  // jscs:disable disallowMultipleVarDecl
  'use strict';

  angular.module('ark.core').directive('arkTimePicker', function () {
    return {
      restrict: 'E',
      scope: {
        time: '=ngModel',
        headerLabel: '@label',
        widgetMode: '=',
        timezoneMode: '=',
        militaryTime: '=',
        simplifiedTime: '=',
        ngDisabled: '=?'
      },
      controller: 'ArkTimePickerCtrl',
      templateUrl: 'ark-time-picker/ark-time-picker.html',
      link: function link($scope) {
        $scope.$watchCollection('[timeData.hour, timeData.minute, timeData.noon, timeData.timeZone]', function () {
          $scope.time = $scope.militaryTime ? $scope.timeData.hour + '.' + $scope.timeData.minute : $scope.timeData.hour + '.' + $scope.timeData.minute + '.' + $scope.timeData.noon;
          if ($scope.timezoneMode) {
            $scope.time += $scope.timeData.timeZone;
            $scope.time = $scope.time.replace('GMT', '');
          }
        });
      }
    };
  }).directive('whilePressed', ['$parse', '$interval', function ($parse, $interval) {
    return {
      restrict: 'A',

      link: function link(scope, element, attrs) {
        var action = $parse(attrs.whilePressed),
            intervalPromise = null,
            TICK_LENGTH = 250;

        function tickAction() {
          action(scope);
        }

        function bindWhilePressed() {
          element.on('mousedown', beginAction);
        }

        function beginAction(e) {
          e.preventDefault();
          scope.$apply(action);
          intervalPromise = $interval(tickAction, TICK_LENGTH);
          element.on('mouseup', endAction);
          element.on('mouseleave', endAction);
        }

        function endAction() {
          $interval.cancel(intervalPromise);
          element.off('mouseup', endAction);
          element.off('mouseleave', endAction);
        }

        bindWhilePressed();
      }
    };
  }]);
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').component('arkToaster', {
    bindings: {
      config: '=?',
      toasterOptions: '=?', // Old syntax, for backwards compatibility
      locale: '<'
    },
    templateUrl: 'ark-toaster/ark-toaster.html',
    controller: 'ArkToasterCtrl'
  });
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').constant('arkToasterConfig', {
    limit: 0, // limits max number of toasts
    closeButton: true,
    newestOnTop: true,
    timeout: 5000, // Set 0 to make it sticky
    iconClasses: {
      error: 'icon-alert-circle',
      info: 'icon-alert-info',
      wait: 'icon-clock-b',
      success: 'icon-alert-checkmark',
      warning: 'icon-alert-triangle'
    },
    bodyOutputType: '', // Options: '', 'trustedHtml', 'template'
    bodyTemplate: 'toasterBodyTmpl.html'
  });
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').controller('ArkToasterCtrl', ['$scope', '$rootScope', '$timeout', 'arkToasterConfig', 'arkToaster', '$sce', function ($scope, $rootScope, $timeout, arkToasterConfig, arkToaster, $sce) {
    var ctrl = this;

    ctrl.toasters = [];

    ctrl.localeDefault = {
      'HIDE_ALL': 'Hide All',
      'NOTIFICATIONS': 'notifications'
    };

    ctrl.removeToast = function (id) {
      var i;
      for (i = 0; i < ctrl.toasters.length; i++) {
        if (ctrl.toasters[i].id === id) {
          break;
        }
      }
      ctrl.toasters.splice(i, 1);
    };

    ctrl.click = function (toaster) {
      if (toaster.clickHandler && angular.isFunction(toaster.clickHandler)) {
        if (toaster.clickHandler(toaster) === true) {
          // clickHandler must return a truthly value to remove toast
          ctrl.removeToast(toaster.id);
        }
      }
    };

    ctrl.clearAll = function () {
      arkToaster.clear();
    };

    ctrl.stopTimer = function (toast) {
      if (toast.timeout) {
        $timeout.cancel(toast.timeout);
        toast.timeout = null;
      }
    };

    ctrl.restartTimer = function (toast) {
      if (!toast.timeout) {
        ctrl._configureTimer(toast);
      }
    };

    ctrl._addToast = function (toast) {
      toast.typeIcon = ctrl.innerConfig.iconClasses[toast.type] || ctrl.innerConfig.iconClasses.info;

      // Set the toast.bodyOutputType to the default if it isn't set
      toast.bodyOutputType = toast.bodyOutputType || ctrl.innerConfig.bodyOutputType;
      switch (toast.bodyOutputType) {
        case 'trustedHtml':
          toast.html = $sce.trustAsHtml(toast.body);
          break;
        case 'template':
          // When template the body should contain the name of the template
          toast.bodyTemplate = toast.body || ctrl.innerConfig.bodyTemplate;
          break;
      }

      ctrl._configureTimer(toast);

      if (ctrl.innerConfig.newestOnTop === true) {
        ctrl.toasters.unshift(toast);
        if (ctrl.innerConfig.limit > 0 && ctrl.toasters.length > ctrl.innerConfig.limit) {
          ctrl.toasters.pop();
        }
      } else {
        ctrl.toasters.push(toast);
        if (ctrl.innerConfig.limit > 0 && ctrl.toasters.length > ctrl.innerConfig.limit) {
          ctrl.toasters.shift();
        }
      }
    };

    ctrl._configureTimer = function (toast) {
      var timeout = typeof toast.timeout === 'number' ? toast.timeout : ctrl.innerConfig.timeout;
      if (timeout > 0) {
        toast.timeout = $timeout(function () {
          ctrl.removeToast(toast.id);
        }, timeout);
      }
    };

    ctrl._updateLocale = function (locale, oldLocale) {
      if (locale !== oldLocale) {
        angular.extend(ctrl.i18n, ctrl.localeDefault, locale);
      }
    };

    ctrl.$onInit = function () {
      ctrl.innerConfig = angular.extend({}, arkToasterConfig, ctrl.config || ctrl.toasterOptions);
      // For backwards compatibility
      ctrl.innerConfig.closeButton = ctrl.innerConfig.closeButton || ctrl.config['close-button'];
      ctrl.innerConfig.timeout = ctrl.innerConfig.timeout || ctrl.config['time-out'];

      ctrl.i18n = angular.extend({}, ctrl.localeDefault, ctrl.locale);

      var deregisterNewToast = $rootScope.$on('arkToasterNewToast', function (event, toast) {
        ctrl._addToast(toast);
      });

      var deregisterClearToasts = $rootScope.$on('arkToasterClearToasts', function () {
        ctrl.toasters.splice(0, ctrl.toasters.length);
      });

      $scope.$on('$destroy', function () {
        // Cleaning up
        deregisterNewToast();
        deregisterClearToasts();
      });

      $scope.$watch(function () {
        return ctrl.locale;
      }, ctrl._updateLocale, true);
    };
  }]);
})(angular);

(function (angular) {
  'use strict';

  function ArkToasterService($rootScope) {
    // http://stackoverflow.com/questions/26501688/a-typescript-guid-class
    var Guid = function () {
      var Guid = {};
      // jscs: disable
      Guid.newGuid = function () {
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
          var r = Math.random() * 16 | 0,
              // jshint ignore:line
          v = c === 'x' ? r : r & 0x3 | 0x8; // jshint ignore:line
          return v.toString(16);
        });
      };
      // jscs: enable
      return Guid;
    }();

    this.pop = function (type, title, body, timeout, clickHandler) {
      var toast = {
        id: Guid.newGuid(),
        type: type,
        title: title,
        body: body,
        timeout: timeout,
        bodyOutputType: 'trustedHtml',
        clickHandler: clickHandler
      };
      $rootScope.$emit('arkToasterNewToast', toast);
    };

    this.clear = function () {
      $rootScope.$emit('arkToasterClearToasts');
    };
  }

  ArkToasterService.$inject = ['$rootScope'];

  angular.module('ark.core').service('arkToaster', ArkToasterService).service('toaster', ArkToasterService); // For backwards compatibility
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').directive('arkToolbarButton', function () {
    return {
      restrict: 'AE',
      scope: false,
      templateUrl: 'ark-toolbar/ark-toolbar-button.html'
    };
  });
})(angular);

(function (angular) {
  'use strict';

  angular.module('ark.core').directive('arkToolbar', function () {
    return {
      restrict: 'E',
      transclude: false,
      replace: false,
      scope: true,
      templateUrl: 'ark-toolbar/ark-toolbar.html',
      link: function link(scope, element, attributes) {
        var requestedToolbarType = attributes.config;
        scope.$watch(function () {
          return scope[requestedToolbarType];
        }, function () {
          scope.options = scope[requestedToolbarType];
        }, true);
      }
    };
  });
})(angular);

(function (angular) {
  'use strict';

  // TODO: Refactor to get rid of handlerArray and just use parse-handlers="eventArray"

  angular.module('ark.core').directive('parseHandlers', function () {
    return {
      restrict: 'A',
      scope: {
        handlerArray: '='
      },
      link: function link($scope, element) {
        angular.forEach($scope.handlerArray, function (obj) {
          if (obj.handler) {
            if (angular.isFunction(obj.handler)) {
              element.bind(obj.handlerName, obj.handler);
            } else {
              element.attr(obj.handlerName, obj.handler);
            }
          } else {
            element.attr(obj.handlerName, '');
          }
        });
      }
    };
  });
})(angular);

'use strict';
(function (d) {
  var b = '[data-toggle="dropdown"]', a = function (f) {
      var e = d(f).on('click.dropdown.data-api', this.toggle);
      d('html').on('click.dropdown.data-api', function () {
        if (!e.hasClass('dropdown-nested')) {
          e.parent().removeClass('open');
        }
      });
    };
  a.prototype = {
    constructor: a,
    toggle: function (j) {
      var i = d(this), h, f, g;
      if (i.is('.disabled, :disabled')) {
        return;
      }
      f = i.attr('data-target');
      if (!f) {
        f = i.attr('href');
        f = f && f.replace(/.*(?=#[^\s]*$)/, '');
      }
      h = d(f);
      if (!h.length) {
        h = i.parent();
      }
      g = h.hasClass('open');
      var isNested = i.hasClass('dropdown-nested');
      if (!g && isNested) {
        h.addClass('nesting');
      } else {
        c();
      }
      if (!g) {
        $('.dropdown.open.nesting').removeClass('open nesting');
        h.toggleClass('open');
      }
      return false;
    }
  };
  function c() {
    d(b).parent().removeClass('open');
  }
  d.fn.dropdown = function (e) {
    return this.each(function () {
      var g = d(this), f = g.data('dropdown');
      if (!f) {
        g.data('dropdown', f = new a(this));
      }
      if (typeof e === 'string') {
        f[e].call(g);
      }
    });
  };
  d.fn.dropdown.Constructor = a;
  d(function () {
    d('html').on('click.dropdown.data-api', c);
    d('body').on('click.dropdown', '.dropdown form', function (f) {
      f.stopPropagation();
    }).on('click.dropdown.data-api', b, a.prototype.toggle);
  });
}(window.jQuery));

angular.module('ark.core.templates', []).run(['$templateCache', function ($templateCache) {
  'use strict';

  $templateCache.put('ark-app-launcher/ark-app-launcher.html', "<nav class=\"ark-app-launcher navbar navbar-default\" role=\"navigation\"><div class=\"container-fluid\"><!-- Brand and toggle get grouped for better mobile display --><div id=\"nav_header\" class=\"navbar-header\"><div class=\"navbar-brand\"><span class=\"fonticon icon-special-g-brandmark\"></span> <span>{{ currentAppName }}</span></div></div><!-- Collect the nav links, forms, and other content for toggling --><div class=\"collapse navbar-collapse\"><ul class=\"nav navbar-nav navbar-right\"><!-- User Menu --><li class=\"dropdown\"><a href data-toggle=\"dropdown\">{{ user.name | truncate:false:25 }}</a><ul class=\"dropdown-menu\"><li ng-if=\"aboutApplication\"><a href ng-click=\"aboutApplication()\">{{ localization.localizedStrings.ABOUT }} {{ currentAppName }}</a><li ng-if=\"aboutApplication\" class=\"divider\"><li ng-repeat=\"item in usermenu\" ng-if=\"!item.disable\" ng-class=\"{divider: item.isDivider}\"><a ng-if=\"!item.isDivider && !item.customAction\" ng-href=\"{{ item.url }}\" ng-attr-target=\"{{ item.target }}\">{{ item.name }} </a><a ng-if=\"!item.isDivider && item.customAction\" href ng-click=\"customAction(item)\">{{ item.name }}</a></ul></li><!-- Localization --><li class=\"dropdown\" ng-if=\"localization\"><a href class=\"dropdown-toggle\" data-toggle=\"dropdown\"><div ng-class=\"localizationIcons[currentLanguage.id]\"></div>{{ currentLanguage.shortName }}</a><ul class=\"dropdown-menu\"><li ng-repeat=\"language in localization.languages\"><a href ng-click=\"changeLanguage(language.id)\"><div ng-class=\"localizationIcons[language.id]\"></div>{{ language.localizedName }}</a></ul></li><!-- Help --><li ng-if=\"helpmenu\"><a ng-href=\"{{ helpmenu.getUrl() }}\" ng-attr-target=\"{{ helpmenu.target }}\"><span ng-if=\"helpmenu.fonticon\" class=\"fonticon\" ng-class=\"helpmenu.fonticon\" ng-attr-title=\"{{ helpmenu.name }}\"></span></a></li><!-- App Launcher --><li class=\"app-launcher-dropdown dropdown\" ng-if=\"appLauncherEnable && appGroups\"><a href class=\"dropdown-toggle\" data-toggle=\"dropdown\"><span title=\"App Launcher\"><span class=\"fonticon icon-dialpad\"></span></span></a><ul class=\"dropdown-menu\"><li ng-repeat-start=\"(name, apps) in appGroups\" class=\"title\">{{ name }}<li ng-repeat=\"app in apps\"><a href ng-href=\"{{ app.links[0].url }}\" target=\"_blank\"><img ng-src=\"{{ baseUrlAssets }}{{ app.image32 }}\"> <span>{{ app.name }}</span></a><li ng-repeat-end class=\"divider\"><li ng-if=\"false\"><a href><span class=\"fonticon icon-dialpad\" style=\"font-size: 24px\"></span> {{ localization.localizedStrings.ALL_APPS }}</a></ul></ul></div><!-- /.navbar-collapse --></div><!-- /.container-fluid --></nav>");

  $templateCache.put('ark-datepicker/ark-datepicker-popup-wrap.html', "<ul class=\"dropdown-menu ark-datepicker-wrap\" ng-style=\"{display: (isOpen && 'block') || 'none', top: position.top+'px', left: position.left+'px'}\"><li ng-transclude><li ng-if=\"showButtonBar\" class=\"button-bar\"><span class=\"btn-group\"><button type=\"button\" class=\"btn btn-sm btn-info\" ng-click=\"select('today')\">{{ getText('current') }}</button> <button type=\"button\" class=\"btn btn-sm btn-danger\" ng-click=\"select(null)\">{{ getText('clear') }}</button> </span><button type=\"button\" class=\"btn btn-sm btn-default pull-right\" ng-click=\"$parent.isOpen = false\">{{ getText('close') }}</button></ul>");

  $templateCache.put('ark-datepicker/ark-datepicker.html', "<div ng-switch=\"datepickerMode\" class=\"ark-datepicker\" ng-class=\"{disabled: ngDisabled}\"><ark-daypicker ng-switch-when=\"day\"></ark-daypicker><ark-monthpicker ng-switch-when=\"month\"></ark-monthpicker><ark-yearpicker ng-switch-when=\"year\"></ark-yearpicker></div>");

  $templateCache.put('ark-datepicker/ark-daypicker.html', "<div class=\"day-view text-center\"><div class=\"month-index\"><table><thead><tr><th><button type=\"button\" class=\"btn btn-default btn-sm pull-left\" ng-click=\"move(-1)\"><i class=\"fonticon icon-chevron-left\"></i></button><th colspan=\"{{ 5 + showWeeks }}\"><button type=\"button\" class=\"btn btn-default btn-sm btn-block\" ng-click=\"toggleMode()\"><strong>{{ title }}</strong></button><th><button type=\"button\" class=\"btn btn-default btn-sm pull-right\" ng-click=\"move(1)\"><i class=\"fonticon icon-chevron-right\"></i></button></thead></table></div><div class=\"day-table\"><table><thead><tr class=\"ark-datepicker-labels\"><th ng-show=\"showWeeks\" class=\"text-center\"><th ng-repeat=\"label in labels track by $index\" class=\"text-center day-label\"><small>{{ label }}</small><tbody><tr ng-repeat=\"row in rows track by $index\"><td ng-show=\"showWeeks\" class=\"text-center\"><small><em>{{ weekNumbers[$index] }}</em></small><td ng-repeat=\"dt in row track by dt.date\" class=\"text-center\"><button type=\"button\" style=\"width:100%\" class=\"btn btn-default btn-sm\" ng-class=\"{'btn-info': dt.selected}\" ng-click=\"select(dt.date)\" ng-disabled=\"dt.disabled\"><span ng-class=\"{'text-muted': dt.secondary, 'text-info': dt.current}\">{{ dt.label }}</span></button></table></div><div class=\"ark-timepicker calendar-timepicker\" ng-if=\"timepickerEnabled\"><div class=\"timepicker-content\" ng-show=\"!timeZoneShow\"><div class=\"col-container first\"><div class=\"icon-iw-circle-no-chevron-up arrow\" while-pressed=\"addHour()\"></div><div class=\"dropdown open\"><input type=\"text\" maxlength=\"2\" ng-model=\"timeData.hour\" ng-click=\"showHour()\" ng-blur=\"validateHour()\"><ul ng-show=\"showHourList\" class=\"dropdown-menu\"><li ng-repeat=\"list in hourList\"><a href ng-mousedown=\"selectHour(list)\" ng-class=\"{selected: list === hour}\">{{ list }}</a></ul></div><div class=\"icon-iw-circle-no-chevron-down arrow\" while-pressed=\"minusHour()\"></div></div><div class=\"col-container column\"><b>:</b></div><div class=\"col-container\"><div class=\"icon-iw-circle-no-chevron-up arrow\" while-pressed=\"addMinute()\"></div><div class=\"dropdown open\"><input type=\"text\" maxlength=\"2\" ng-model=\"timeData.minute\" ng-click=\"showMinute()\" ng-blur=\"validateMinute()\"><ul ng-show=\"showMinuteList\" class=\"dropdown-menu\"><li ng-repeat=\"list in minuteList\"><a href ng-mousedown=\"selectMinute(list)\" ng-class=\"{selected: list===minute}\">{{ list }}</a></ul></div><div class=\"icon-iw-circle-no-chevron-down arrow\" while-pressed=\"minusMinute()\"></div></div><div class=\"col-container last\"><div class=\"icon-iw-circle-no-chevron-up arrow\" ng-click=\"changeNoon()\"></div><input type=\"text\" maxlength=\"2\" ng-model=\"timeData.noon\" ng-blur=\"validateNoon()\" readonly><div class=\"icon-iw-circle-no-chevron-down arrow\" ng-click=\"changeNoon()\"></div></div><div class=\"col-container last timepicker-button\" ng-if=\"timezoneEnabled\" ng-click=\"toggleTimeZone()\"><span class=\"fonticon icon-clock-timezone\"></span></div></div><div class=\"timepicker-content\" ng-if=\"timezoneEnabled\" ng-show=\"timeZoneShow\"><div class=\"col-container\"><div class=\"icon-iw-circle-no-chevron-up arrow timezone\" ng-click=\"addTimeZone()\"></div><div class=\"dropdown open\"><input type=\"text\" class=\"timezone\" maxlength=\"9\" ng-model=\"timeData.timeZone\" ng-click=\"showTimeZone()\" ng-blur=\"validateTimeZone()\" readonly><ul ng-show=\"showTimeZoneList\" class=\"dropdown-menu timezone\"><li ng-repeat=\"list in timeZoneList\"><a href ng-mousedown=\"selectTimeZone(list, $index)\" class=\"timezone\" ng-class=\"{selected: list === timeZone}\">{{ list }}</a></ul></div><div class=\"icon-iw-circle-no-chevron-down arrow timezone\" ng-click=\"minusTimeZone()\"></div></div><div class=\"col-container last timepicker-button\" ng-click=\"toggleTimeZone()\"><span class=\"fonticon icon-clock\"></span></div></div></div></div>");

  $templateCache.put('ark-datepicker/ark-monthpicker.html', "<table class=\"month-view\"><thead><tr><th><button type=\"button\" class=\"btn btn-default btn-sm pull-left\" ng-click=\"move(-1)\"><i class=\"icon-chevron-left\"></i></button><th><button type=\"button\" class=\"btn btn-default btn-sm btn-block\" ng-click=\"toggleMode()\"><strong>{{title}}</strong></button><th><button type=\"button\" class=\"btn btn-default btn-sm pull-right\" ng-click=\"move(1)\"><i class=\"icon-chevron-right\"></i></button><tbody><tr ng-repeat=\"row in rows track by $index\"><td ng-repeat=\"dt in row track by dt.date\" class=\"text-center\"><button type=\"button\" style=\"width:100%\" class=\"btn btn-default\" ng-class=\"{'btn-info': dt.selected}\" ng-click=\"select(dt.date)\" ng-disabled=\"dt.disabled\"><span ng-class=\"{'text-info': dt.current}\">{{dt.label}}</span></button></table>");

  $templateCache.put('ark-datepicker/ark-yearpicker.html', "<table class=\"year-view\"><thead><tr><th><button type=\"button\" class=\"btn btn-default btn-sm pull-left\" ng-click=\"move(-1)\"><i class=\"icon-chevron-left\"></i></button><th colspan=\"3\"><button type=\"button\" class=\"btn btn-default btn-sm btn-block\" ng-click=\"toggleMode()\"><strong>{{title}}</strong></button><th><button type=\"button\" class=\"btn btn-default btn-sm pull-right\" ng-click=\"move(1)\"><i class=\"icon-chevron-right\"></i></button><tbody><tr ng-repeat=\"row in rows track by $index\"><td ng-repeat=\"dt in row track by dt.date\" class=\"text-center\"><button type=\"button\" style=\"width:100%\" class=\"btn btn-default\" ng-class=\"{'btn-info': dt.selected}\" ng-click=\"select(dt.date)\" ng-disabled=\"dt.disabled\"><span ng-class=\"{'text-info': dt.current}\">{{dt.label}}</span></button></table>");

  $templateCache.put('ark-expandable-panel/ark-expandable-panel.html', "<div class=\"ark-expandable-panel\" ng-class=\"'ark-expandable-panel-' + $ctrl.side\"><div class=\"ark-expandable-panel-container\" ng-show=\"$ctrl.expanded\"><div class=\"ark-expandable-panel-container-inner\"><ng-transclude></ng-transclude></div></div><div class=\"ark-expandable-panel-widget\" ng-click=\"$ctrl.togglePanel()\"><span class=\"fonticon\" ng-class=\"'icon-control-skip-' + ($ctrl.expanded ? $ctrl.side : $ctrl.otherSide($ctrl.side))\"></span></div><div style=\"clear:both\"></div>");

  $templateCache.put('ark-filter-bar/ark-filter-bar.html', "<div class=\"ark-filter-bar\" ng-class=\"{disabled: ngDisabled}\"><div class=\"input-container\"><input type=\"text\" class=\"form-control filter-search-box\" ng-model=\"searchText\" ng-class=\"{'filter-box-show-icon': showSearchIcon}\" ng-blur=\"resetItems()\" ng-attr-placeholder=\"{{ ctrl.i18n.SEARCH }}\"> <span class=\"icon-search search-box-icon\" ng-if=\"showSearchIcon\"></span> <span class=\"icon-close search-box-cancel\" ng-show=\"hasContent\" ng-click=\"clearInputText()\"></span><div class=\"spinner-container input-spinner\" ng-show=\"isSearching\"><div class=\"spin-circle\"></div><div class=\"spin-inner-circle\"></div></div></div><div ng-if=\"displayDropdown\" class=\"dropdown open\"><ul class=\"dropdown-menu filter-dropdown\" aria-labelledby=\"filterDropdown\"><li ng-repeat=\"item in items\" ng-init=\"breakIndex = item.toLowerCase().indexOf(prevSearchText.toLowerCase())\" ng-class=\"{ active: isActive($index) }\" ng-mouseenter=\"selectActive($index)\" ng-mousedown=\"selectMatch($index)\"><a class=\"items-found\" ng-if=\"item.toLowerCase().indexOf(prevSearchText.toLowerCase()) == -1\">{{ item }} </a><a class=\"items-found\" ng-if=\"item.toLowerCase().indexOf(prevSearchText.toLowerCase()) != -1\">{{ item.substring(0, breakIndex) }}<b>{{ item.substring(breakIndex, (breakIndex + prevSearchText.length)) }}</b>{{ item.substring((breakIndex + prevSearchText.length)) }}</a><li ng-if=\"items.length === 0\"><a class=\"not-found\">{{ ctrl.i18n.SEARCH_FOR }} \"<b>{{ prevSearchText }}</b>\" {{ ctrl.i18n.NOT_FOUND }}</a></ul></div></div>");

  $templateCache.put('ark-footer/ark-footer.html', "<footer class=\"ark-footer\"><div class=\"rsection\"><img class=\"logo-img\" ng-src=\"{{ ::$ctrl.tenantLogoLink }}\" alt=\"\"><div class=\"powered-by\" ng-if=\"::(!$ctrl.hidePoweredBy)\" ng-bind=\"$ctrl.i18n.POWERED_BY\"></div><div class=\"version\" ng-if=\"::$ctrl.appVersion\" ng-bind=\"::$ctrl.appVersion\"></div></div><div class=\"links\" ng-if=\"::($ctrl.termsAndConditions || $ctrl.privacyPolicy)\"><a ng-if=\"::$ctrl.termsAndConditions\" class=\"terms-of-use\" target=\"_blank\" href ng-href=\"{{ ::$ctrl.termsAndConditions }}\" ng-bind=\"$ctrl.i18n.TERMS_OF_USE\"></a> <span ng-if=\"::($ctrl.termsAndConditions && $ctrl.privacyPolicy)\">/ </span><a ng-if=\"::$ctrl.privacyPolicy\" class=\"privacy-policy\" target=\"_blank\" href ng-href=\"{{ ::$ctrl.privacyPolicy }}\" ng-bind=\"$ctrl.i18n.PRIVACY_POLICY\"></a></div><div class=\"logo\" ng-if=\"::($ctrl.genesysLogoLink && !($ctrl.termsAndConditions || privacyPolicy))\"><img ng-src=\"{{ ::$ctrl.genesysLogoLink }}\" alt=\"Genesys\"></div><div class=\"copyright\">&copy; {{ ::$ctrl.currentYear }} {{ $ctrl.i18n.COPYRIGHT }}</div></footer>");

  $templateCache.put('ark-login/ark-login-wrapper.html', "<div class=\"ark-login ark-login-deprecated\" ng-class=\"::$ctrl.cssClass\"><div class=\"wrapper\"><div class=\"branding\" ng-if=\"::$ctrl.logoUrl\"><img ng-src=\"{{ ::$ctrl.logoUrl }}\" alt=\"Genesys\"></div><div class=\"well\"><form role=\"form\" ng-if=\"!$ctrl.isLoading\"><div class=\"form-group\"><h2>{{ $ctrl.title }}</h2><div ng-transclude></div></div></form><div class=\"loading-container\" ng-if=\"$ctrl.isLoading\"><h2>{{ ::$ctrl.loadingTitle }}</h2><div class=\"spinner-container\"><div class=\"spin-circle\"></div><div class=\"spin-inner-circle\"></div></div></div></div></div></div>");

  $templateCache.put('ark-login/ark-login.html', "<ark-login-wrapper is-loading=\"$ctrl.isLoading\" logo-url=\"{{ $ctrl.logoUrl }}\" title=\"{{ $ctrl.loginForm.title }}\" loading-title=\"{{ $ctrl.loginForm.loading }}\"><div class=\"ark-login-fields\" ng-class=\"{'has-error': $ctrl.errorMessage}\"><input type=\"text\" class=\"form-control ark-login-username\" ng-model=\"$ctrl.username\" ng-attr-placeholder=\"{{ $ctrl.loginForm.username }}\"> <input type=\"password\" class=\"form-control ark-login-password\" autocomplete=\"off\" ng-model=\"$ctrl.password\" ng-attr-placeholder=\"{{ $ctrl.loginForm.password }}\"></div><div class=\"btn-group bootstrap-select login-select\" ng-if=\"$ctrl.showLanguageBar\"><button type=\"button\" class=\"btn btn-default dropdown-toggle selectpicker\" ng-model=\"$ctrl.language\" ark-select ark-options=\"item.title for item in $ctrl.languageMenu\"></button></div><div class=\"error-container\" ng-if=\"$ctrl.errorMessage\"><span class=\"icon-alert-circle\"></span><div class=\"ark-login-error-messages\">{{ $ctrl.errorMessage }}</div></div><div class=\"ark-login-button\"><button type=\"submit\" class=\"btn btn-primary btn-block\" ng-click=\"$ctrl.login()\">{{ $ctrl.loginForm.login }}</button></div><div class=\"ark-login-forgot-password\" ng-if=\"$ctrl.forgotPassword\"><a href ng-click=\"$ctrl.forgotPasswordFn()\">{{ $ctrl.loginForm.forgotPassword }}</a></div><div class=\"remote-message\" ng-if=\"::$ctrl.remoteMessageUrl\">{{ ::$ctrl.remoteMessage }}</div></ark-login-wrapper>");

  $templateCache.put('ark-navbar/ark-navbar.html', "<nav class=\"ark-navbar navbar navbar-default\" role=\"navigation\"><div class=\"container-fluid\"><!-- Brand and toggle get grouped for better mobile display --><div ng-if=\"navigationJSON.header\" ng-attr-id=\"{{ navigationJSON.header.id }}\" class=\"navbar-header ark-dropdown dropdown\" ng-mouseover=\"resetAutoClose(navigationJSON.header.id, $event)\" ng-class=\"{'active-dropdown': matchRoute(navigationJSON.header.route).module, 'onhover': navigationJSON.header.allowhover && navigationJSON.header.children}\"><a ng-if=\"navigationJSON.header && navigationJSON.header.route\" ng-href=\"{{ navigationJSON.header.route }}\" class=\"navbar-brand\"><span ng-if=\"navigationJSON.header.fonticon\" class=\"fonticon\" ng-class=\"navigationJSON.header.fonticon\"></span> <span class=\"navbar-appname\">{{ i18n ? i18n[navigationJSON.header.id] : '' }}</span> </a><a ng-if=\"navigationJSON.header && !navigationJSON.header.route\" class=\"navbar-brand ark-dropdown-toggle\"><span ng-if=\"navigationJSON.header.fonticon\" class=\"fonticon\" ng-class=\"navigationJSON.header.fonticon\"></span> <span class=\"navbar-appname\">{{ i18n ? i18n[navigationJSON.header.id] : '' }}</span></a><ul ng-if=\"navigationJSON.header.children\" class=\"dropdown-menu\" role=\"menu\" aria-labelledby=\"{{ navigationJSON.header.id }}\" ng-class=\"{'autoclose': navigationJSON.header.allowhover && navigationJSON.header.children}\"><li ng-repeat=\"subItem in navigationJSON.header.children\" ng-click=\"autoClose($event, subItem.children)\" ng-attr-id=\"{{ subItem.id }}\" ng-class=\"{'ark-dropdown dropdown': subItem.children, 'ark-hover': subItem.submenuHover, 'ark-focus': !subItem.submenuHover, 'active': matchRoute(subItem.route).subModule, 'subdivider': subItem.subdivider }\" tabindex=\"-1\"><a ng-if=\"subItem.type == 'sub-item' && subItem.children\" class=\"dropdown-nested\">{{ i18n ? i18n[subItem.id] : '' }}</a> <a ng-if=\"subItem.type == 'sub-item' && !subItem.children\" ng-href=\"{{ subItem.route }}\">{{ i18n ? i18n[subItem.id] : '' }}</a> <span ng-if=\"subItem.type == 'sub-group'\">{{ i18n ? i18n[subItem.id] : '' }}</span><ul ng-if=\"subItem.children\" class=\"dropdown-menu sub-menu\"><li ng-repeat=\"subSubItem in subItem.children\" ng-attr-id=\"{{ subSubItem.id }}\" ng-class=\"{divider: subSubItem.type == 'sub-group', 'active': matchRoute(subSubItem.route).subSubModule}\"><a ng-if=\"subSubItem.type == 'sub-item'\" ng-href=\"{{ subSubItem.route }}\">{{ i18n ? i18n[subSubItem.id] : '' }}</a> <span ng-if=\"subSubItem.type == 'sub-group'\">{{ i18n ? i18n[subSubItem.id] : '' }}</span></ul></ul><div class=\"vertical-divider\"></div><button type=\"button\" class=\"navbar-toggle\" ng-init=\"isCollapsed = true\" ng-click=\"toggleCollapse()\"><span class=\"sr-only\">Toggle navigation</span> <span class=\"icon-menu-hamburger\"></span> <span class=\"navbar-dashboard-label\">Dashboard</span></button></div><!-- Collect the nav links, forms, and other content for toggling --><div class=\"navbar-collapse\" ng-class=\"{collapse: isCollapsed}\"><!-- left --><ul class=\"nav navbar-nav\"><li ng-repeat=\"item in navigationJSON.left\" ng-attr-id=\"{{ item.id }}\" class=\"ark-dropdown dropdown\" ng-mouseover=\"resetAutoClose(item.id, $event)\" ng-class=\"{'active-dropdown': matchRoute(item.route).module, 'onhover': navigationJSON.header.allowhover && item.children}\"><a ng-if=\"navigationJSON.header.allowhover && item.children && !stopClose\" ng-href=\"{{item.route}}\"><span ng-if=\"!item.fonticon\">{{ i18n ? i18n[item.id] : '' }} <b ng-if=\"item.caret == true\" class=\"caret\"></b></span> <span ng-if=\"item.fonticon\" ng-attr-title=\"{{ i18n ? i18n[item.id] : '' }}\"><span class=\"fonticon\" ng-class=\"item.fonticon\"></span> <b ng-if=\"item.caret == true\" class=\"caret\"></b> </span></a><a ng-if=\"!navigationJSON.header.allowhover && item.children && !stopClose\" ng-href=\"#\" class=\"ark-dropdown-toggle\"><span ng-if=\"!item.fonticon\">{{ i18n ? i18n[item.id] : '' }} <b ng-if=\"item.caret == true\" class=\"caret\"></b></span> <span ng-if=\"item.fonticon\" ng-attr-title=\"{{ i18n ? i18n[item.id] : '' }}\"><span class=\"fonticon\" ng-class=\"item.fonticon\"></span> <b ng-if=\"item.caret == true\" class=\"caret\"></b> </span></a><a ng-if=\"!item.children || stopClose\" ng-href=\"{{ item.route }}\"><span ng-if=\"!item.fonticon\">{{ i18n ? i18n[item.id] : '' }} <b ng-if=\"item.caret == true\" class=\"caret\"></b></span> <span ng-if=\"item.fonticon\" ng-attr-title=\"{{ i18n ? i18n[item.id] : '' }}\"><span class=\"fonticon\" ng-class=\"item.fonticon\"></span> <b ng-if=\"item.caret == true\" class=\"caret\"></b></span></a><ul ng-if=\"item.children\" class=\"dropdown-menu\" role=\"menu\" aria-labelledby=\"{{ item.id }}\" ng-class=\"{'autoclose': navigationJSON.header.allowhover && item.children}\"><li ng-repeat=\"subItem in item.children\" ng-click=\"autoClose($event, subItem.children)\" ng-attr-id=\"{{ subItem.id }}\" ng-class=\"{'ark-dropdown dropdown': subItem.children, 'ark-hover': subItem.submenuHover, 'ark-focus': !subItem.submenuHover, 'active': matchRoute(subItem.route).subModule, 'subdivider': subItem.subdivider }\" tabindex=\"-1\"><a ng-if=\"subItem.type == 'sub-item' && subItem.children\" class=\"dropdown-nested\">{{ i18n ? i18n[subItem.id] : '' }}</a> <a ng-if=\"subItem.type == 'sub-item' && !subItem.children\" ng-href=\"{{ subItem.route }}\">{{ i18n ? i18n[subItem.id] : '' }}</a> <span ng-if=\"subItem.type == 'sub-group'\">{{ i18n ? i18n[subItem.id] : '' }}</span><ul ng-if=\"subItem.children\" class=\"dropdown-menu sub-menu\"><li ng-repeat=\"subSubItem in subItem.children\" ng-attr-id=\"{{ subSubItem.id }}\" ng-class=\"{divider: subSubItem.type == 'sub-group', 'active': matchRoute(subSubItem.route).subSubModule}\"><a ng-if=\"subSubItem.type == 'sub-item'\" ng-href=\"{{ subSubItem.route }}\">{{ i18n ? i18n[subSubItem.id] : '' }}</a> <span ng-if=\"subSubItem.type == 'sub-group'\">{{ i18n ? i18n[subSubItem.id] : '' }}</span></ul></ul></ul><!-- right --><ul class=\"nav navbar-nav navbar-right\"><li ng-repeat=\"item in navigationJSON.right\" ng-attr-id=\"{{ item.id }}\" class=\"ark-dropdown dropdown\" ng-mouseover=\"resetAutoClose(item.id, $event)\" ng-class=\"{'active-dropdown': matchRoute(item.route).module, 'onhover': navigationJSON.header.allowhover && item.children}\"><a ng-if=\"item.route && item.type !== 'search-item' && item.children && !stopClose && navigationJSON.header.allowhover \" ng-attr-id=\"{{ item.id }}\" ng-href=\"{{item.route}}\" role=\"button\"><span ng-if=\"!item.fonticon\">{{ i18n ? i18n[item.id] : '' }} <b ng-if=\"item.caret == true\" class=\"caret\"></b></span> <span ng-if=\"item.fonticon\" ng-attr-title=\"{{ i18n ? i18n[item.id] :'' }}\"><span class=\"fonticon\" ng-class=\"item.fonticon\"></span> <b ng-if=\"item.caret == true\" class=\"caret\"></b> </span></a><a ng-if=\"item.route && item.type !== 'search-item' && item.children && !stopClose && !navigationJSON.header.allowhover \" ng-attr-id=\"{{ item.id }}\" ng-href=\"#\" class=\"ark-dropdown-toggle\" role=\"button\"><span ng-if=\"!item.fonticon\">{{ i18n ? i18n[item.id] : '' }} <b ng-if=\"item.caret == true\" class=\"caret\"></b></span> <span ng-if=\"item.fonticon\" ng-attr-title=\"{{ i18n ? i18n[item.id] :'' }}\"><span class=\"fonticon\" ng-class=\"item.fonticon\"></span> <b ng-if=\"item.caret == true\" class=\"caret\"></b> </span></a><a ng-if=\"item.route && item.type !== 'search-item' && (!item.children || stopClose)\" ng-href=\"{{ item.route }}\"><span ng-if=\"!item.fonticon\">{{ i18n ? i18n[item.id] : '' }} <b ng-if=\"item.caret == true\" class=\"caret\"></b></span> <span ng-if=\"item.fonticon\" ng-attr-title=\"{{ i18n ? i18n[item.id] :'' }}\"><span class=\"fonticon\" ng-class=\"item.fonticon\"></span> <b ng-if=\"item.caret == true\" class=\"caret\"></b> </span></a><a ng-if=\"!item.route && item.type === 'search-item' && !stopClose\" class=\"ark-dropdown-toggle\" role=\"button\"><span ng-if=\"!item.fonticon\">{{ i18n ? i18n[item.id] : '' }} <b ng-if=\"item.caret == true\" class=\"caret\"></b></span> <span ng-if=\"item.fonticon\" ng-attr-title=\"{{ i18n ? i18n[item.id] : '' }}\"><span class=\"fonticon\" ng-class=\"item.fonticon\"></span> <b ng-if=\"item.caret == true\" class=\"caret\"></b> </span></a><a ng-if=\"!item.route && item.type === 'search-item' && stopClose\" role=\"button\"><span ng-if=\"!item.fonticon\">{{ i18n ? i18n[item.id] : '' }} <b ng-if=\"item.caret == true\" class=\"caret\"></b></span> <span ng-if=\"item.fonticon\" ng-attr-title=\"{{ i18n ? i18n[item.id] : '' }}\"><span class=\"fonticon\" ng-class=\"item.fonticon\"></span> <b ng-if=\"item.caret == true\" class=\"caret\"></b></span></a><a ng-if=\"item.type === 'contextual-help'\" role=\"button\" ng-click=\"openCloseContextualHelp()\"><span ng-if=\"item.fonticon\" ng-attr-title=\"{{ i18n ? i18n[item.id] : '' }}\"><span class=\"fonticon\" ng-class=\"item.fonticon\"></span> </span> </a><ul ng-if=\"item.children\" class=\"dropdown-menu\" role=\"menu\" aria-labelledby=\"{{ item.id }}\" ng-class=\"{'autoclose': navigationJSON.header.allowhover && item.children}\"><li ng-repeat=\"subItem in item.children\" ng-click=\"autoClose($event, subItem.children)\" ng-attr-id=\"{{ subItem.id }}\" ng-class=\"{'ark-dropdown dropdown': subItem.children, 'ark-hover': subItem.submenuHover, 'ark-focus': !subItem.submenuHover, 'active': matchRoute(subItem.route).subModule, 'subdivider': subItem.subdivider }\" tabindex=\"-1\"><a ng-if=\"subItem.type == 'sub-item' && subItem.children\" class=\"dropdown-nested\">{{ i18n ? i18n[subItem.id] : '' }}</a> <a ng-if=\"subItem.type == 'sub-item' && !subItem.children\" ng-href=\"{{ subItem.route }}\">{{ i18n ? i18n[subItem.id] : '' }}</a> <span ng-if=\"subItem.type == 'sub-group'\">{{ i18n ? i18n[subItem.id] : '' }}</span><ul ng-if=\"subItem.children\" class=\"dropdown-menu sub-menu open-left\" ng-click=\"autoCloseSub($event)\"><li ng-repeat=\"subSubItem in subItem.children\" ng-attr-id=\"{{ subSubItem.id }}\" ng-class=\"{divider: subSubItem.type == 'sub-group', 'active': matchRoute(subSubItem.route).subSubModule}\"><a ng-if=\"subSubItem.type == 'sub-item'\" ng-href=\"{{ subSubItem.route }}\">{{ i18n ? i18n[subSubItem.id] : '' }}</a> <span ng-if=\"subSubItem.type == 'sub-group'\">{{ i18n ? i18n[subSubItem.id] : '' }}</span></ul></ul><ul ng-if=\"item.type === 'search-item'\" class=\"dropdown-menu searchbar\"><li><div class=\"ark-filter-bar\"><div class=\"input-container\" stop-close><input type=\"text\" ng-model=\"searchbar.searchText\" class=\"form-control filter-search-box\" placeholder=\"Search\"> <span class=\"icon-search search-box-icon\"></span> <span class=\"icon-close search-box-cancel\" ng-show=\"hasContent\" ng-click=\"clearInputText()\"></span><div class=\"spinner-container input-spinner\" ng-show=\"isSearching\"><div class=\"spin-circle\"></div><div class=\"spin-inner-circle\"></div></div></div><div ng-if=\"displayDropdown\" class=\"dropdown open\"><ul class=\"dropdown-menu filter-dropdown search-result\" aria-labelledby=\"filterDropdown\"><li ng-repeat=\"item in items\" ng-init=\"breakIndex = item.toLowerCase().indexOf(prevSearchText.toLowerCase())\"><a class=\"items-found\" ng-click=\"clickItem(item)\">{{ item.substring(0, breakIndex) }}<b>{{ item.substring(breakIndex, (breakIndex + prevSearchText.length)) }}</b>{{ item.substring((breakIndex + prevSearchText.length)) }}</a><li ng-if=\"items.length === 0\"><a class=\"not-found\">Search for \"<b>{{ prevSearchText }}</b>\" not found</a></ul></div></div></ul></ul></div><!-- /.navbar-collapse --></div><!-- /.container-fluid --></nav>");

  $templateCache.put('ark-nested-search/ark-nested-search.html', "<span class=\"ark-nested-search\" ng-class=\"{disabled: ngDisabled}\"><span class=\"searchContainer\" style=\"width: calc(100% - 72px)\"><span class=\"fonticon icon-search\"></span> <input ng-keydown=\"searchKeyPress($event)\" placeholder=\"{{placeholder}}\" class=\"form-control nestedSearchInput\" ng-model=\"search.searchValue\"> <span ng-if=\"!delayPromise\"><span ng-if=\"search.searchValue && searchResults.length\" class=\"searchcount\">{{ currSearchIndex + 1 }} of {{ searchResults.length }} </span><span ng-if=\"search.searchValue && !searchResults.length\" class=\"searchcount\">0 results </span><span ng-show=\"search.searchValue && !delayPromise\" class=\"icon-close search-box-cancel close-span ark-fonticon\" ng-click=\"search.searchValue = ''\"></span> </span><span ng-if=\"delayPromise && config.delay\" class=\"searchcount wait\">waiting...</span> </span><span><button ng-disabled=\"!searchResults.length\" ng-click=\"switchPrimaryResult('next')\" type=\"button\" class=\"nextResult btn btn-default fonticon icon-iw-circle-no-chevron-down\" style=\"padding: 2px 12px\"></button><!--\n" + "    --><button ng-disabled=\"!searchResults.length\" ng-click=\"switchPrimaryResult('previous')\" type=\"button\" class=\"previousResult btn btn-default fonticon icon-iw-circle-no-chevron-up\" style=\"padding: 2px 12px; margin-left:1px\"></button> <button ng-show=\"showClearSearch\" ng-click=\"search.searchValue = ''\" type=\"button\" class=\"btn btn-default clear-search-button\">Clear Search</button></span></span>");

  $templateCache.put('ark-nested-tree/ark-nested-tree.html', "<div class=\"ark-nested-tree panel panel-default\" ng-class=\"{ 'no-border': !showBorder }\" filter-treeview=\"true\" tree-id=\"myTree\" tree-model=\"model\" node-id=\"id\" node-label=\"label\" node-children=\"items\" tree-name=\"{{ treeName }}\" level-depth=\"0\" node-unselectable=\"unselectable\" node-html-content=\"htmlContent\" max-child-height=\"maxHeight\"></div>");

  $templateCache.put('ark-select/ark-select.html', "<div class=\"ark-select-wrapper bootstrap-select dropdown-menu\" ng-class=\"{ scrollable: $matches.length > 10 }\"><ul tabindex=\"-1\" class=\"inner select dropdown-menu selectpicker\" ng-show=\"$isVisible()\" role=\"select\" style=\"display:block\"><li role=\"presentation\" ng-if=\"$enableSelectAll\" ng-class=\"$isAllSelected() ? 'selected' : $isMaxSelected() ? 'max-selected' : ''\"><!-- ng-class=\"{active: $isActive($index)}\" --> <a role=\"menuitem\" tabindex=\"-1\" ng-attr-id=\"{{ $parentId + '-' + (match.value.name || match.value.id || 'select-default-id-' + match.label) }}\" ng-checked=\"$isAllSelected\" ng-attr-title=\"{{ $allText }}\" ng-click=\"$selectAll($index, $event)\"><span>{{ $allText }}</span> <i ng-class=\"$iconCheckmark\" class=\"pull-right\" ng-if=\"$isMultiple && $isAllSelected\"><!-- --></i></a><li ng-if=\"$enableSelectAll\" role=\"separator\" class=\"divider\"><li role=\"presentation\" ng-repeat=\"match in $matches\" ng-class=\"$isActive($index) ? 'selected' : $isMaxSelected() ? 'max-selected' : ''\"><!-- ng-class=\"{active: $isActive($index)}\" --> <a role=\"menuitem\" tabindex=\"-1\" ng-attr-id=\"{{ $parentId + '-' + (match.value.name || match.value.id || 'select-default-id-' + match.label) }}\" ng-checked=\"$isActive($index)\" ng-attr-title=\"{{ match.label }}\" ng-click=\"$select($index, $event)\"><span ng-bind=\"match.label\"></span> <i ng-class=\"$iconCheckmark\" class=\"pull-right\" ng-if=\"$isMultiple && $isActive($index)\"><!-- --></i></a></ul></div>");

  $templateCache.put('ark-select/tooltip.tpl.html', "<div class=\"tooltip in\" ng-show=\"title\"><div class=\"tooltip-arrow\"></div><div class=\"tooltip-inner\" ng-bind=\"title\"></div></div>");

  $templateCache.put('ark-sidebar/ark-sidebar.html', "<div class=\"ark-sidebar\"><div class=\"ark-sidebar-container\" ng-show=\"showSidebar\" ng-class=\"{'ark-sidebar-shadow': showShadow}\" ng-include=\"template\"></div></div>");

  $templateCache.put('ark-simple-tabs/ark-side-tabs.html', "<div class=\"side-tabs-container\"><ul class=\"nav nav-side-tabs\"><li ng-repeat=\"tab in tabs\" ng-class=\"{ active: $index === selectedItemIndex }\" ng-click=\"ctrl.setActive($index)\"><a ng-attr-title=\"{{ iconsOnly ? tab.title : '' }}\" href><span class=\"icon\" ng-class=\"tab.icon\" ng-if=\"tab.icon\"></span> <span ng-if=\"!iconsOnly\" ng-bind=\"tab.title\"></span></a></ul><div class=\"tabs-contents\"><div ng-if=\"!switchReload\"><div ng-include=\"tab.templateUrl\" ng-repeat=\"tab in tabs\" ng-show=\"$index === selectedItemIndex\"></div></div><div ng-if=\"switchReload\"><div ng-include=\"selectedTemplate\"></div></div></div></div>");

  $templateCache.put('ark-simple-tabs/ark-simple-tabs.html', "<div class=\"simple-tabs-container\"><ul class=\"nav nav-tabs\"><li ng-repeat=\"tab in tabs\" ng-class=\"{ active: $index === selectedItemIndex }\" ng-click=\"ctrl.setActive($index)\"><a ng-attr-title=\"{{ iconsOnly ? tab.title : '' }}\" href><span class=\"icon\" ng-class=\"tab.icon\" ng-if=\"tab.icon\"></span> <span ng-if=\"!iconsOnly\" ng-bind=\"tab.title\"></span></a></ul><div class=\"tabs-contents\"><div ng-if=\"!switchReload\"><div ng-include=\"tab.templateUrl\" ng-repeat=\"tab in tabs\" ng-show=\"$index === selectedItemIndex\"></div></div><div ng-if=\"switchReload\"><div ng-include=\"selectedTemplate\"></div></div></div></div>");

  $templateCache.put('ark-simple-tabs/ark-underline-tabs.html', "<div class=\"underline-tabs-container\"><nav class=\"navbar navbar-switch-default\"><ul class=\"nav navbar-nav\"><li ng-repeat=\"tab in tabs\" ng-class=\"{ active: $index === selectedItemIndex }\" ng-click=\"ctrl.setActive($index)\"><a ng-attr-title=\"{{ iconsOnly ? tab.title : '' }}\" href><span class=\"icon\" ng-class=\"tab.icon\" ng-if=\"tab.icon\"></span> <span ng-if=\"!iconsOnly\" ng-bind=\"tab.title\"></span></a></ul></nav><div class=\"tabs-contents\"><div ng-if=\"!switchReload\"><div ng-include=\"tab.templateUrl\" ng-repeat=\"tab in tabs\" ng-show=\"$index === selectedItemIndex\"></div></div><div ng-if=\"switchReload\"><div ng-include=\"selectedTemplate\"></div></div></div></div>");

  $templateCache.put('ark-slider/ark-slider.html', "<div class=\"ark-slider\" ng-class=\"{'ark-slider-active': isActive}\"><span ng-transclude ng-mousedown=\"setActive()\" ng-mouseup=\"setActive()\"></span><div class=\"slider-value-container\" ng-class=\"{'slider-value-container-active': isActive}\" ng-if=\"!useTooltip\">{{ inputValue }}<span ng-if=\"showPercentage\">&#37;</span></div><div class=\"slider-fill\"><div class=\"slider-value\" ng-show=\"isActive && useTooltip\">{{ inputValue }}<span ng-if=\"showPercentage\">&#37;</span><div class=\"arrow-bottom\"></div></div><div class=\"slider-thumb\"></div></div></div>");

  $templateCache.put('ark-tags/ark-tags.html', "<div class=\"ark-tags\"><span ng-repeat=\"tag in tagList\" class=\"tag animated pulse\" ng-click=\"ctrl.removeTag(tag)\"><span class=\"tag-label\">{{ ::tag }}</span> <a class=\"tag-remove-link\"><span class=\"icon-close\"></span></a></span><div class=\"tag-add-container\"><div ng-click=\"ctrl.addTag()\" class=\"tag-add\"><span class=\"icon-add\"></span></div><input class=\"input-tag\" ng-model=\"inputTag\" placeholder=\"Add a Tag\"></div></div>");

  $templateCache.put('ark-time-picker/ark-time-picker.html', "<div class=\"ark-timepicker\" ng-class=\"{disabled: ngDisabled}\"><div class=\"timepicker-header\" ng-if=\"widgetMode\"><b>{{ headerLabel }}</b></div><div class=\"timepicker-content\"><div class=\"col-container first\"><div class=\"icon-iw-circle-no-chevron-up arrow\" ng-if=\"widgetMode\" while-pressed=\"addHour()\"></div><div class=\"dropdown open\"><input type=\"text\" maxlength=\"2\" ng-model=\"timeData.hour\" ng-click=\"showHour()\" ng-blur=\"validateHour()\"><ul ng-show=\"timeData.showHourList\" class=\"dropdown-menu\" ng-class=\"{scrollable: timeData.hourList.length > 6}\"><li ng-repeat=\"list in timeData.hourList\"><a href ng-mousedown=\"selectHour(list)\" ng-class=\"{selected: list === timeData.hour}\">{{ list }}</a></ul></div><div class=\"icon-iw-circle-no-chevron-down arrow\" ng-if=\"widgetMode\" while-pressed=\"minusHour()\"></div></div><div class=\"col-container column\" ng-if=\"!simplifiedTime\"><b>:</b></div><div class=\"col-container\" ng-if=\"!simplifiedTime\"><div class=\"icon-iw-circle-no-chevron-up arrow\" ng-if=\"widgetMode\" while-pressed=\"addMinute()\"></div><div class=\"dropdown open\"><input type=\"text\" maxlength=\"2\" ng-model=\"timeData.minute\" ng-click=\"showMinute()\" ng-blur=\"validateMinute()\"><ul ng-show=\"timeData.showMinuteList\" class=\"dropdown-menu\" ng-class=\"{scrollable: timeData.minuteList.length > 6}\"><li ng-repeat=\"list in timeData.minuteList\"><a href ng-mousedown=\"selectMinute(list)\" ng-class=\"{selected: list===timeData.minute}\">{{ list }}</a></ul></div><div class=\"icon-iw-circle-no-chevron-down arrow\" ng-if=\"widgetMode\" while-pressed=\"minusMinute()\"></div></div><div class=\"col-container last\" ng-if=\"!militaryTime\"><div class=\"icon-iw-circle-no-chevron-up arrow\" ng-if=\"widgetMode\" ng-click=\"changeNoon()\"></div><div class=\"dropdown open\"><input type=\"text\" maxlength=\"2\" ng-model=\"timeData.noon\" ng-click=\"showNoon()\" ng-blur=\"validateNoon()\"><ul ng-show=\"timeData.showNoonList\" class=\"dropdown-menu\"><li ng-repeat=\"list in timeData.noonList\"><a href ng-mousedown=\"selectNoon(list)\" ng-class=\"{selected: list===timeData.noon}\">{{ list }}</a></ul></div><div class=\"icon-iw-circle-no-chevron-down arrow\" ng-if=\"widgetMode\" ng-click=\"changeNoon()\"></div></div><div class=\"col-container last\" ng-if=\"timezoneMode\"><div class=\"icon-iw-circle-no-chevron-up arrow timezone\" ng-if=\"widgetMode\" ng-click=\"addTimeZone()\"></div><div class=\"dropdown open\"><input type=\"text\" class=\"timezone\" maxlength=\"9\" ng-model=\"timeData.timeZone\" ng-click=\"showTimeZone()\" ng-blur=\"validateTimeZone()\" readonly><ul ng-show=\"timeData.showTimeZoneList\" class=\"dropdown-menu timezone\" ng-class=\"{scrollable: timeData.timeZoneList.length > 6}\"><li ng-repeat=\"list in timeData.timeZoneList\"><a href ng-mousedown=\"selectTimeZone(list, $index)\" class=\"timezone\" ng-class=\"{selected: list === timeData.timeZone}\">{{ list }}</a></ul></div><div class=\"icon-iw-circle-no-chevron-down arrow timezone\" ng-if=\"widgetMode\" ng-click=\"minusTimeZone()\"></div></div></div></div>");

  $templateCache.put('ark-toaster/ark-toaster.html', "<div class=\"ark-toaster-container\"><div class=\"toaster-top-bar\" ng-if=\"$ctrl.toasters.length > 0\">{{ $ctrl.toasters.length }} {{ $ctrl.i18n.NOTIFICATIONS }}<div class=\"toaster-hide-all\" ng-click=\"$ctrl.clearAll()\">{{ $ctrl.i18n.HIDE_ALL }}</div></div><div class=\"toasts-container\"><div ng-repeat=\"toaster in $ctrl.toasters\" class=\"toast\" ng-click=\"$ctrl.click(toaster)\" ng-mouseover=\"$ctrl.stopTimer(toaster)\" ng-mouseout=\"$ctrl.restartTimer(toaster)\"><button class=\"toast-close-button\" ng-if=\"$ctrl.innerConfig.closeButton\" ng-click=\"$ctrl.removeToast(toaster.id)\"><span class=\"icon-close\"></span></button><div class=\"toaster-title-container\"><span class=\"toaster-type\" ng-class=\"toaster.typeIcon\"></span><div class=\"toaster-title\">{{ toaster.title }}</div></div><div class=\"toast-message\" ng-switch on=\"toaster.bodyOutputType\"><div ng-switch-when=\"trustedHtml\" ng-bind-html=\"toaster.html\"></div><div ng-switch-when=\"template\"><div ng-include=\"toaster.bodyTemplate\"></div></div><div ng-switch-default ng-bind=\"toaster.body\"></div></div></div></div></div>");

  $templateCache.put('ark-toolbar/ark-toolbar-button.html', "<span ng-if=\"button.icon\" class=\"fonticon\" ng-class=\"[button.icon, button.buttonStyleClass]\" data-toggle=\"tooltip\" data-placement=\"bottom\" ng-attr-title=\"{{ button.tooltipTitle }}\"></span> <span ng-if=\"button.title\" class=\"icon-title\" ng-attr-title=\"{{ button.tooltipTitle }}\">{{ button.title }}</span><div ng-if=\"button.select\" class=\"btn-group bootstrap-select show-tick\"><button ng-if=\"!button.select.multiple\" type=\"button\" ark-select class=\"btn btn-default dropdown-toggle selectpicker\" ng-attr-id=\"{{ button.select.id }}\" ng-model=\"button.select.value\" ark-options=\"{{ button.select.options }}\" ng-click=\"button.click($event, button)\" placeholder=\"{{ button.select.placeholder }}\" ng-disabled=\"button.isDisabled\"></button> <button ng-if=\"button.select.multiple\" type=\"button\" ark-select class=\"btn btn-default dropdown-toggle selectpicker\" ng-attr-id=\"{{ button.select.id }}\" ng-model=\"button.select.value\" ark-options=\"{{ button.select.options }}\" ng-click=\"button.click($event, button)\" placeholder=\"{{ button.select.placeholder }}\" ng-disabled=\"button.isDisabled\" multiple></button></div><div ng-if=\"button.input\" class=\"inline input-container\"><div class=\"spacer\"></div><span ng-if=\"button.input.icon\" class=\"fonticon\" ng-class=\"[button.input.icon]\"></span> <input ng-if=\"!button.input.eventHandlers\" type=\"text\" class=\"inline form-control search-input\" ng-class=\"button.input.className\" ng-attr-id=\"{{ button.input.id }}\" ng-model=\"button.input.value\" placeholder=\"{{ button.input.placeholder }}\" ng-disabled=\"button.isDisabled\"> <input ng-if=\"button.input.eventHandlers\" type=\"text\" class=\"inline form-control search-input\" ng-class=\"button.input.className\" ng-attr-id=\"{{ button.input.id }}\" ng-model=\"button.input.value\" placeholder=\"{{ button.input.placeholder }}\" parse-handlers handler-array=\"button.input.eventHandlers\" ng-disabled=\"button.isDisabled\"> <span class=\"icon-close search-box-cancel close-span fonticon\" ng-show=\"button.input.value !== ''\" ng-click=\"button.input.value = ''\"></span><div class=\"spacer\"></div></div><div ng-if=\"button.HTMLtemplate\" ng-bind-html=\"button.HTMLtemplate\" class=\"toolbar-template\"></div>");

  $templateCache.put('ark-toolbar/ark-toolbar.html', "<div class=\"ark-toolbar\" ng-class=\"[options.toolbarContainer, options.theme + '-theme']\" ng-style=\"{{ options.toolbarStyle }}\"><ul class=\"lefttoolbar ark-toolbar-buttons\" ng-class=\"options.leftButtonContainer\"><li ng-repeat=\"button in options.lefttoolbar\" class=\"{{ button.class }}\" ng-class=\"{'non-clickable': button.nonClickable, 'is-disabled': button.isDisabled, 'spacer': button.spacer}\" ng-attr-id=\"{{ button.id }}\" ng-click=\"!button.isDisabled && button.click($event, button)\" ark-toolbar-button></ul><ul class=\"righttoolbar ark-toolbar-buttons\" ng-class=\"options.rightButtonContainer\"><li ng-repeat=\"button in options.righttoolbar\" class=\"{{ button.class }}\" ng-class=\"{'non-clickable': button.nonClickable, 'is-disabled': button.isDisabled, 'spacer': button.spacer}\" ng-attr-id=\"{{ button.id }}\" ng-click=\"!button.isDisabled && button.click($event, button)\" ark-toolbar-button></ul></div>");
}]);
//# sourceMappingURL=ark-core.js.map
