text: /**
   * @file Iterator tools
   * @version v0.0.3
   * @author Adam Mill <hismajesty@theroyalwhee.com>
   * @copyright Copyright 2020-2021 Adam Mill
   * @license Apache-2.0
   */
  
  /**
   * Constants.
   * @ignore
   */
  const MAX = Number.MAX_SAFE_INTEGER;
  
  /**
   * Generator a range sequence.
   * @example
   * range(0, 10);     // From 0-10 step 1 (auto)
   * range(10, 0);     // From 10-0 step -1 (auto)
   * range(20);        // From 0-20 step 1 (auto)
   * range(3, 12, 3);  // From 3-12 step 3
   * @param {integer} from Starting value, inclusive.
   * @param {integer} to Ending value value, inclusive.
   * @param {integer} step The amount to advance by.
   * @yields {integer} The next step in the range.
   */
  function* range(from, to, step) {
    if(from !== undefined && to === undefined) {
      to = from;
      from = 0;
    }
    if(from === undefined) {
      from = 0;
    }
    if(to === undefined) {
      to = MAX;
    };
    if(step === undefined) {
      step = from < to ? 1 : -1;
    }
    const lt = step > 0;
    let current = from;
    while(lt ? current <= to : current >= to) {
      yield current;
      current += step;
    }
  }
  
  /**
   * Repeat a value.
   * @param {any} value Any value to repeat.
   * @param {integer} length Number of times to repat.
   * @yields {any} The repeated value.
   */
  function* repeat(value, length=MAX) {
    let idx = 0;
    while(idx < length) {
      yield value;
      idx += 1;
    }
  }
  
  /**
   * Limit wrapped iterator to a given length.
   * @param {iterable} iter The iterable to operator on.
   * @param {integer} length The length to limit wrapper iterable to.
   * @returns The iterable limited to specified length.
   */
  function* limit(iter, length) {
    let idx = 0;
    for(let value of iter) {
      if(idx >= length) {
        break;
      }
      yield value;
      idx += 1;
    }
  }
  
  /**
   * Concatinate iterators together.
   * @param  {...iterables} iters The iterators to concatinate.
   * @returns The resulting concatinated iterator.
   */
  function* concat(...iters) {
    for(let iter of iters) {
      for(let value of iter) {
        yield value;
      }
    }
  }
  
  /**
   * Build a function that takes the next item from an iterable.
   * That function returns the 'last' value when done.
   * @example
   * const take = taker([ 1, 2 ], 0);
   * const first = take();  // 1
   * const second = take(); // 2
   * const third = take();  // 0
   * const fourth = take(); // 0
   * @param {iterable} iter The iterable to operator on.
   * @param {any} last The value to return if at end.
   * @returns The function that takes the next item.
   */
  function taker(iter, last) {
    const it = iter[Symbol.iterator]();
    return function takeNext() {
      const { value, done } = it.next();
      if(done) {
        return last;
      } else {
        return value;
      }
    };
  }
  
  /**
   * Fibonacci sequence.
   * @param {number} initial The initial value.
   * @param {number} maximum The maximum value.
   * @returns An iterable fibonacci sequence.
   */
  function* fibonacci(initial=1) {
    let previous = 0;
    let current = initial;
    while(1) {
      yield current;
      [ previous, current ] = [ current, previous + current ];
    }
  }
  
  /**
   * Map values.
   * @param {iterable} iter The iterable to operator on.
   * @param {function} fn A function to transform/map each item.
   * @returns An iterator of mapped items.
   */
  function* map(iter, fn) {
    for(let value of iter) {
      yield fn(value);
    }
  }
  
  /**
   * Filter values.
   * @param {iterable} iter The iterable to operator on.
   * @param {function} fn A function to filter each item.
   * @returns An iterator of filtered items.
   */
  function* filter(iter, fn) {
    for(let value of iter) {
      if(fn(value)) {
        yield value;
      }
    }
  }
  
  /**
   * Slice a range out of an iterable.
   * @param {iterable} iter The iterable to operator on.
   * @param {integer} from The starting index.
   * @param {integer} to The ending index.
   * @returns An iterator of the sliced part.
   */
  function* slice(iter, from, to) {
    if(from !== undefined && to === undefined) {
      to = from;
      from = 0;
    }
    if(from === undefined) {
      from = 0;
    }
    if(to === undefined) {
      to = MAX;
    };
    let idx = 0;
    for(let item of iter) {
      if(idx > to) {
        break;
      }
      idx += 1;
      if(idx <= from) {
        continue;
      }
      yield item;
    }
  }
  
  /**
   * Advance an iterator by a given amount.
   * @param {iterator} iter The iterator to advance .
   * @param {integer} size The number of items to advance by.
   * @returns The advanced iterator.
   */
  function advance(iter, size) {
    return slice(iter, size, MAX);
  }
  
  /**
   * Exports.
   */
  module.exports = {
    // General.
    taker,
    // Transform the values.
    map,
    // Change the iteration.
    limit,
    filter,
    slice,
    advance,
    concat,
    // Create iterators.
    range,
    repeat,
    fibonacci,
  };
  