text: /* */ 
  'use strict';
  
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  
  /**
   * Copyright (c) 2013-present, Facebook, Inc.
   * All rights reserved.
   *
   * This source code is licensed under the BSD-style license found in the
   * LICENSE file in the root directory of this source tree. An additional grant
   * of patent rights can be found in the PATENTS file in the same directory.
   *
   *
   */
  
  var KIND_KEYS = 'keys';
  var KIND_VALUES = 'values';
  var KIND_ENTRIES = 'entries';
  
  /**
   * Specific Array iterators.
   */
  var ArrayIterators = function () {
  
    var hasNative = hasNativeIterator(Array);
    var ArrayIterator = void 0;
  
    if (!hasNative) {
      ArrayIterator = function () {
        // 22.1.5.1 CreateArrayIterator Abstract Operation
  
        function ArrayIterator(array, kind) {
          _classCallCheck(this, ArrayIterator);
  
          this._iteratedObject = array;
          this._kind = kind;
          this._nextIndex = 0;
        }
  
        // 22.1.5.2.1 %ArrayIteratorPrototype%.next()
  
  
        ArrayIterator.prototype.next = function next() {
          if (this._iteratedObject == null) {
            return { value: undefined, done: true };
          }
  
          var array = this._iteratedObject;
          var len = this._iteratedObject.length;
          var index = this._nextIndex;
          var kind = this._kind;
  
          if (index >= len) {
            this._iteratedObject = undefined;
            return { value: undefined, done: true };
          }
  
          this._nextIndex = index + 1;
  
          if (kind === KIND_KEYS) {
            return { value: index, done: false };
          } else if (kind === KIND_VALUES) {
            return { value: array[index], done: false };
          } else if (kind === KIND_ENTRIES) {
            return { value: [index, array[index]], done: false };
          }
        };
  
        // 22.1.5.2.2 %ArrayIteratorPrototype%[@@iterator]()
  
  
        ArrayIterator.prototype[Symbol.iterator] = function () {
          return this;
        };
  
        return ArrayIterator;
      }();
    }
  
    return {
      keys: hasNative ? function (array) {
        return array.keys();
      } : function (array) {
        return new ArrayIterator(array, KIND_KEYS);
      },
  
      values: hasNative ? function (array) {
        return array.values();
      } : function (array) {
        return new ArrayIterator(array, KIND_VALUES);
      },
  
      entries: hasNative ? function (array) {
        return array.entries();
      } : function (array) {
        return new ArrayIterator(array, KIND_ENTRIES);
      }
    };
  }();
  
  // -----------------------------------------------------------------
  
  /**
   * Specific String iterators.
   */
  var StringIterators = function () {
  
    var hasNative = hasNativeIterator(String);
    var StringIterator = void 0;
  
    if (!hasNative) {
      StringIterator = function () {
        // 21.1.5.1 CreateStringIterator Abstract Operation
  
        function StringIterator(string) {
          _classCallCheck(this, StringIterator);
  
          this._iteratedString = string;
          this._nextIndex = 0;
        }
  
        // 21.1.5.2.1 %StringIteratorPrototype%.next()
  
  
        StringIterator.prototype.next = function next() {
          if (this._iteratedString == null) {
            return { value: undefined, done: true };
          }
  
          var index = this._nextIndex;
          var s = this._iteratedString;
          var len = s.length;
  
          if (index >= len) {
            this._iteratedString = undefined;
            return { value: undefined, done: true };
          }
  
          var ret = void 0;
          var first = s.charCodeAt(index);
  
          if (first < 0xD800 || first > 0xDBFF || index + 1 === len) {
            ret = s[index];
          } else {
            var second = s.charCodeAt(index + 1);
            if (second < 0xDC00 || second > 0xDFFF) {
              ret = s[index];
            } else {
              ret = s[index] + s[index + 1];
            }
          }
  
          this._nextIndex = index + ret.length;
  
          return { value: ret, done: false };
        };
  
        // 21.1.5.2.2 %StringIteratorPrototype%[@@iterator]()
  
  
        StringIterator.prototype[Symbol.iterator] = function () {
          return this;
        };
  
        return StringIterator;
      }();
    }
  
    return {
      keys: function () {
        throw TypeError('Strings default iterator doesn\'t implement keys.');
      },
  
  
      values: hasNative ? function (string) {
        return string[Symbol.iterator]();
      } : function (string) {
        return new StringIterator(string);
      },
  
      entries: function () {
        throw TypeError('Strings default iterator doesn\'t implement entries.');
      }
    };
  }();
  
  function hasNativeIterator(classObject) {
    return typeof classObject.prototype[Symbol.iterator] === 'function' && typeof classObject.prototype.values === 'function' && typeof classObject.prototype.keys === 'function' && typeof classObject.prototype.entries === 'function';
  }
  
  // -----------------------------------------------------------------
  
  /**
   * Generic object iterator.
   */
  
  var ObjectIterator = function () {
    function ObjectIterator(object, kind) {
      _classCallCheck(this, ObjectIterator);
  
      this._iteratedObject = object;
      this._kind = kind;
      this._keys = Object.keys(object);
      this._nextIndex = 0;
    }
  
    ObjectIterator.prototype.next = function next() {
      var len = this._keys.length;
      var index = this._nextIndex;
      var kind = this._kind;
      var key = this._keys[index];
  
      if (index >= len) {
        this._iteratedObject = undefined;
        return { value: undefined, done: true };
      }
  
      this._nextIndex = index + 1;
  
      if (kind === KIND_KEYS) {
        return { value: key, done: false };
      } else if (kind === KIND_VALUES) {
        return { value: this._iteratedObject[key], done: false };
      } else if (kind === KIND_ENTRIES) {
        return { value: [key, this._iteratedObject[key]], done: false };
      }
    };
  
    ObjectIterator.prototype[Symbol.iterator] = function () {
      return this;
    };
  
    return ObjectIterator;
  }();
  
  /**
   * Generic object iterator, iterates over all own enumerable
   * properties. Used only if if no specific iterator is available,
   * and object don't implement iterator protocol.
   */
  
  
  var GenericIterators = {
    keys: function (object) {
      return new ObjectIterator(object, KIND_KEYS);
    },
    values: function (object) {
      return new ObjectIterator(object, KIND_VALUES);
    },
    entries: function (object) {
      return new ObjectIterator(object, KIND_ENTRIES);
    }
  };
  
  // -----------------------------------------------------------------
  
  /**
   * Main iterator function. Returns default iterator based
   * on the class of an instance.
   */
  function enumerate(object, kind) {
  
    // First check specific iterators.
    if (typeof object === 'string') {
      return StringIterators[kind || KIND_VALUES](object);
    } else if (Array.isArray(object)) {
      return ArrayIterators[kind || KIND_VALUES](object);
  
      // Then see if an object implements own.
    } else if (object[Symbol.iterator]) {
        return object[Symbol.iterator]();
  
        // And fallback to generic with entries.
      } else {
          return GenericIterators[kind || KIND_ENTRIES](object);
        }
  }
  
  Object.assign(enumerate, {
    /**
     * Export constants
     */
  
    KIND_KEYS: KIND_KEYS,
    KIND_VALUES: KIND_VALUES,
    KIND_ENTRIES: KIND_ENTRIES,
  
    /**
     * Convenient explicit iterators for special kinds.
     */
  
    keys: function (object) {
      return enumerate(object, KIND_KEYS);
    },
    values: function (object) {
      return enumerate(object, KIND_VALUES);
    },
    entries: function (object) {
      return enumerate(object, KIND_ENTRIES);
    },
  
  
    generic: GenericIterators.entries
  
  });
  
  module.exports = enumerate;