text: import Eventor from '../../libs/eventor'
  
  // https://github.com/MoeKit/clocker
  var instances = [];
  var matchers = [];
  // Miliseconds
  matchers.push(/^[0-9]*$/.source);
  // Month/Day/Year [hours:minutes:seconds]
  matchers.push(/([0-9]{1,2}\/){2}[0-9]{4}( [0-9]{1,2}(:[0-9]{2}){2})?/
    .source);
  // Year/Day/Month [hours:minutes:seconds] and
  // Year-Day-Month [hours:minutes:seconds]
  matchers.push(/[0-9]{4}([/-][0-9]{1,2}){2}( [0-9]{1,2}(:[0-9]{2}){2})?/
    .source);
  // Cast the matchers to a regular expression object
  matchers = new RegExp(matchers.join('|'));
  // Parse a Date formatted has String to a native object
  
  function parseDateString (dateString) {
    // Pass through when a native object is sent
    if (dateString instanceof Date) {
      return dateString
    }
    // Caste string to date object
    if (String(dateString).match(matchers)) {
      // If looks like a milisecond value cast to number before
      // final casting (Thanks to @msigley)
      if (String(dateString).match(/^[0-9]*$/)) {
        dateString = Number(dateString)
      }
      // Replace dashes to slashes
      if (String(dateString).match(/-/)) {
        dateString = String(dateString).replace(/-/g, '/')
      }
      return new Date(dateString)
    } else {
      throw new Error('Couldn\'t cast `' + dateString +
        '` to a date object.')
    }
  }
  // Map to convert from a directive to offset object property
  var DIRECTIVE_KEY_MAP = {
    'Y': 'years',
    'm': 'months',
    'w': 'weeks',
    'D': 'days',
    'H': 'hours',
    'M': 'minutes',
    'S': 'seconds'
  };
  // Returns an escaped regexp from the string
  
  function escapedRegExp (str) {
    var sanitize = str.toString().replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
    return new RegExp(sanitize)
  }
  // Time string formatter
  
  function strftime (offsetObject) {
    return function (format) {
      var directives = format.match(/%(-|!)?[A-Z]{1}(:[^]+)?/gi);
      if (directives) {
        for (var i = 0, len = directives.length; i < len; ++i) {
          var directive = directives[i].match(/%(-|!)?([a-zA-Z]{1})(:[^]+)?/);
          var regexp = escapedRegExp(directive[0]);
          var modifier = directive[1] || '';
          var plural = directive[3] || '';
          var value = null;
          // Get the key
          directive = directive[2];
          // Swap shot-versions directives
          if (DIRECTIVE_KEY_MAP.hasOwnProperty(directive)) {
            value = DIRECTIVE_KEY_MAP[directive];
            value = Number(offsetObject[value])
          }
          if (value !== null) {
            // Pluralize
            if (modifier === '!') {
              value = pluralize(plural, value)
            }
            // Add zero-padding
            if (modifier === '') {
              if (value < 10) {
                value = '0' + value.toString()
              }
            }
            // Replace the directive
            format = format.replace(regexp, value.toString())
          }
        }
      }
      format = format.replace('%_M1', offsetObject.minutes_1)
        .replace('%_M2', offsetObject.minutes_2)
        .replace('%_S1', offsetObject.seconds_1)
        .replace('%_S2', offsetObject.seconds_2)
        .replace('%_S3', offsetObject.seconds_3)
        .replace('%_H1', offsetObject.hours_1)
        .replace('%_H2', offsetObject.hours_2)
        .replace('%_H3', offsetObject.hours_3)
        .replace('%_D1', offsetObject.days_1)
        .replace('%_D2', offsetObject.days_2)
        .replace('%_D3', offsetObject.days_3);
      format = format.replace(/%%/, '%');
      return format
    }
  }
  // Pluralize
  
  function pluralize (format, count) {
    var plural = 's';
    var singular = '';
    if (format) {
      format = format.replace(/(:||\s)/gi, '').split(/,/);
      if (format.length === 1) {
        plural = format[0]
      } else {
        singular = format[0];
        plural = format[1]
      }
    }
    if (Math.abs(count) === 1) {
      return singular
    } else {
      return plural
    }
  }
  
  function splitNumber (number) {
    number = number + '';
    number = (number.length === 1 ? ('0' + number) : number) + '';
    return number.split('')
  }
  
  // The Final Countdown
  var Countdown = function (finalDate, option) {
    option = option || {};
    this.PRECISION = option.precision || 100; // 0.1 seconds, used to update the DOM
    this.interval = null;
    this.offset = {};
    // Register this instance
    this.instanceNumber = instances.length;
    instances.push(this);
    // Set the final date and start
    this.setFinalDate(finalDate)
  };
  
  Eventor.mixTo(Countdown);
  var pro = Countdown.prototype;
  
  var fns = {
    start () {
      if (this.interval !== null) {
        clearInterval(this.interval)
      }
      var self = this;
      this.update();
      this.interval = setInterval(function () {
        self.update()
      }, this.PRECISION);
      return this
    },
    stop () {
      clearInterval(this.interval);
      this.interval = null;
      this._dispatchEvent('stoped');
      return this
    },
    toggle () {
      if (this.interval) {
        this.stop()
      } else {
        this.start()
      }
      return this
    },
    pause () {
      return this.stop()
    },
    resume () {
      return this.start()
    },
    remove () {
      this.stop();
      instances[this.instanceNumber] = null
    },
    setFinalDate (value) {
      this.finalDate = parseDateString(value); // Cast the given date
      return this
    },
    getOffset () {
      this.totalSecsLeft = this.finalDate.getTime() - new Date().getTime(); // In miliseconds
      this.totalSecsLeft = Math.ceil(this.totalSecsLeft / 1000);
      this.totalSecsLeft = this.totalSecsLeft < 0 ? 0 : this.totalSecsLeft;
      // Calculate the offsets
      return {
        seconds: this.totalSecsLeft % 60,
        minutes: Math.floor(this.totalSecsLeft / 60) % 60,
        hours: Math.floor(this.totalSecsLeft / 60 / 60) % 24,
        days: Math.floor(this.totalSecsLeft / 60 / 60 / 24),
        weeks: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7),
        months: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 30),
        years: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 365)
      }
    },
    update () {
      // Calculate the offsets
      this.offset = this.getOffset();
      // split offset only for days, hours, minutes, seconds and two number like 45, do not support 100
  
      var list = ['days', 'hours', 'minutes', 'seconds'];
  
      for (var i = 0; i < list.length; i++) {
        var key = list[i];
        var numbers = splitNumber(this.offset[key]);
        for (let n = 0; n < numbers.length; n++) {
          this.offset[`${key}_${n + 1}`] = numbers[n]
        }
      }
      // Dispatch an event
      if (this.totalSecsLeft === 0) {
        this.stop();
        this._dispatchEvent('finish')
      } else {
        this._dispatchEvent('update')
      }
      return this
    },
    _dispatchEvent (eventName) {
      var event = {};
      event.finalDate = this.finalDate;
      event.offset = this.offset;
      event.strftime = strftime(this.offset);
      this.emit(eventName, event);
      this.emit('tick', event)
    }
  };
  
  for (var i in fns) {
    pro[i] = fns[i]
  }
  
  export default Countdown
  