text: 'use strict';
  
  var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  
  (function (global, factory) {
    'use strict';
  
    var fnc;
    fnc = (typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('angular'), require('moment')) : typeof define === 'function' && define.amd ? define(['angular', 'moment'], factory) : factory(global.angular, global.moment);
  })(undefined, function (angular, moment) {
    if (moment.locale() === 'en') {
      console.error('angular datepicker moment locale en, 如果要中文请执行 moment.locale("zh-cn")');
    }
    //(function (global, factory) {
    //  'use strict';
    //  var fnc;
    //  fnc = (typeof exports === 'object' && typeof module !== 'undefined') ? module.exports = factory(require('angular'), require('moment')) :
    //        (typeof define === 'function' && define.amd) ? define(['angular', 'moment'], factory) :
    //        factory(global.angular, global.moment);
    //}(this, function (angular, moment) {
    var Module = angular.module('datePicker', []);
  
    Module.constant('datePickerConfig', {
      template: 'templates/datepicker.html',
      view: 'month',
      views: ['year', 'month', 'date', 'hours', 'minutes'],
      momentNames: {
        year: 'year',
        month: 'month',
        date: 'day',
        hours: 'hours',
        minutes: 'minutes'
      },
      viewConfig: {
        year: ['years', 'isSameYear'],
        month: ['months', 'isSameMonth'],
        hours: ['hours', 'isSameHour'],
        minutes: ['minutes', 'isSameMinutes']
      },
      step: 5
    });
  
    //Moment format filter.
    Module.filter('mFormat', function () {
      return function (m, format, tz) {
        if (!moment.isMoment(m)) {
          return m ? moment(m).format(format) : '';
        }
        return tz ? moment.tz(m, tz).format(format) : m.format(format);
      };
    });
  
    Module.directive('datePicker', ['datePickerConfig', 'datePickerUtils', function datePickerDirective(datePickerConfig, datePickerUtils) {
  
      //noinspection JSUnusedLocalSymbols
      return {
        // this is a bug ?
        require: '?ngModel',
        template: '<div ng-include="template"></div>',
        scope: {
          model: '=datePicker',
          after: '=?',
          before: '=?'
        },
        link: function link(scope, element, attrs, ngModel) {
          function prepareViews() {
            scope.views = datePickerConfig.views.concat();
            scope.view = attrs.view || datePickerConfig.view;
  
            scope.views = scope.views.slice(scope.views.indexOf(attrs.maxView || 'year'), scope.views.indexOf(attrs.minView || 'minutes') + 1);
  
            if (scope.views.length === 1 || scope.views.indexOf(scope.view) === -1) {
              scope.view = scope.views[0];
            }
          }
  
          function getDate(name) {
            return datePickerUtils.getDate(scope, attrs, name);
          }
  
          var arrowClick = false,
              tz = scope.tz = attrs.timezone,
              createMoment = datePickerUtils.createMoment,
              eventIsForPicker = datePickerUtils.eventIsForPicker,
              step = parseInt(attrs.step || datePickerConfig.step, 10),
              partial = !!attrs.partial,
              minDate = getDate('minDate'),
              maxDate = getDate('maxDate'),
              pickerID = element[0].id,
              now = scope.now = createMoment(),
              selected = scope.date = createMoment(scope.model || now),
              autoclose = attrs.autoClose === 'true',
  
          // Either gets the 1st day from the attributes, or asks moment.js to give it to us as it is localized.
          firstDay = attrs.firstDay && attrs.firstDay >= 0 && attrs.firstDay <= 6 ? parseInt(attrs.firstDay, 10) : moment().weekday(0).day(),
              setDate,
              prepareViewData,
              isSame,
              clipDate,
              isNow,
              inValidRange;
  
          datePickerUtils.setParams(tz, firstDay);
  
          if (!scope.model) {
            selected.minute(Math.ceil(selected.minute() / step) * step).second(0);
          }
  
          scope.template = attrs.template || datePickerConfig.template;
  
          scope.watchDirectChanges = attrs.watchDirectChanges !== undefined;
          scope.callbackOnSetDate = attrs.dateChange ? datePickerUtils.findFunction(scope, attrs.dateChange) : undefined;
  
          prepareViews();
  
          scope.setView = function (nextView) {
            if (scope.views.indexOf(nextView) !== -1) {
              scope.view = nextView;
            }
          };
  
          scope.$on('selectDate', function (e, d, fromOther) {
            scope.selectDate(e, d, fromOther);
          });
  
          scope.selectDate = function (e, date, fromOther) {
            if (angular.element(e.target).hasClass('disabled')) {
              return false;
            }
            if (attrs.disabled) {
              return false;
            }
            if (isSame(scope.date, date)) {
              date = scope.date;
            }
            date = clipDate(date);
            // if (!date) {
            //   return false;
            // }
            scope.date = date;
  
            var nextView = scope.views[scope.views.indexOf(scope.view) + 1];
            if (!nextView || partial || scope.model) {
              setDate(date, fromOther);
            }
  
            if (nextView) {
              scope.setView(nextView);
            } else if (autoclose) {
              setTimeout(function () {
                element.addClass('hidden');
                scope.$emit('hidePicker');
              }, 50);
            } else if (date) {
              prepareViewData();
              // autoClose
              setTimeout(function () {
                scope.$emit('hidePicker');
              }, 50);
            }
          };
  
          setDate = function setDate(date, fromOther) {
            // if (date) {
            scope.model = date;
            if (ngModel) {
              ngModel.$setViewValue(date);
            }
            // }
            scope.$emit('setDate', scope.model, scope.view, fromOther);
  
            //This is duplicated in the new functionality.
            if (scope.callbackOnSetDate) {
              scope.callbackOnSetDate(attrs.datePicker, scope.date);
            }
          };
  
          function update() {
            var view = scope.view;
            datePickerUtils.setParams(tz, firstDay);
  
            if (scope.model && !arrowClick) {
              scope.date = createMoment(scope.model);
              arrowClick = false;
            }
  
            var date = scope.date;
  
            switch (view) {
              case 'year':
                scope.years = datePickerUtils.getVisibleYears(date);
                break;
              case 'month':
                scope.months = datePickerUtils.getVisibleMonths(date);
                break;
              case 'date':
                scope.weekdays = scope.weekdays || datePickerUtils.getDaysOfWeek();
                scope.weeks = datePickerUtils.getVisibleWeeks(date);
                break;
              case 'hours':
                scope.hours = datePickerUtils.getVisibleHours(date);
                break;
              case 'minutes':
                scope.minutes = datePickerUtils.getVisibleMinutes(date, step);
                break;
            }
  
            prepareViewData();
          }
  
          function watch() {
            if (scope.view !== 'date') {
              return scope.view;
            }
            return scope.date ? scope.date.month() : null;
          }
  
          scope.$watch(watch, update);
  
          if (scope.watchDirectChanges) {
            scope.$watch('model', function () {
              arrowClick = false;
              update();
            });
          }
  
          prepareViewData = function prepareViewData() {
            var view = scope.view,
                date = scope.date,
                classes = [],
                classList = '',
                i,
                j;
  
            if (!scope.date) {
              scope.date = moment(new Date());
              date = scope.date;
            }
  
            datePickerUtils.setParams(tz, firstDay);
  
            if (view === 'date') {
              var weeks = scope.weeks,
                  week;
              for (i = 0; i < weeks.length; i++) {
                week = weeks[i];
                classes.push([]);
                for (j = 0; j < week.length; j++) {
                  classList = '';
                  if (datePickerUtils.isSameDay(date, week[j])) {
                    classList += 'active';
                  }
                  if (isNow(week[j], view)) {
                    classList += ' now';
                  }
                  //if (week[j].month() !== date.month()) classList += ' disabled';
                  if (!inValidRange(week[j])) {
                    classList += ' disabled out-of-valid-range';
                  } else if (week[j].month() !== date.month()) {
                    classList += ' disabled';
                  }
  
                  classes[i].push(classList);
                }
              }
            } else {
              var params = datePickerConfig.viewConfig[view],
                  dates = scope[params[0]],
                  compareFunc = params[1];
  
              for (i = 0; i < dates.length; i++) {
                classList = '';
                if (datePickerUtils[compareFunc](date, dates[i])) {
                  classList += 'active';
                }
                if (isNow(dates[i], view)) {
                  classList += ' now';
                }
                if (!inValidRange(dates[i])) {
                  classList += ' disabled out-of-valid-range';
                }
                classes.push(classList);
              }
            }
            scope.classes = classes;
          };
  
          scope.next = function (delta) {
            var date = moment(scope.date);
            delta = delta || 1;
            switch (scope.view) {
              case 'year':
              /*falls through*/
              case 'month':
                date.year(date.year() + delta);
                break;
              case 'date':
                date.month(date.month() + delta);
                break;
              case 'hours':
              /*falls through*/
              case 'minutes':
                date.hours(date.hours() + delta);
                break;
            }
            date = clipDate(date);
            if (date) {
              scope.date = date;
              arrowClick = true;
              update();
            }
          };
  
          inValidRange = function inValidRange(date) {
            var valid = true;
            if (minDate && minDate.isAfter(date)) {
              valid = isSame(minDate, date);
            }
            if (maxDate && maxDate.isBefore(date)) {
              valid &= isSame(maxDate, date);
            }
            return valid;
          };
  
          isSame = function isSame(date1, date2) {
            return date1 && date1.isSame(date2, datePickerConfig.momentNames[scope.view]) ? true : false;
          };
  
          clipDate = function clipDate(date) {
            if (minDate && minDate.isAfter(date)) {
              return minDate;
            } else if (maxDate && maxDate.isBefore(date)) {
              return maxDate;
            } else {
              return date;
            }
          };
  
          isNow = function isNow(date, view) {
            var is = true;
  
            switch (view) {
              case 'minutes':
                is &= ~~(now.minutes() / step) === ~~(date.minutes() / step);
              /* falls through */
              case 'hours':
                is &= now.hours() === date.hours();
              /* falls through */
              case 'date':
                is &= now.date() === date.date();
              /* falls through */
              case 'month':
                is &= now.month() === date.month();
              /* falls through */
              case 'year':
                is &= now.year() === date.year();
            }
            return is;
          };
  
          scope.prev = function (delta) {
            return scope.next(-delta || -1);
          };
  
          if (pickerID) {
            scope.$on('pickerUpdate', function (event, pickerIDs, data) {
              if (eventIsForPicker(pickerIDs, pickerID)) {
                var updateViews = false,
                    updateViewData = false;
  
                if (angular.isDefined(data.minDate)) {
                  minDate = data.minDate ? data.minDate : false;
                  updateViewData = true;
                }
                if (angular.isDefined(data.maxDate)) {
                  maxDate = data.maxDate ? data.maxDate : false;
                  updateViewData = true;
                }
  
                if (angular.isDefined(data.minView)) {
                  attrs.minView = data.minView;
                  updateViews = true;
                }
                if (angular.isDefined(data.maxView)) {
                  attrs.maxView = data.maxView;
                  updateViews = true;
                }
                attrs.view = data.view || attrs.view;
  
                if (updateViews) {
                  prepareViews();
                }
  
                if (updateViewData) {
                  update();
                }
              }
            });
          }
        }
      };
    }]);
    //}));
  
    //(function (global, factory) {
    //  'use strict';
    //  var fnc;
    //  fnc = (typeof exports === 'object' && typeof module !== 'undefined') ? module.exports = factory(require('angular'), require('moment')) :
    //    (typeof define === 'function' && define.amd) ? define(['angular', 'moment'], factory) :
    //      factory(global.angular, global.moment);
    //}(this, function (angular, moment) {
    angular.module('datePicker').factory('datePickerUtils', function () {
      var tz, firstDay;
      var createNewDate = function createNewDate(year, month, day, hour, minute) {
        var utc = Date.UTC(year | 0, month | 0, day | 0, hour | 0, minute | 0);
        return tz ? moment.tz(utc, tz) : moment(utc);
      };
  
      return {
        getVisibleMinutes: function getVisibleMinutes(m, step) {
          var year = m.year(),
              month = m.month(),
              day = m.date(),
              hour = m.hours(),
              pushedDate,
              offset = m.utcOffset() / 60,
              minutes = [],
              minute;
  
          for (minute = 0; minute < 60; minute += step) {
            pushedDate = createNewDate(year, month, day, hour - offset, minute);
            minutes.push(pushedDate);
          }
          return minutes;
        },
        getVisibleWeeks: function getVisibleWeeks(m) {
          m = moment(m);
          var startYear = m.year(),
              startMonth = m.month();
  
          //Set date to the first day of the month
          m.date(1);
  
          //Grab day of the week
          var day = m.day();
  
          //Go back the required number of days to arrive at the previous week start
          m.date(firstDay - (day + (firstDay >= day ? 6 : -1)));
  
          var weeks = [];
  
          while (weeks.length < 6) {
            if (m.year() === startYear && m.month() > startMonth) {
              break;
            }
            weeks.push(this.getDaysOfWeek(m));
            m.add(7, 'd');
          }
          return weeks;
        },
        getVisibleYears: function getVisibleYears(d) {
          var m = moment(d),
              year = m.year();
  
          m.year(year - year % 10);
          year = m.year();
  
          var offset = m.utcOffset() / 60,
              years = [],
              pushedDate,
              actualOffset;
  
          for (var i = 0; i < 12; i++) {
            pushedDate = createNewDate(year, 0, 1, 0 - offset);
            actualOffset = pushedDate.utcOffset() / 60;
            if (actualOffset !== offset) {
              pushedDate = createNewDate(year, 0, 1, 0 - actualOffset);
              offset = actualOffset;
            }
            years.push(pushedDate);
            year++;
          }
          return years;
        },
        getDaysOfWeek: function getDaysOfWeek(m) {
          m = m ? m : tz ? moment.tz(tz).day(firstDay) : moment().day(firstDay);
  
          var year = m.year(),
              month = m.month(),
              day = m.date(),
              days = [],
              pushedDate,
              offset = m.utcOffset() / 60,
              actualOffset;
  
          for (var i = 0; i < 7; i++) {
            pushedDate = createNewDate(year, month, day, 0 - offset, 0, false);
            actualOffset = pushedDate.utcOffset() / 60;
            if (actualOffset !== offset) {
              pushedDate = createNewDate(year, month, day, 0 - actualOffset, 0, false);
            }
            days.push(pushedDate);
            day++;
          }
          return days;
        },
        getVisibleMonths: function getVisibleMonths(m) {
          var year = m.year(),
              offset = m.utcOffset() / 60,
              months = [],
              pushedDate,
              actualOffset;
  
          for (var month = 0; month < 12; month++) {
            pushedDate = createNewDate(year, month, 1, 0 - offset, 0, false);
            actualOffset = pushedDate.utcOffset() / 60;
            if (actualOffset !== offset) {
              pushedDate = createNewDate(year, month, 1, 0 - actualOffset, 0, false);
            }
            months.push(pushedDate);
          }
          return months;
        },
        getVisibleHours: function getVisibleHours(m) {
          var year = m.year(),
              month = m.month(),
              day = m.date(),
              hours = [],
              hour,
              pushedDate,
              actualOffset,
              offset = m.utcOffset() / 60;
  
          for (hour = 0; hour < 24; hour++) {
            pushedDate = createNewDate(year, month, day, hour - offset, 0, false);
            actualOffset = pushedDate.utcOffset() / 60;
            if (actualOffset !== offset) {
              pushedDate = createNewDate(year, month, day, hour - actualOffset, 0, false);
            }
            hours.push(pushedDate);
          }
  
          return hours;
        },
        isAfter: function isAfter(model, date) {
          return model && model.unix() >= date.unix();
        },
        isBefore: function isBefore(model, date) {
          return model.unix() <= date.unix();
        },
        isSameYear: function isSameYear(model, date) {
          return model && model.year() === date.year();
        },
        isSameMonth: function isSameMonth(model, date) {
          return this.isSameYear(model, date) && model.month() === date.month();
        },
        isSameDay: function isSameDay(model, date) {
          return this.isSameMonth(model, date) && model.date() === date.date();
        },
        isSameHour: function isSameHour(model, date) {
          return this.isSameDay(model, date) && model.hours() === date.hours();
        },
        isSameMinutes: function isSameMinutes(model, date) {
          return this.isSameHour(model, date) && model.minutes() === date.minutes();
        },
        setParams: function setParams(zone, fd) {
          tz = zone;
          firstDay = fd;
        },
        scopeSearch: function scopeSearch(scope, name, comparisonFn) {
          var parentScope = scope,
              nameArray = name.split('.'),
              target,
              i,
              j = nameArray.length;
  
          do {
            target = parentScope = parentScope.$parent;
  
            //Loop through provided names.
            for (i = 0; i < j; i++) {
              target = target[nameArray[i]];
              if (!target) {
                continue;
              }
            }
  
            //If we reached the end of the list for this scope,
            //and something was found, trigger the comparison
            //function. If the comparison function is happy, return
            //found result. Otherwise, continue to the next parent scope
            if (target && comparisonFn(target)) {
              return target;
            }
          } while (parentScope.$parent);
  
          return false;
        },
        findFunction: function findFunction(scope, name) {
          //Search scope ancestors for a matching function.
          return this.scopeSearch(scope, name, function (target) {
            //Property must also be a function
            return angular.isFunction(target);
          });
        },
        findParam: function findParam(scope, name) {
          //Search scope ancestors for a matching parameter.
          return this.scopeSearch(scope, name, function () {
            //As long as the property exists, we're good
            return true;
          });
        },
        createMoment: function createMoment(m) {
          if (tz) {
            return moment.tz(m, tz);
          } else {
            //If input is a moment, and we have no TZ info, we need to remove TZ
            //info from the moment, otherwise the newly created moment will take
            //the timezone of the input moment. The easiest way to do that is to
            //take the unix timestamp, and use that to create a new moment.
            //The new moment will use the local timezone of the user machine.
            return moment.isMoment(m) ? moment.unix(m.unix()) : moment(m);
          }
        },
        getDate: function getDate(scope, attrs, name) {
          var result = false;
          if (attrs[name]) {
            result = this.createMoment(attrs[name]);
            if (!result.isValid()) {
              result = this.findParam(scope, attrs[name]);
              if (result) {
                result = this.createMoment(result);
              }
            }
          }
  
          return result;
        },
        eventIsForPicker: function eventIsForPicker(targetIDs, pickerID) {
          //Checks if an event targeted at a specific picker, via either a string name, or an array of strings.
          return angular.isArray(targetIDs) && targetIDs.indexOf(pickerID) > -1 || targetIDs === pickerID;
        }
      };
    });
    //}));
  
    //(function (global, factory) {
    //  'use strict';
    //  var fnc;
    //  fnc = (typeof exports === 'object' && typeof module !== 'undefined') ? module.exports = factory(require('angular'), require('moment')) :
    //    (typeof define === 'function' && define.amd) ? define(['angular', 'moment'], factory) :
    //      factory(global.angular, global.moment);
    //}(this, function (angular, moment) {
    var Module = angular.module('datePicker');
  
    Module.directive('dateRange', ['$compile', 'datePickerUtils', 'dateTimeConfig', function ($compile, datePickerUtils, dateTimeConfig) {
      function getTemplate(attrs, id, model, min, max) {
        return dateTimeConfig.template(angular.extend(attrs, {
          ngModel: model,
          minDate: min && moment.isMoment(min) ? min.format() : false,
          maxDate: max && moment.isMoment(max) ? max.format() : false
        }), id);
      }
  
      function randomName() {
        return 'picker' + Math.random().toString().substr(2);
      }
  
      return {
        scope: {
          start: '=',
          end: '='
        },
        link: function link(scope, element, attrs) {
          var dateChange = null,
              pickerRangeID = element[0].id,
              pickerIDs = [randomName(), randomName()],
              createMoment = datePickerUtils.createMoment,
              eventIsForPicker = datePickerUtils.eventIsForPicker;
  
          scope.dateChange = function (modelName, newDate) {
            //Notify user if callback exists.
            if (dateChange) {
              dateChange(modelName, newDate);
            }
          };
  
          function setMax(date) {
            scope.$broadcast('pickerUpdate', pickerIDs[0], {
              maxDate: date
            });
          }
  
          function setMin(date) {
            scope.$broadcast('pickerUpdate', pickerIDs[1], {
              minDate: date
            });
          }
  
          if (pickerRangeID) {
            scope.$on('pickerUpdate', function (event, targetIDs, data) {
              if (eventIsForPicker(targetIDs, pickerRangeID)) {
                //If we received an update event, dispatch it to the inner pickers using their IDs.
                scope.$broadcast('pickerUpdate', pickerIDs, data);
              }
            });
          }
  
          datePickerUtils.setParams(attrs.timezone);
  
          scope.start = createMoment(scope.start);
          scope.end = createMoment(scope.end);
  
          scope.$watchGroup(['start', 'end'], function (dates) {
            //Scope data changed, update picker min/max
            setMin(dates[0]);
            setMax(dates[1]);
          });
  
          if (angular.isDefined(attrs.dateChange)) {
            dateChange = datePickerUtils.findFunction(scope, attrs.dateChange);
          }
  
          attrs.onSetDate = 'dateChange';
  
          var template = '<div><table class="date-range"><tr><td valign="top">' + getTemplate(attrs, pickerIDs[0], 'start', false, scope.end) + '</td><td valign="top">' + getTemplate(attrs, pickerIDs[1], 'end', scope.start, false) + '</td></tr></table></div>';
  
          var picker = $compile(template)(scope);
          element.append(picker);
        }
      };
    }]);
    //}));
  
    //(function (global, factory) {
    //  'use strict';
    //  var fnc;
    //  fnc = (typeof exports === 'object' && typeof module !== 'undefined') ? module.exports = factory(require('angular'), require('moment')) :
    //    (typeof define === 'function' && define.amd) ? define(['angular', 'moment'], factory) :
    //      factory(global.angular, global.moment);
    //}(this, function (angular, moment) {
    var PRISTINE_CLASS = 'ng-pristine',
        DIRTY_CLASS = 'ng-dirty';
  
    var Module = angular.module('datePicker');
  
    Module.constant('dateTimeConfig', {
      template: function template(attrs, id) {
        return '' + '<div ' + (id ? 'id="' + id + '" ' : '') + 'date-picker="' + attrs.ngModel + '" ' + (attrs.view ? 'view="' + attrs.view + '" ' : '') + (attrs.maxView ? 'max-view="' + attrs.maxView + '" ' : '') + (attrs.maxDate ? 'max-date="' + attrs.maxDate + '" ' : '') + (attrs.autoClose ? 'auto-close="' + attrs.autoClose + '" ' : '') + (attrs.template ? 'template="' + attrs.template + '" ' : '') + (attrs.minView ? 'min-view="' + attrs.minView + '" ' : '') + (attrs.minDate ? 'min-date="' + attrs.minDate + '" ' : '') + (attrs.partial ? 'partial="' + attrs.partial + '" ' : '') + (attrs.step ? 'step="' + attrs.step + '" ' : '') + (attrs.onSetDate ? 'date-change="' + attrs.onSetDate + '" ' : '') + (attrs.ngModel ? 'ng-model="' + attrs.ngModel + '" ' : '') + (attrs.firstDay ? 'first-day="' + attrs.firstDay + '" ' : '') + (attrs.timezone ? 'timezone="' + attrs.timezone + '" ' : '') + 'class="date-picker-date-time"></div>';
      },
      format: 'YYYY-MM-DD HH:mm',
      views: ['date', 'year', 'month', 'hours', 'minutes'],
      autoClose: false,
      position: 'relative'
    });
  
    Module.directive('dateTimeAppend', function () {
      return {
        link: function link(scope, element) {
          element.bind('click', function () {
            element.find('input')[0].focus();
          });
        }
      };
    });
  
    Module.directive('dateTime', ['$compile', '$document', '$filter', 'dateTimeConfig', '$parse', 'datePickerUtils', function ($compile, $document, $filter, dateTimeConfig, $parse, datePickerUtils) {
      var body = $document.find('body');
      var dateFilter = $filter('mFormat');
  
      return {
        require: 'ngModel',
        scope: true,
        link: function link(scope, element, attrs, ngModel) {
          var format = attrs.format || dateTimeConfig.format,
              parentForm = element.inheritedData('$formController'),
              views = $parse(attrs.views)(scope) || dateTimeConfig.views.concat(),
              view = attrs.view || views[0],
              index = views.indexOf(view),
              dismiss = attrs.autoClose ? $parse(attrs.autoClose)(scope) : dateTimeConfig.autoClose,
              picker = null,
              pickerID = element[0].id,
              position = attrs.position || dateTimeConfig.position,
              container = null,
              minDate = null,
              minValid = null,
              maxDate = null,
              maxValid = null,
              timezone = attrs.timezone || false,
              eventIsForPicker = datePickerUtils.eventIsForPicker,
              dateChange = null,
              shownOnce = false,
              template;
  
          if (index === -1) {
            views.splice(index, 1);
          }
  
          views.unshift(view);
  
          attrs.$observe('id', function (d) {
            pickerID = d;
          });
  
          function formatter(value) {
            return dateFilter(value, format, timezone);
          }
  
          function parser(viewValue) {
            if (viewValue.length === format.length) {
              return viewValue;
            }
            return viewValue.length === 0 ? viewValue : undefined;
          }
  
          function setMin(date) {
            if (date && !moment.isMoment(date)) {
              date = moment(date);
            }
            minDate = date;
            attrs.minDate = date ? date.format() : date;
            minValid = moment.isMoment(date);
          }
  
          function setMax(date) {
            if (date && !moment.isMoment(date)) {
              date = moment(date);
            }
            maxDate = date;
  
            attrs.maxDate = date ? date.format() : date;
            maxValid = moment.isMoment(date);
          }
  
          ngModel.$formatters.push(formatter);
          ngModel.$parsers.unshift(parser);
  
          if (angular.isDefined(attrs.minDate)) {
            setMin(datePickerUtils.findParam(scope, attrs.minDate));
  
            ngModel.$validators.min = function (value) {
              //If we don't have a min / max value, then any value is valid.
              return minValid ? moment.isMoment(value) && (minDate.isSame(value) || minDate.isBefore(value)) : true;
            };
          }
  
          if (angular.isDefined(attrs.maxDate)) {
            setMax(datePickerUtils.findParam(scope, attrs.maxDate));
  
            ngModel.$validators.max = function (value) {
              return maxValid ? moment.isMoment(value) && (maxDate.isSame(value) || maxDate.isAfter(value)) : true;
            };
          }
  
          if (angular.isDefined(attrs.dateChange)) {
            dateChange = datePickerUtils.findFunction(scope, attrs.dateChange);
          }
  
          function getTemplate() {
            template = dateTimeConfig.template(attrs);
          }
  
          function updateInput(event) {
            if (event.stopPropagation) {
              event.stopPropagation();
            }
            if (ngModel.$pristine) {
              ngModel.$dirty = true;
              ngModel.$pristine = false;
              element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
              if (parentForm) {
                parentForm.$setDirty();
              }
              ngModel.$render();
            }
          }
  
          scope.$on('clearPickerView', clear);
  
          function clear() {
            if (picker) {
              picker.remove();
              picker = null;
            }
            if (container) {
              container.remove();
              container = null;
            }
          }
  
          if (pickerID) {
            scope.$on('pickerUpdate', function (event, pickerIDs, data) {
              // console.log(pickerIDs, pickerID);
              if (eventIsForPicker(pickerIDs, pickerID)) {
                if (picker) {
                  //Need to handle situation where the data changed but the picker is currently open.
                  //To handle this, we can create the inner picker with a random ID, then forward
                  //any events received to it.
                } else {
                  var validateRequired = false;
                  if (angular.isDefined(data.minDate)) {
                    setMin(data.minDate);
                    validateRequired = true;
                  }
                  if (angular.isDefined(data.maxDate)) {
                    setMax(data.maxDate);
                    validateRequired = true;
                  }
  
                  if (angular.isDefined(data.minView)) {
                    attrs.minView = data.minView;
                  }
                  if (angular.isDefined(data.maxView)) {
                    attrs.maxView = data.maxView;
                  }
                  attrs.view = data.view || attrs.view;
  
                  if (validateRequired) {
                    ngModel.$validate();
                  }
                  if (angular.isDefined(data.format)) {
                    format = attrs.format = data.format || dateTimeConfig.format;
                    ngModel.$modelValue = -1; //Triggers formatters. This value will be discarded.
                  }
                  getTemplate();
                }
              }
            });
          }
  
          function showPicker() {
            if (picker) {
              return;
            }
            // create picker element
            picker = $compile(template)(scope);
            scope.$digest();
  
            //If the picker has already been shown before then we shouldn't be binding to events, as these events are already bound to in this scope.
            if (!shownOnce) {
              scope.$on('setDate', function (event, date, view, fromOther) {
                updateInput(event);
                if (dateChange && fromOther !== true) {
                  dateChange(attrs.ngModel, date);
                }
                if (dismiss && views[views.length - 1] === view) {
                  clear();
                }
              });
  
              scope.$on('hidePicker', function () {
                element[0].blur();
              });
  
              scope.$on('$destroy', clear);
  
              shownOnce = true;
            }
  
            // move picker below input element
  
            if (position === 'absolute') {
              var pos = element[0].getBoundingClientRect();
              // Support IE8
              var height = pos.height || element[0].offsetHeight;
              picker.css({
                top: pos.top + height + 'px',
                left: pos.left + 'px',
                display: 'block',
                position: position
              });
              body.append(picker);
            } else {
              // relative
              container = angular.element('<div date-picker-wrapper></div>');
              element[0].parentElement.insertBefore(container[0], element[0]);
              container.append(picker);
              //          this approach doesn't work
              //          element.before(picker);
              picker.css({
                top: element[0].offsetHeight + 'px',
                display: 'block'
              });
            }
            picker.bind('mousedown', function (evt) {
              evt.preventDefault();
            });
          }
  
          element.bind('focus', showPicker);
          element.bind('click', showPicker);
          element.bind('blur', clear);
          getTemplate();
        }
      };
    }]);
    //}));
  
    angular.module('datePicker').run(['$templateCache', function ($templateCache) {
      $templateCache.put('templates/datepicker.html', "<div ng-switch=\"view\">\r" + "\n" + "  <div ng-switch-when=\"date\">\r" + "\n" + "    <table>\r" + "\n" + "      <thead>\r" + "\n" + "      <tr>\r" + "\n" + "        <th ng-click=\"prev()\">&lsaquo;</th>\r" + "\n" + "        <th colspan=\"5\" class=\"switch\" ng-click=\"setView('month')\" ng-bind=\"date|mFormat:'YYYY MMMM':tz\"></th>\r" + "\n" + "        <th ng-click=\"next()\">&rsaquo;</i></th>\r" + "\n" + "      </tr>\r" + "\n" + "      <tr>\r" + "\n" + "        <th ng-repeat=\"day in weekdays\" style=\"overflow: hidden\" ng-bind=\"day|mFormat:'ddd':tz\"></th>\r" + "\n" + "      </tr>\r" + "\n" + "      </thead>\r" + "\n" + "      <tbody>\r" + "\n" + "      <tr ng-repeat=\"week in weeks\" ng-init=\"$index2 = $index\">\r" + "\n" + "        <td ng-repeat=\"day in week\">\r" + "\n" + "          <span\r" + "\n" + "            ng-class=\"classes[$index2][$index]\"\r" + "\n" + "            ng-click=\"selectDate($event, day)\" ng-bind=\"day|mFormat:'DD':tz\"></span>\r" + "\n" + "        </td>\r" + "\n" + "      </tr>\r" + "\n" + "      </tbody>\r" + "\n" + "    </table>\r" + "\n" + "  </div>\r" + "\n" + "  <div ng-switch-when=\"year\">\r" + "\n" + "    <table>\r" + "\n" + "      <thead>\r" + "\n" + "      <tr>\r" + "\n" + "        <th ng-click=\"prev(10)\">&lsaquo;</th>\r" + "\n" + "        <th colspan=\"5\" class=\"switch\"ng-bind=\"years[0].year()+' - '+years[years.length-1].year()\"></th>\r" + "\n" + "        <th ng-click=\"next(10)\">&rsaquo;</i></th>\r" + "\n" + "      </tr>\r" + "\n" + "      </thead>\r" + "\n" + "      <tbody>\r" + "\n" + "      <tr>\r" + "\n" + "        <td colspan=\"7\">\r" + "\n" + "          <span ng-class=\"classes[$index]\"\r" + "\n" + "                ng-repeat=\"year in years\"\r" + "\n" + "                ng-click=\"selectDate($event, year)\" ng-bind=\"year.year()\"></span>\r" + "\n" + "        </td>\r" + "\n" + "      </tr>\r" + "\n" + "      </tbody>\r" + "\n" + "    </table>\r" + "\n" + "  </div>\r" + "\n" + "  <div ng-switch-when=\"month\">\r" + "\n" + "    <table>\r" + "\n" + "      <thead>\r" + "\n" + "      <tr>\r" + "\n" + "        <th ng-click=\"prev()\">&lsaquo;</th>\r" + "\n" + "        <th colspan=\"5\" class=\"switch\" ng-click=\"setView('year')\" ng-bind=\"date|mFormat:'YYYY':tz\"></th>\r" + "\n" + "        <th ng-click=\"next()\">&rsaquo;</i></th>\r" + "\n" + "      </tr>\r" + "\n" + "      </thead>\r" + "\n" + "      <tbody>\r" + "\n" + "      <tr>\r" + "\n" + "        <td colspan=\"7\">\r" + "\n" + "          <span ng-repeat=\"month in months\"\r" + "\n" + "                ng-class=\"classes[$index]\"\r" + "\n" + "                ng-click=\"selectDate($event, month)\"\r" + "\n" + "                ng-bind=\"month|mFormat:'MMM':tz\"></span>\r" + "\n" + "        </td>\r" + "\n" + "      </tr>\r" + "\n" + "      </tbody>\r" + "\n" + "    </table>\r" + "\n" + "  </div>\r" + "\n" + "  <div ng-switch-when=\"hours\">\r" + "\n" + "    <table>\r" + "\n" + "      <thead>\r" + "\n" + "      <tr>\r" + "\n" + "        <th ng-click=\"prev(24)\">&lsaquo;</th>\r" + "\n" + "        <th colspan=\"5\" class=\"switch\" ng-click=\"setView('date')\" ng-bind=\"date|mFormat:'DD MMMM YYYY':tz\"></th>\r" + "\n" + "        <th ng-click=\"next(24)\">&rsaquo;</i></th>\r" + "\n" + "      </tr>\r" + "\n" + "      </thead>\r" + "\n" + "      <tbody>\r" + "\n" + "      <tr>\r" + "\n" + "        <td colspan=\"7\">\r" + "\n" + "          <span ng-repeat=\"hour in hours\"\r" + "\n" + "                ng-class=\"classes[$index]\"\r" + "\n" + "                ng-click=\"selectDate($event, hour)\" ng-bind=\"hour|mFormat:'HH:mm':tz\"></span>\r" + "\n" + "        </td>\r" + "\n" + "      </tr>\r" + "\n" + "      </tbody>\r" + "\n" + "    </table>\r" + "\n" + "  </div>\r" + "\n" + "  <div ng-switch-when=\"minutes\">\r" + "\n" + "    <table>\r" + "\n" + "      <thead>\r" + "\n" + "      <tr>\r" + "\n" + "        <th ng-click=\"prev()\">&lsaquo;</th>\r" + "\n" + "        <th colspan=\"5\" class=\"switch\" ng-click=\"setView('hours')\" ng-bind=\"date|mFormat:'DD MMMM YYYY':tz\"></th>\r" + "\n" + "        <th ng-click=\"next()\">&rsaquo;</i></th>\r" + "\n" + "      </tr>\r" + "\n" + "      </thead>\r" + "\n" + "      <tbody>\r" + "\n" + "      <tr>\r" + "\n" + "        <td colspan=\"7\">\r" + "\n" + "          <span ng-repeat=\"minute in minutes\"\r" + "\n" + "                ng-class=\"classes[$index]\"\r" + "\n" + "                ng-click=\"selectDate($event, minute)\"\r" + "\n" + "                ng-bind=\"minute|mFormat:'HH:mm':tz\"></span>\r" + "\n" + "        </td>\r" + "\n" + "      </tr>\r" + "\n" + "      </tbody>\r" + "\n" + "    </table>\r" + "\n" + "  </div>\r" + "\n" + "</div>");
    }]);
  });
  