docs: function Enumerable(object) {
    var self = this,
      enumeratorFactory = Enumerator.enumeratorFactories[crafity.getType(object)];
  
    if (enumeratorFactory === undefined) {
      throw ("There is no Enumerator for an object of type '" + crafity.getType(object) + "'");
    }
  
    /**
     * An enumerable object
     */
    this.getObject = function internalGetObject() {
      return object;
    };
  
    this.overrideEnumerator = function overrideEnumeratorInternal(getEnumerator) {
      self.getEnumerator = function getEnumeratorInternal() {
        return function () {
          return getEnumerator(self.getEnumerator());
        };
      };
      return self;
    };
  
    /**
     * Returns a function that gets an enumerator
     * @returns {Function} A function to get an enumerator
     */
    this.getEnumerator = function getEnumeratorInternal() {
      return enumeratorFactory.getEnumerator(self, object);
    };
  
    /**
     * Define a for each loop for an enumerable
     * @param {Function} consumer A yield function
     * @returns {Enumerable} A new enumerable containing the each logic
     */
    this.forEach = function forEachInternal(consumer) {
      return crafity.Enumerable.from(consumer);
    };
    /**
     * Selects or transforms an enumerable into a new enumerable
     * @param {Function} func A function that selects a value from an item
     * @returns {Enumerable} A new enumerable containing the select logic
     */
    this.select = function selectInternal(func) {
      //	return self.forEach(
      //		function forEachItem(value, yieldReturn) {
      //			yieldReturn(func(value));
      //		}
      //		);
  
      //	return new Enumerable(this).overrideEnumerator(function(enumerator) {
      //		return enumerator.overrideGetCurrent(function (current) {
      //			return func(current);
      //		});
      //	});
      var innerEnumerator = self.getEnumerator();
      return new Enumerable(
        new Enumerator(
          function getCurrentInternal() {
            return func(innerEnumerator.getCurrent());
          },
          function moveNextInternal() {
            return innerEnumerator.moveNext();
          },
          function resetInternal() {
            return innerEnumerator.reset();
          }
        )
      );
    };
    this.union = function unionInternal(enumerable) {
      var innerEnumerator = self.getEnumerator(),
        otherEnumerable,
        otherEnumerator,
        switched = false;
      return new crafity.Enumerable(
        new crafity.Enumerator(
          function getCurrentInternal() {
            return switched === false ? innerEnumerator.getCurrent() : otherEnumerator.getCurrent();
          },
          function moveNextInternal() {
            var result = false;
            if (switched === false) {
              result = innerEnumerator.moveNext();
              if (result === false) {
                if (otherEnumerable === undefined) {
                  otherEnumerable = new crafity.Enumerable(enumerable);
                }
                otherEnumerator = otherEnumerable.getEnumerator();
                result = otherEnumerator.moveNext();
                switched = true;
              }
            } else {
              result = otherEnumerator.moveNext();
            }
  
            return result;
          },
          function resetInternal() {
            switched = false;
            return innerEnumerator.reset();
          }
        )
      );
    };
    this.selectMany = function selectManyInternal(func) {
      var innerEnumerator = self.getEnumerator()
        , childEnumerable, childEnumerator;
  
      return new crafity.Enumerable(
        new crafity.Enumerator(
          function getCurrentInternal() {
            return childEnumerator.getCurrent();
          },
          function moveNextInternal() {
            var movedNext = false, finished = false, childValue;
  
            if (childEnumerator !== undefined) {
              movedNext = childEnumerator.moveNext();
            }
  
            while (movedNext === false && finished === false) {
              childEnumerator = undefined;
              childEnumerable = undefined;
              finished = innerEnumerator.moveNext() === false;
              if (finished === false) {
                childValue = func(innerEnumerator.getCurrent());
                childEnumerable = new crafity.Enumerable(childValue);
                childEnumerator = childEnumerable.getEnumerator();
              }
              if (childEnumerator !== undefined) {
                movedNext = childEnumerator.moveNext();
              }
            }
  
            return movedNext;
          },
          function resetInternal() {
            childEnumerator = undefined;
            childEnumerable = undefined;
            return innerEnumerator.reset();
          }
        )
      );
    };
    this.recursive = function recursiveInternal(func) {
      var innerEnumerator = self.getEnumerator()
        , childEnumerable, childEnumerator;
      return new crafity.Enumerable(
        new crafity.Enumerator(
          function getCurrentInternal() {
            if (crafity.hasValue(childEnumerator)) {
              return childEnumerator.getCurrent();
            }
            return innerEnumerator.getCurrent();
          },
          function moveNextInternal() {
            var movedNext = false, finished = false;
  
            if (crafity.hasValue(childEnumerable) && crafity.hasNoValue(childEnumerator)) {
              childEnumerator = childEnumerable.getEnumerator();
            }
  
            if (crafity.hasValue(childEnumerator)) {
              movedNext = childEnumerator.moveNext();
            }
  
            if (movedNext === false && finished === false) {
              childEnumerator = undefined;
              childEnumerable = undefined;
              movedNext = innerEnumerator.moveNext();
              finished = !movedNext;
              if (finished === false) {
                var childValue = func(innerEnumerator.getCurrent());
                childEnumerable = new crafity.Enumerable(childValue).recursive(func);
              }
            }
  
            return movedNext;
          },
          function resetInternal() {
            childEnumerator = undefined;
            childEnumerable = undefined;
            return innerEnumerator.reset();
          }
        )
      );
    };
    /**
     * Where filters an enumerable by creating a new filtered enumerable
     * @param {Function} func A function that decides if a value is included
     * @returns {Enumerable} A new filtered enumerable
     */
    this.where = function whereInternal(func) {
      var innerEnumerator = self.getEnumerator();
      return new crafity.Enumerable(
        new crafity.Enumerator(
          function getCurrentInternal() {
            return innerEnumerator.getCurrent();
          },
          function moveNextInternal() {
            var moveNext = innerEnumerator.moveNext();
            while (moveNext && !func(innerEnumerator.getCurrent())) {
              moveNext = innerEnumerator.moveNext();
            }
            return moveNext;
          },
          function resetInternal() {
            return innerEnumerator.reset();
          }
        )
      );
    };
    /**
     * Take X number of items from the enumerable
     * @param {Number} number Number of items to take
     * @returns {Enumerable} A new enumerable containing the take logic
     */
    this.take = function takeInternal(number) {
      var innerEnumerator = self.getEnumerator();
      return new crafity.Enumerable(
        new crafity.Enumerator(
          function getCurrentInternal() {
            return innerEnumerator.getCurrent();
          },
          function moveNextInternal() {
            return innerEnumerator.getIndex() < number && innerEnumerator.moveNext();
          },
          function resetInternal() {
            return innerEnumerator.reset();
          }
        )
      );
    };
    /**
     * Skip X number of items in the enumerable
     * @param number Number of items to skip
     * @returns {Enumerable} A new enumerable containing the skip logic
     */
    this.skip = function skipInternal(number) {
      var innerEnumerator = self.getEnumerator();
      return new Enumerable(
        new Enumerator(
          function getCurrentInternal() {
            return innerEnumerator.getCurrent();
          },
          function moveNextInternal() {
            while (innerEnumerator.getIndex() < number && innerEnumerator.moveNext()) {
              innerEnumerator.__ = 1;
            }
            return innerEnumerator.moveNext();
          },
          function resetInternal() {
            return innerEnumerator.reset();
          }
        )
      );
    };
    /**
     * Loop thru all the items in an enumerable.
     * @param {Function} func This function will be called for every item
     */
    this.loop = function loopInternal(func) {
      var enumerator = self.getEnumerator();
      enumerator.reset();
      while (enumerator.moveNext()) {
        func(enumerator.getCurrent());
      }
    };
    /**
     * Aggregate an enumerable with a custom function
     * @param {Function} func A function containing the aggregagtion logic
     * @param {Object} seed The initial value to start the aggregation with
     * @returns {Object} The aggregated result
     */
    this.aggregate = function aggregateInternal(func, seed) {
      var result = seed;
      self.loop(function (value) {
        result = func(result, value);
      });
      return result;
    };
    /**
     * Collect all the values from an enumerable into an Array
     * @returns {Array} An array containing all the enumerable values
     */
    this.toArray = function toArrayInternal() {
      return self.aggregate(function (seed, value) {
        seed.push(value);
        return seed;
      }, []);
    };
    /**
     * Sum all the values in an enumerable
     * @returns {Number} The sum of the values
     */
    this.sum = function sumInternal() {
      return self.aggregate(function (seed, value) {
        return seed + value;
      }, 0);
    };
    /**
     * Count all the values in an enumerable
     * @returns {Number} The number of the values in the enumerable
     */
    this.count = function countInternal() {
      return self.aggregate(function (seed, value) {
        return seed + 1;
      }, 0);
    };
  
  }