• js 对json数据进行检索 插件 linq.js


    有时界面需要很多数据。但是多次访问服务器效率很低,所以需要检索json数据,最好是像sql查询语句那种

     linq.js 插件

    LINQ,语言集成查询(Language Integrated Query)是一组用于c#和Visual Basic语言的扩展。它允许编写C#或者Visual Basic代码以查询数据库相同的方式操作内存数据。
    而Linq.js就是基于上面的机制,通过javascript来实现的。

    实例(https://www.cnblogs.com/landeanfen/p/4672542.html):
    //重复输出5个3
    Enumerable.Repeat(3).Take(5);//33333
    //输出10开始5个值
    Enumerable.Range(10,5);//10,11,12,13,14
    //随机
    Enumerable.Choice("a","b","c","d").Take(5)//随机输出a,b,c,d
    //输出大于7个数
    Enumerable.Range(1,10).Count("$>7")//3
    //输出指定位置的值
    Enumerable.Range(1,10).ElementAt(3)//4
    var arr = [
        {
            name:'abcd',
            item:{
                list:[1,2,3,4]
            }
        },
        {
            name:'123',
            item:{
                list:[3,4,5,6,7,8]
            }
        },
        {
            name:'你好',
            item:{
                list:[5,6,7,8,9]
            }
        }
    ]
    //选择name字段
    Enumerable.From(arr).Select('$.name');//abcd,123,你好
    //输出index为1的
    Enumerable.From(arr).Select('$.name').Where('v,i=>i==1');//123
    //输出所有的list
    Enumerable.From(arr).SelectMany('$.item.list');//123434567856789
    //输出去重的list
    Enumerable.From(arr).SelectMany('$.item.list').Distinct();//123456789
    //倒叙
    Enumerable.From(arr).SelectMany('$.item.list').Distinct().OrderByDescending();//987654321
    //分组
    Enumerable.From(arr).SelectMany('$.item.list').Distinct().GroupBy('$%3').Select("$.Key() + ':' + $.ToString('-')");//1:1-4-7,2:2-5-8,0:3-6-9

    重点是,引用了从jgit上下载的jslinq-master 下的js 文件无效,也可能是下载错了,最后引用的是https://www.bootcdn.cn/linq.js/ 这里的文件

    jquery.linq.js

    /*--------------------------------------------------------------------------
    * linq.js - LINQ for JavaScript
    * ver 2.2.0.2 (Jan. 21th, 2011)
    *
    * created and maintained by neuecc <ils@neue.cc>
    * licensed under Microsoft Public License(Ms-PL)
    * http://neue.cc/
    * http://linqjs.codeplex.com/
    *--------------------------------------------------------------------------*/
    jQuery.extend({ Enumerable: (function (){
        var Enumerable = function (getEnumerator)
        {
            this.GetEnumerator = getEnumerator;
        }
    
        // Generator
    
        Enumerable.Choice = function () // variable argument
        {
            var args = (arguments[0] instanceof Array) ? arguments[0] : arguments;
    
            return new Enumerable(function ()
            {
                return new IEnumerator(
                    Functions.Blank,
                    function ()
                    {
                        return this.Yield(args[Math.floor(Math.random() * args.length)]);
                    },
                    Functions.Blank);
            });
        }
    
        Enumerable.Cycle = function () // variable argument
        {
            var args = (arguments[0] instanceof Array) ? arguments[0] : arguments;
    
            return new Enumerable(function ()
            {
                var index = 0;
                return new IEnumerator(
                    Functions.Blank,
                    function ()
                    {
                        if (index >= args.length) index = 0;
                        return this.Yield(args[index++]);
                    },
                    Functions.Blank);
            });
        }
    
        Enumerable.Empty = function ()
        {
            return new Enumerable(function ()
            {
                return new IEnumerator(
                    Functions.Blank,
                    function () { return false; },
                    Functions.Blank);
            });
        }
    
        Enumerable.From = function (obj)
        {
            if (obj == null)
            {
                return Enumerable.Empty();
            }
            if (obj instanceof Enumerable)
            {
                return obj;
            }
            if (typeof obj == Types.Number || typeof obj == Types.Boolean)
            {
                return Enumerable.Repeat(obj, 1);
            }
            if (typeof obj == Types.String)
            {
                return new Enumerable(function ()
                {
                    var index = 0;
                    return new IEnumerator(
                        Functions.Blank,
                        function ()
                        {
                            return (index < obj.length) ? this.Yield(obj.charAt(index++)) : false;
                        },
                        Functions.Blank);
                });
            }
            if (typeof obj != Types.Function)
            {
                // array or array like object
                if (typeof obj.length == Types.Number)
                {
                    return new ArrayEnumerable(obj);
                }
    
                // JScript's IEnumerable
                if (!(obj instanceof Object) && Utils.IsIEnumerable(obj))
                {
                    return new Enumerable(function ()
                    {
                        var isFirst = true;
                        var enumerator;
                        return new IEnumerator(
                            function () { enumerator = new Enumerator(obj); },
                            function ()
                            {
                                if (isFirst) isFirst = false;
                                else enumerator.moveNext();
    
                                return (enumerator.atEnd()) ? false : this.Yield(enumerator.item());
                            },
                            Functions.Blank);
                    });
                }
            }
    
            // case function/object : Create KeyValuePair[]
            return new Enumerable(function ()
            {
                var array = [];
                var index = 0;
    
                return new IEnumerator(
                    function ()
                    {
                        for (var key in obj)
                        {
                            if (!(obj[key] instanceof Function))
                            {
                                array.push({ Key: key, Value: obj[key] });
                            }
                        }
                    },
                    function ()
                    {
                        return (index < array.length)
                            ? this.Yield(array[index++])
                            : false;
                    },
                    Functions.Blank);
            });
        },
    
        Enumerable.Return = function (element)
        {
            return Enumerable.Repeat(element, 1);
        }
    
        // Overload:function(input, pattern)
        // Overload:function(input, pattern, flags)
        Enumerable.Matches = function (input, pattern, flags)
        {
            if (flags == null) flags = "";
            if (pattern instanceof RegExp)
            {
                flags += (pattern.ignoreCase) ? "i" : "";
                flags += (pattern.multiline) ? "m" : "";
                pattern = pattern.source;
            }
            if (flags.indexOf("g") === -1) flags += "g";
    
            return new Enumerable(function ()
            {
                var regex;
                return new IEnumerator(
                    function () { regex = new RegExp(pattern, flags) },
                    function ()
                    {
                        var match = regex.exec(input);
                        return (match) ? this.Yield(match) : false;
                    },
                    Functions.Blank);
            });
        }
    
        // Overload:function(start, count)
        // Overload:function(start, count, step)
        Enumerable.Range = function (start, count, step)
        {
            if (step == null) step = 1;
            return Enumerable.ToInfinity(start, step).Take(count);
        }
    
        // Overload:function(start, count)
        // Overload:function(start, count, step)
        Enumerable.RangeDown = function (start, count, step)
        {
            if (step == null) step = 1;
            return Enumerable.ToNegativeInfinity(start, step).Take(count);
        }
    
        // Overload:function(start, to)
        // Overload:function(start, to, step)
        Enumerable.RangeTo = function (start, to, step)
        {
            if (step == null) step = 1;
            return (start < to)
                ? Enumerable.ToInfinity(start, step).TakeWhile(function (i) { return i <= to; })
                : Enumerable.ToNegativeInfinity(start, step).TakeWhile(function (i) { return i >= to; })
        }
    
        // Overload:function(obj)
        // Overload:function(obj, num)
        Enumerable.Repeat = function (obj, num)
        {
            if (num != null) return Enumerable.Repeat(obj).Take(num);
    
            return new Enumerable(function ()
            {
                return new IEnumerator(
                    Functions.Blank,
                    function () { return this.Yield(obj); },
                    Functions.Blank);
            });
        }
    
        Enumerable.RepeatWithFinalize = function (initializer, finalizer)
        {
            initializer = Utils.CreateLambda(initializer);
            finalizer = Utils.CreateLambda(finalizer);
    
            return new Enumerable(function ()
            {
                var element;
                return new IEnumerator(
                    function () { element = initializer(); },
                    function () { return this.Yield(element); },
                    function ()
                    {
                        if (element != null)
                        {
                            finalizer(element);
                            element = null;
                        }
                    });
            });
        }
    
        // Overload:function(func)
        // Overload:function(func, count)
        Enumerable.Generate = function (func, count)
        {
            if (count != null) return Enumerable.Generate(func).Take(count);
            func = Utils.CreateLambda(func);
    
            return new Enumerable(function ()
            {
                return new IEnumerator(
                    Functions.Blank,
                    function () { return this.Yield(func()); },
                    Functions.Blank);
            });
        }
    
        // Overload:function()
        // Overload:function(start)
        // Overload:function(start, step)
        Enumerable.ToInfinity = function (start, step)
        {
            if (start == null) start = 0;
            if (step == null) step = 1;
    
            return new Enumerable(function ()
            {
                var value;
                return new IEnumerator(
                    function () { value = start - step },
                    function () { return this.Yield(value += step); },
                    Functions.Blank);
            });
        }
    
        // Overload:function()
        // Overload:function(start)
        // Overload:function(start, step)
        Enumerable.ToNegativeInfinity = function (start, step)
        {
            if (start == null) start = 0;
            if (step == null) step = 1;
    
            return new Enumerable(function ()
            {
                var value;
                return new IEnumerator(
                    function () { value = start + step },
                    function () { return this.Yield(value -= step); },
                    Functions.Blank);
            });
        }
    
        Enumerable.Unfold = function (seed, func)
        {
            func = Utils.CreateLambda(func);
    
            return new Enumerable(function ()
            {
                var isFirst = true;
                var value;
                return new IEnumerator(
                    Functions.Blank,
                    function ()
                    {
                        if (isFirst)
                        {
                            isFirst = false;
                            value = seed;
                            return this.Yield(value);
                        }
                        value = func(value);
                        return this.Yield(value);
                    },
                    Functions.Blank);
            });
        }
    
        // Extension Methods
    
        Enumerable.prototype =
        {
            /* Projection and Filtering Methods */
    
            // Overload:function(func)
            // Overload:function(func, resultSelector<element>)
            // Overload:function(func, resultSelector<element, nestLevel>)
            CascadeBreadthFirst: function (func, resultSelector)
            {
                var source = this;
                func = Utils.CreateLambda(func);
                resultSelector = Utils.CreateLambda(resultSelector);
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var nestLevel = 0;
                    var buffer = [];
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            while (true)
                            {
                                if (enumerator.MoveNext())
                                {
                                    buffer.push(enumerator.Current());
                                    return this.Yield(resultSelector(enumerator.Current(), nestLevel));
                                }
    
                                var next = Enumerable.From(buffer).SelectMany(function (x) { return func(x); });
                                if (!next.Any())
                                {
                                    return false;
                                }
                                else
                                {
                                    nestLevel++;
                                    buffer = [];
                                    Utils.Dispose(enumerator);
                                    enumerator = next.GetEnumerator();
                                }
                            }
                        },
                        function () { Utils.Dispose(enumerator); });
                });
            },
    
            // Overload:function(func)
            // Overload:function(func, resultSelector<element>)
            // Overload:function(func, resultSelector<element, nestLevel>)
            CascadeDepthFirst: function (func, resultSelector)
            {
                var source = this;
                func = Utils.CreateLambda(func);
                resultSelector = Utils.CreateLambda(resultSelector);
    
                return new Enumerable(function ()
                {
                    var enumeratorStack = [];
                    var enumerator;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            while (true)
                            {
                                if (enumerator.MoveNext())
                                {
                                    var value = resultSelector(enumerator.Current(), enumeratorStack.length);
                                    enumeratorStack.push(enumerator);
                                    enumerator = Enumerable.From(func(enumerator.Current())).GetEnumerator();
                                    return this.Yield(value);
                                }
    
                                if (enumeratorStack.length <= 0) return false;
                                Utils.Dispose(enumerator);
                                enumerator = enumeratorStack.pop();
                            }
                        },
                        function ()
                        {
                            try { Utils.Dispose(enumerator); }
                            finally { Enumerable.From(enumeratorStack).ForEach(function (s) { s.Dispose(); }) }
                        });
                });
            },
    
            Flatten: function ()
            {
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var middleEnumerator = null;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            while (true)
                            {
                                if (middleEnumerator != null)
                                {
                                    if (middleEnumerator.MoveNext())
                                    {
                                        return this.Yield(middleEnumerator.Current());
                                    }
                                    else
                                    {
                                        middleEnumerator = null;
                                    }
                                }
    
                                if (enumerator.MoveNext())
                                {
                                    if (enumerator.Current() instanceof Array)
                                    {
                                        Utils.Dispose(middleEnumerator);
                                        middleEnumerator = Enumerable.From(enumerator.Current())
                                            .SelectMany(Functions.Identity)
                                            .Flatten()
                                            .GetEnumerator();
                                        continue;
                                    }
                                    else
                                    {
                                        return this.Yield(enumerator.Current());
                                    }
                                }
    
                                return false;
                            }
                        },
                        function ()
                        {
                            try { Utils.Dispose(enumerator); }
                            finally { Utils.Dispose(middleEnumerator); }
                        });
                });
            },
    
            Pairwise: function (selector)
            {
                var source = this;
                selector = Utils.CreateLambda(selector);
    
                return new Enumerable(function ()
                {
                    var enumerator;
    
                    return new IEnumerator(
                        function ()
                        {
                            enumerator = source.GetEnumerator();
                            enumerator.MoveNext();
                        },
                        function ()
                        {
                            var prev = enumerator.Current();
                            return (enumerator.MoveNext())
                                ? this.Yield(selector(prev, enumerator.Current()))
                                : false;
                        },
                        function () { Utils.Dispose(enumerator); });
                });
            },
    
            // Overload:function(func)
            // Overload:function(seed,func<value,element>)
            // Overload:function(seed,func<value,element>,resultSelector)
            Scan: function (seed, func, resultSelector)
            {
                if (resultSelector != null) return this.Scan(seed, func).Select(resultSelector);
    
                var isUseSeed;
                if (func == null)
                {
                    func = Utils.CreateLambda(seed); // arguments[0]
                    isUseSeed = false;
                }
                else
                {
                    func = Utils.CreateLambda(func);
                    isUseSeed = true;
                }
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var value;
                    var isFirst = true;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            if (isFirst)
                            {
                                isFirst = false;
                                if (!isUseSeed)
                                {
                                    if (enumerator.MoveNext())
                                    {
                                        return this.Yield(value = enumerator.Current());
                                    }
                                }
                                else
                                {
                                    return this.Yield(value = seed);
                                }
                            }
    
                            return (enumerator.MoveNext())
                                ? this.Yield(value = func(value, enumerator.Current()))
                                : false;
                        },
                        function () { Utils.Dispose(enumerator); });
                });
            },
    
            // Overload:function(selector<element>)
            // Overload:function(selector<element,index>)
            Select: function (selector)
            {
                var source = this;
                selector = Utils.CreateLambda(selector);
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var index = 0;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            return (enumerator.MoveNext())
                                ? this.Yield(selector(enumerator.Current(), index++))
                                : false;
                        },
                        function () { Utils.Dispose(enumerator); })
                });
            },
    
            // Overload:function(collectionSelector<element>)
            // Overload:function(collectionSelector<element,index>)
            // Overload:function(collectionSelector<element>,resultSelector)
            // Overload:function(collectionSelector<element,index>,resultSelector)
            SelectMany: function (collectionSelector, resultSelector)
            {
                var source = this;
                collectionSelector = Utils.CreateLambda(collectionSelector);
                if (resultSelector == null) resultSelector = function (a, b) { return b; }
                resultSelector = Utils.CreateLambda(resultSelector);
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var middleEnumerator = undefined;
                    var index = 0;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            if (middleEnumerator === undefined)
                            {
                                if (!enumerator.MoveNext()) return false;
                            }
                            do
                            {
                                if (middleEnumerator == null)
                                {
                                    var middleSeq = collectionSelector(enumerator.Current(), index++);
                                    middleEnumerator = Enumerable.From(middleSeq).GetEnumerator();
                                }
                                if (middleEnumerator.MoveNext())
                                {
                                    return this.Yield(resultSelector(enumerator.Current(), middleEnumerator.Current()));
                                }
                                Utils.Dispose(middleEnumerator);
                                middleEnumerator = null;
                            } while (enumerator.MoveNext())
                            return false;
                        },
                        function ()
                        {
                            try { Utils.Dispose(enumerator); }
                            finally { Utils.Dispose(middleEnumerator); }
                        })
                });
            },
    
            // Overload:function(predicate<element>)
            // Overload:function(predicate<element,index>)
            Where: function (predicate)
            {
                predicate = Utils.CreateLambda(predicate);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var index = 0;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            while (enumerator.MoveNext())
                            {
                                if (predicate(enumerator.Current(), index++))
                                {
                                    return this.Yield(enumerator.Current());
                                }
                            }
                            return false;
                        },
                        function () { Utils.Dispose(enumerator); })
                });
            },
    
            OfType: function (type)
            {
                var typeName;
                switch (type)
                {
                    case Number: typeName = Types.Number; break;
                    case String: typeName = Types.String; break;
                    case Boolean: typeName = Types.Boolean; break;
                    case Function: typeName = Types.Function; break;
                    default: typeName = null; break;
                }
                return (typeName === null)
                    ? this.Where(function (x) { return x instanceof type })
                    : this.Where(function (x) { return typeof x === typeName });
            },
    
            // Overload:function(second,selector<outer,inner>)
            // Overload:function(second,selector<outer,inner,index>)
            Zip: function (second, selector)
            {
                selector = Utils.CreateLambda(selector);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var firstEnumerator;
                    var secondEnumerator;
                    var index = 0;
    
                    return new IEnumerator(
                        function ()
                        {
                            firstEnumerator = source.GetEnumerator();
                            secondEnumerator = Enumerable.From(second).GetEnumerator();
                        },
                        function ()
                        {
                            if (firstEnumerator.MoveNext() && secondEnumerator.MoveNext())
                            {
                                return this.Yield(selector(firstEnumerator.Current(), secondEnumerator.Current(), index++));
                            }
                            return false;
                        },
                        function ()
                        {
                            try { Utils.Dispose(firstEnumerator); }
                            finally { Utils.Dispose(secondEnumerator); }
                        })
                });
            },
    
            /* Join Methods */
    
            // Overload:function (inner, outerKeySelector, innerKeySelector, resultSelector)
            // Overload:function (inner, outerKeySelector, innerKeySelector, resultSelector, compareSelector)
            Join: function (inner, outerKeySelector, innerKeySelector, resultSelector, compareSelector)
            {
                outerKeySelector = Utils.CreateLambda(outerKeySelector);
                innerKeySelector = Utils.CreateLambda(innerKeySelector);
                resultSelector = Utils.CreateLambda(resultSelector);
                compareSelector = Utils.CreateLambda(compareSelector);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var outerEnumerator;
                    var lookup;
                    var innerElements = null;
                    var innerCount = 0;
    
                    return new IEnumerator(
                        function ()
                        {
                            outerEnumerator = source.GetEnumerator();
                            lookup = Enumerable.From(inner).ToLookup(innerKeySelector, Functions.Identity, compareSelector);
                        },
                        function ()
                        {
                            while (true)
                            {
                                if (innerElements != null)
                                {
                                    var innerElement = innerElements[innerCount++];
                                    if (innerElement !== undefined)
                                    {
                                        return this.Yield(resultSelector(outerEnumerator.Current(), innerElement));
                                    }
    
                                    innerElement = null;
                                    innerCount = 0;
                                }
    
                                if (outerEnumerator.MoveNext())
                                {
                                    var key = outerKeySelector(outerEnumerator.Current());
                                    innerElements = lookup.Get(key).ToArray();
                                }
                                else
                                {
                                    return false;
                                }
                            }
                        },
                        function () { Utils.Dispose(outerEnumerator); })
                });
            },
    
            // Overload:function (inner, outerKeySelector, innerKeySelector, resultSelector)
            // Overload:function (inner, outerKeySelector, innerKeySelector, resultSelector, compareSelector)
            GroupJoin: function (inner, outerKeySelector, innerKeySelector, resultSelector, compareSelector)
            {
                outerKeySelector = Utils.CreateLambda(outerKeySelector);
                innerKeySelector = Utils.CreateLambda(innerKeySelector);
                resultSelector = Utils.CreateLambda(resultSelector);
                compareSelector = Utils.CreateLambda(compareSelector);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator = source.GetEnumerator();
                    var lookup = null;
    
                    return new IEnumerator(
                        function ()
                        {
                            enumerator = source.GetEnumerator();
                            lookup = Enumerable.From(inner).ToLookup(innerKeySelector, Functions.Identity, compareSelector);
                        },
                        function ()
                        {
                            if (enumerator.MoveNext())
                            {
                                var innerElement = lookup.Get(outerKeySelector(enumerator.Current()));
                                return this.Yield(resultSelector(enumerator.Current(), innerElement));
                            }
                            return false;
                        },
                        function () { Utils.Dispose(enumerator); })
                });
            },
    
            /* Set Methods */
    
            All: function (predicate)
            {
                predicate = Utils.CreateLambda(predicate);
    
                var result = true;
                this.ForEach(function (x)
                {
                    if (!predicate(x))
                    {
                        result = false;
                        return false; // break
                    }
                });
                return result;
            },
    
            // Overload:function()
            // Overload:function(predicate)
            Any: function (predicate)
            {
                predicate = Utils.CreateLambda(predicate);
    
                var enumerator = this.GetEnumerator();
                try
                {
                    if (arguments.length == 0) return enumerator.MoveNext(); // case:function()
    
                    while (enumerator.MoveNext()) // case:function(predicate)
                    {
                        if (predicate(enumerator.Current())) return true;
                    }
                    return false;
                }
                finally { Utils.Dispose(enumerator); }
            },
    
            Concat: function (second)
            {
                var source = this;
    
                return new Enumerable(function ()
                {
                    var firstEnumerator;
                    var secondEnumerator;
    
                    return new IEnumerator(
                        function () { firstEnumerator = source.GetEnumerator(); },
                        function ()
                        {
                            if (secondEnumerator == null)
                            {
                                if (firstEnumerator.MoveNext()) return this.Yield(firstEnumerator.Current());
                                secondEnumerator = Enumerable.From(second).GetEnumerator();
                            }
                            if (secondEnumerator.MoveNext()) return this.Yield(secondEnumerator.Current());
                            return false;
                        },
                        function ()
                        {
                            try { Utils.Dispose(firstEnumerator); }
                            finally { Utils.Dispose(secondEnumerator); }
                        })
                });
            },
    
            Insert: function (index, second)
            {
                var source = this;
    
                return new Enumerable(function ()
                {
                    var firstEnumerator;
                    var secondEnumerator;
                    var count = 0;
                    var isEnumerated = false;
    
                    return new IEnumerator(
                        function ()
                        {
                            firstEnumerator = source.GetEnumerator();
                            secondEnumerator = Enumerable.From(second).GetEnumerator();
                        },
                        function ()
                        {
                            if (count == index && secondEnumerator.MoveNext())
                            {
                                isEnumerated = true;
                                return this.Yield(secondEnumerator.Current());
                            }
                            if (firstEnumerator.MoveNext())
                            {
                                count++;
                                return this.Yield(firstEnumerator.Current());
                            }
                            if (!isEnumerated && secondEnumerator.MoveNext())
                            {
                                return this.Yield(secondEnumerator.Current());
                            }
                            return false;
                        },
                        function ()
                        {
                            try { Utils.Dispose(firstEnumerator); }
                            finally { Utils.Dispose(secondEnumerator); }
                        })
                });
            },
    
            Alternate: function (value)
            {
                value = Enumerable.Return(value);
                return this.SelectMany(function (elem)
                {
                    return Enumerable.Return(elem).Concat(value);
                }).TakeExceptLast();
            },
    
            // Overload:function(value)
            // Overload:function(value, compareSelector)
            Contains: function (value, compareSelector)
            {
                compareSelector = Utils.CreateLambda(compareSelector);
                var enumerator = this.GetEnumerator();
                try
                {
                    while (enumerator.MoveNext())
                    {
                        if (compareSelector(enumerator.Current()) === value) return true;
                    }
                    return false;
                }
                finally { Utils.Dispose(enumerator) }
            },
    
            DefaultIfEmpty: function (defaultValue)
            {
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var isFirst = true;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            if (enumerator.MoveNext())
                            {
                                isFirst = false;
                                return this.Yield(enumerator.Current());
                            }
                            else if (isFirst)
                            {
                                isFirst = false;
                                return this.Yield(defaultValue);
                            }
                            return false;
                        },
                        function () { Utils.Dispose(enumerator); })
                });
            },
    
            // Overload:function()
            // Overload:function(compareSelector)
            Distinct: function (compareSelector)
            {
                return this.Except(Enumerable.Empty(), compareSelector);
            },
    
            // Overload:function(second)
            // Overload:function(second, compareSelector)
            Except: function (second, compareSelector)
            {
                compareSelector = Utils.CreateLambda(compareSelector);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var keys;
    
                    return new IEnumerator(
                        function ()
                        {
                            enumerator = source.GetEnumerator();
                            keys = new Dictionary(compareSelector);
                            Enumerable.From(second).ForEach(function (key) { keys.Add(key); });
                        },
                        function ()
                        {
                            while (enumerator.MoveNext())
                            {
                                var current = enumerator.Current();
                                if (!keys.Contains(current))
                                {
                                    keys.Add(current);
                                    return this.Yield(current);
                                }
                            }
                            return false;
                        },
                        function () { Utils.Dispose(enumerator); })
                });
            },
    
            // Overload:function(second)
            // Overload:function(second, compareSelector)
            Intersect: function (second, compareSelector)
            {
                compareSelector = Utils.CreateLambda(compareSelector);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var keys;
                    var outs;
    
                    return new IEnumerator(
                        function ()
                        {
                            enumerator = source.GetEnumerator();
    
                            keys = new Dictionary(compareSelector);
                            Enumerable.From(second).ForEach(function (key) { keys.Add(key); });
                            outs = new Dictionary(compareSelector);
                        },
                        function ()
                        {
                            while (enumerator.MoveNext())
                            {
                                var current = enumerator.Current();
                                if (!outs.Contains(current) && keys.Contains(current))
                                {
                                    outs.Add(current);
                                    return this.Yield(current);
                                }
                            }
                            return false;
                        },
                        function () { Utils.Dispose(enumerator); })
                });
            },
    
            // Overload:function(second)
            // Overload:function(second, compareSelector)
            SequenceEqual: function (second, compareSelector)
            {
                compareSelector = Utils.CreateLambda(compareSelector);
    
                var firstEnumerator = this.GetEnumerator();
                try
                {
                    var secondEnumerator = Enumerable.From(second).GetEnumerator();
                    try
                    {
                        while (firstEnumerator.MoveNext())
                        {
                            if (!secondEnumerator.MoveNext()
                                || compareSelector(firstEnumerator.Current()) !== compareSelector(secondEnumerator.Current()))
                            {
                                return false;
                            }
                        }
    
                        if (secondEnumerator.MoveNext()) return false;
                        return true;
                    }
                    finally { Utils.Dispose(secondEnumerator); }
                }
                finally { Utils.Dispose(firstEnumerator); }
            },
    
            Union: function (second, compareSelector)
            {
                compareSelector = Utils.CreateLambda(compareSelector);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var firstEnumerator;
                    var secondEnumerator;
                    var keys;
    
                    return new IEnumerator(
                        function ()
                        {
                            firstEnumerator = source.GetEnumerator();
                            keys = new Dictionary(compareSelector);
                        },
                        function ()
                        {
                            var current;
                            if (secondEnumerator === undefined)
                            {
                                while (firstEnumerator.MoveNext())
                                {
                                    current = firstEnumerator.Current();
                                    if (!keys.Contains(current))
                                    {
                                        keys.Add(current);
                                        return this.Yield(current);
                                    }
                                }
                                secondEnumerator = Enumerable.From(second).GetEnumerator();
                            }
                            while (secondEnumerator.MoveNext())
                            {
                                current = secondEnumerator.Current();
                                if (!keys.Contains(current))
                                {
                                    keys.Add(current);
                                    return this.Yield(current);
                                }
                            }
                            return false;
                        },
                        function ()
                        {
                            try { Utils.Dispose(firstEnumerator); }
                            finally { Utils.Dispose(secondEnumerator); }
                        })
                });
            },
    
            /* Ordering Methods */
    
            OrderBy: function (keySelector)
            {
                return new OrderedEnumerable(this, keySelector, false);
            },
    
            OrderByDescending: function (keySelector)
            {
                return new OrderedEnumerable(this, keySelector, true);
            },
    
            Reverse: function ()
            {
                var source = this;
    
                return new Enumerable(function ()
                {
                    var buffer;
                    var index;
    
                    return new IEnumerator(
                        function ()
                        {
                            buffer = source.ToArray();
                            index = buffer.length;
                        },
                        function ()
                        {
                            return (index > 0)
                                ? this.Yield(buffer[--index])
                                : false;
                        },
                        Functions.Blank)
                });
            },
    
            Shuffle: function ()
            {
                var source = this;
    
                return new Enumerable(function ()
                {
                    var buffer;
    
                    return new IEnumerator(
                        function () { buffer = source.ToArray(); },
                        function ()
                        {
                            if (buffer.length > 0)
                            {
                                var i = Math.floor(Math.random() * buffer.length);
                                return this.Yield(buffer.splice(i, 1)[0]);
                            }
                            return false;
                        },
                        Functions.Blank)
                });
            },
    
            /* Grouping Methods */
    
            // Overload:function(keySelector)
            // Overload:function(keySelector,elementSelector)
            // Overload:function(keySelector,elementSelector,resultSelector)
            // Overload:function(keySelector,elementSelector,resultSelector,compareSelector)
            GroupBy: function (keySelector, elementSelector, resultSelector, compareSelector)
            {
                var source = this;
                keySelector = Utils.CreateLambda(keySelector);
                elementSelector = Utils.CreateLambda(elementSelector);
                if (resultSelector != null) resultSelector = Utils.CreateLambda(resultSelector);
                compareSelector = Utils.CreateLambda(compareSelector);
    
                return new Enumerable(function ()
                {
                    var enumerator;
    
                    return new IEnumerator(
                        function ()
                        {
                            enumerator = source.ToLookup(keySelector, elementSelector, compareSelector)
                                .ToEnumerable()
                                .GetEnumerator();
                        },
                        function ()
                        {
                            while (enumerator.MoveNext())
                            {
                                return (resultSelector == null)
                                    ? this.Yield(enumerator.Current())
                                    : this.Yield(resultSelector(enumerator.Current().Key(), enumerator.Current()));
                            }
                            return false;
                        },
                        function () { Utils.Dispose(enumerator); })
                });
            },
    
            // Overload:function(keySelector)
            // Overload:function(keySelector,elementSelector)
            // Overload:function(keySelector,elementSelector,resultSelector)
            // Overload:function(keySelector,elementSelector,resultSelector,compareSelector)
            PartitionBy: function (keySelector, elementSelector, resultSelector, compareSelector)
            {
    
                var source = this;
                keySelector = Utils.CreateLambda(keySelector);
                elementSelector = Utils.CreateLambda(elementSelector);
                compareSelector = Utils.CreateLambda(compareSelector);
                var hasResultSelector;
                if (resultSelector == null)
                {
                    hasResultSelector = false;
                    resultSelector = function (key, group) { return new Grouping(key, group) }
                }
                else
                {
                    hasResultSelector = true;
                    resultSelector = Utils.CreateLambda(resultSelector);
                }
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var key;
                    var compareKey;
                    var group = [];
    
                    return new IEnumerator(
                        function ()
                        {
                            enumerator = source.GetEnumerator();
                            if (enumerator.MoveNext())
                            {
                                key = keySelector(enumerator.Current());
                                compareKey = compareSelector(key);
                                group.push(elementSelector(enumerator.Current()));
                            }
                        },
                        function ()
                        {
                            var hasNext;
                            while ((hasNext = enumerator.MoveNext()) == true)
                            {
                                if (compareKey === compareSelector(keySelector(enumerator.Current())))
                                {
                                    group.push(elementSelector(enumerator.Current()));
                                }
                                else break;
                            }
    
                            if (group.length > 0)
                            {
                                var result = (hasResultSelector)
                                    ? resultSelector(key, Enumerable.From(group))
                                    : resultSelector(key, group);
                                if (hasNext)
                                {
                                    key = keySelector(enumerator.Current());
                                    compareKey = compareSelector(key);
                                    group = [elementSelector(enumerator.Current())];
                                }
                                else group = [];
    
                                return this.Yield(result);
                            }
    
                            return false;
                        },
                        function () { Utils.Dispose(enumerator); })
                });
            },
    
            BufferWithCount: function (count)
            {
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
    
                    return new IEnumerator(
                    function () { enumerator = source.GetEnumerator(); },
                    function ()
                    {
                        var array = [];
                        var index = 0;
                        while (enumerator.MoveNext())
                        {
                            array.push(enumerator.Current());
                            if (++index >= count) return this.Yield(array);
                        }
                        if (array.length > 0) return this.Yield(array);
                        return false;
                    },
                    function () { Utils.Dispose(enumerator); })
                });
            },
    
            /* Aggregate Methods */
    
            // Overload:function(func)
            // Overload:function(seed,func)
            // Overload:function(seed,func,resultSelector)
            Aggregate: function (seed, func, resultSelector)
            {
                return this.Scan(seed, func, resultSelector).Last();
            },
    
            // Overload:function()
            // Overload:function(selector)
            Average: function (selector)
            {
                selector = Utils.CreateLambda(selector);
    
                var sum = 0;
                var count = 0;
                this.ForEach(function (x)
                {
                    sum += selector(x);
                    ++count;
                });
    
                return sum / count;
            },
    
            // Overload:function()
            // Overload:function(predicate)
            Count: function (predicate)
            {
                predicate = (predicate == null) ? Functions.True : Utils.CreateLambda(predicate);
    
                var count = 0;
                this.ForEach(function (x, i)
                {
                    if (predicate(x, i)) ++count;
                });
                return count;
            },
    
            // Overload:function()
            // Overload:function(selector)
            Max: function (selector)
            {
                if (selector == null) selector = Functions.Identity;
                return this.Select(selector).Aggregate(function (a, b) { return (a > b) ? a : b; });
            },
    
            // Overload:function()
            // Overload:function(selector)
            Min: function (selector)
            {
                if (selector == null) selector = Functions.Identity;
                return this.Select(selector).Aggregate(function (a, b) { return (a < b) ? a : b; });
            },
    
            MaxBy: function (keySelector)
            {
                keySelector = Utils.CreateLambda(keySelector);
                return this.Aggregate(function (a, b) { return (keySelector(a) > keySelector(b)) ? a : b });
            },
    
            MinBy: function (keySelector)
            {
                keySelector = Utils.CreateLambda(keySelector);
                return this.Aggregate(function (a, b) { return (keySelector(a) < keySelector(b)) ? a : b });
            },
    
            // Overload:function()
            // Overload:function(selector)
            Sum: function (selector)
            {
                if (selector == null) selector = Functions.Identity;
                return this.Select(selector).Aggregate(0, function (a, b) { return a + b; });
            },
    
            /* Paging Methods */
    
            ElementAt: function (index)
            {
                var value;
                var found = false;
                this.ForEach(function (x, i)
                {
                    if (i == index)
                    {
                        value = x;
                        found = true;
                        return false;
                    }
                });
    
                if (!found) throw new Error("index is less than 0 or greater than or equal to the number of elements in source.");
                return value;
            },
    
            ElementAtOrDefault: function (index, defaultValue)
            {
                var value;
                var found = false;
                this.ForEach(function (x, i)
                {
                    if (i == index)
                    {
                        value = x;
                        found = true;
                        return false;
                    }
                });
    
                return (!found) ? defaultValue : value;
            },
    
            // Overload:function()
            // Overload:function(predicate)
            First: function (predicate)
            {
                if (predicate != null) return this.Where(predicate).First();
    
                var value;
                var found = false;
                this.ForEach(function (x)
                {
                    value = x;
                    found = true;
                    return false;
                });
    
                if (!found) throw new Error("First:No element satisfies the condition.");
                return value;
            },
    
            // Overload:function(defaultValue)
            // Overload:function(defaultValue,predicate)
            FirstOrDefault: function (defaultValue, predicate)
            {
                if (predicate != null) return this.Where(predicate).FirstOrDefault(defaultValue);
    
                var value;
                var found = false;
                this.ForEach(function (x)
                {
                    value = x;
                    found = true;
                    return false;
                });
                return (!found) ? defaultValue : value;
            },
    
            // Overload:function()
            // Overload:function(predicate)
            Last: function (predicate)
            {
                if (predicate != null) return this.Where(predicate).Last();
    
                var value;
                var found = false;
                this.ForEach(function (x)
                {
                    found = true;
                    value = x;
                });
    
                if (!found) throw new Error("Last:No element satisfies the condition.");
                return value;
            },
    
            // Overload:function(defaultValue)
            // Overload:function(defaultValue,predicate)
            LastOrDefault: function (defaultValue, predicate)
            {
                if (predicate != null) return this.Where(predicate).LastOrDefault(defaultValue);
    
                var value;
                var found = false;
                this.ForEach(function (x)
                {
                    found = true;
                    value = x;
                });
                return (!found) ? defaultValue : value;
            },
    
            // Overload:function()
            // Overload:function(predicate)
            Single: function (predicate)
            {
                if (predicate != null) return this.Where(predicate).Single();
    
                var value;
                var found = false;
                this.ForEach(function (x)
                {
                    if (!found)
                    {
                        found = true;
                        value = x;
                    }
                    else throw new Error("Single:sequence contains more than one element.");
                });
    
                if (!found) throw new Error("Single:No element satisfies the condition.");
                return value;
            },
    
            // Overload:function(defaultValue)
            // Overload:function(defaultValue,predicate)
            SingleOrDefault: function (defaultValue, predicate)
            {
                if (predicate != null) return this.Where(predicate).SingleOrDefault(defaultValue);
    
                var value;
                var found = false;
                this.ForEach(function (x)
                {
                    if (!found)
                    {
                        found = true;
                        value = x;
                    }
                    else throw new Error("Single:sequence contains more than one element.");
                });
    
                return (!found) ? defaultValue : value;
            },
    
            Skip: function (count)
            {
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var index = 0;
    
                    return new IEnumerator(
                        function ()
                        {
                            enumerator = source.GetEnumerator();
                            while (index++ < count && enumerator.MoveNext()) { };
                        },
                        function ()
                        {
                            return (enumerator.MoveNext())
                                ? this.Yield(enumerator.Current())
                                : false;
                        },
                        function () { Utils.Dispose(enumerator); })
                });
            },
    
            // Overload:function(predicate<element>)
            // Overload:function(predicate<element,index>)
            SkipWhile: function (predicate)
            {
                predicate = Utils.CreateLambda(predicate);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var index = 0;
                    var isSkipEnd = false;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            while (!isSkipEnd)
                            {
                                if (enumerator.MoveNext())
                                {
                                    if (!predicate(enumerator.Current(), index++))
                                    {
                                        isSkipEnd = true;
                                        return this.Yield(enumerator.Current());
                                    }
                                    continue;
                                }
                                else return false;
                            }
    
                            return (enumerator.MoveNext())
                                ? this.Yield(enumerator.Current())
                                : false;
    
                        },
                        function () { Utils.Dispose(enumerator); });
                });
            },
    
            Take: function (count)
            {
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var index = 0;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            return (index++ < count && enumerator.MoveNext())
                                ? this.Yield(enumerator.Current())
                                : false;
                        },
                        function () { Utils.Dispose(enumerator); }
                    )
                });
            },
    
            // Overload:function(predicate<element>)
            // Overload:function(predicate<element,index>)
            TakeWhile: function (predicate)
            {
                predicate = Utils.CreateLambda(predicate);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var index = 0;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            return (enumerator.MoveNext() && predicate(enumerator.Current(), index++))
                                ? this.Yield(enumerator.Current())
                                : false;
                        },
                        function () { Utils.Dispose(enumerator); });
                });
            },
    
            // Overload:function()
            // Overload:function(count)
            TakeExceptLast: function (count)
            {
                if (count == null) count = 1;
                var source = this;
    
                return new Enumerable(function ()
                {
                    if (count <= 0) return source.GetEnumerator(); // do nothing
    
                    var enumerator;
                    var q = [];
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            while (enumerator.MoveNext())
                            {
                                if (q.length == count)
                                {
                                    q.push(enumerator.Current());
                                    return this.Yield(q.shift());
                                }
                                q.push(enumerator.Current());
                            }
                            return false;
                        },
                        function () { Utils.Dispose(enumerator); });
                });
            },
    
            TakeFromLast: function (count)
            {
                if (count <= 0 || count == null) return Enumerable.Empty();
                var source = this;
    
                return new Enumerable(function ()
                {
                    var sourceEnumerator;
                    var enumerator;
                    var q = [];
    
                    return new IEnumerator(
                        function () { sourceEnumerator = source.GetEnumerator(); },
                        function ()
                        {
                            while (sourceEnumerator.MoveNext())
                            {
                                if (q.length == count) q.shift()
                                q.push(sourceEnumerator.Current());
                            }
                            if (enumerator == null)
                            {
                                enumerator = Enumerable.From(q).GetEnumerator();
                            }
                            return (enumerator.MoveNext())
                                ? this.Yield(enumerator.Current())
                                : false;
                        },
                        function () { Utils.Dispose(enumerator); });
                });
            },
    
            IndexOf: function (item)
            {
                var found = null;
                this.ForEach(function (x, i)
                {
                    if (x === item)
                    {
                        found = i;
                        return true;
                    }
                });
    
                return (found !== null) ? found : -1;
            },
    
            LastIndexOf: function (item)
            {
                var result = -1;
                this.ForEach(function (x, i)
                {
                    if (x === item) result = i;
                });
    
                return result;
            },
    
            /* Convert Methods */
    
            ToArray: function ()
            {
                var array = [];
                this.ForEach(function (x) { array.push(x) });
                return array;
            },
    
            // Overload:function(keySelector)
            // Overload:function(keySelector, elementSelector)
            // Overload:function(keySelector, elementSelector, compareSelector)
            ToLookup: function (keySelector, elementSelector, compareSelector)
            {
                keySelector = Utils.CreateLambda(keySelector);
                elementSelector = Utils.CreateLambda(elementSelector);
                compareSelector = Utils.CreateLambda(compareSelector);
    
                var dict = new Dictionary(compareSelector);
                this.ForEach(function (x)
                {
                    var key = keySelector(x);
                    var element = elementSelector(x);
    
                    var array = dict.Get(key);
                    if (array !== undefined) array.push(element);
                    else dict.Add(key, [element]);
                });
                return new Lookup(dict);
            },
    
            ToObject: function (keySelector, elementSelector)
            {
                keySelector = Utils.CreateLambda(keySelector);
                elementSelector = Utils.CreateLambda(elementSelector);
    
                var obj = {};
                this.ForEach(function (x)
                {
                    obj[keySelector(x)] = elementSelector(x);
                });
                return obj;
            },
    
            // Overload:function(keySelector, elementSelector)
            // Overload:function(keySelector, elementSelector, compareSelector)
            ToDictionary: function (keySelector, elementSelector, compareSelector)
            {
                keySelector = Utils.CreateLambda(keySelector);
                elementSelector = Utils.CreateLambda(elementSelector);
                compareSelector = Utils.CreateLambda(compareSelector);
    
                var dict = new Dictionary(compareSelector);
                this.ForEach(function (x)
                {
                    dict.Add(keySelector(x), elementSelector(x));
                });
                return dict;
            },
    
            // Overload:function()
            // Overload:function(replacer)
            // Overload:function(replacer, space)
            ToJSON: function (replacer, space)
            {
                return JSON.stringify(this.ToArray(), replacer, space);
            },
    
            // Overload:function()
            // Overload:function(separator)
            // Overload:function(separator,selector)
            ToString: function (separator, selector)
            {
                if (separator == null) separator = "";
                if (selector == null) selector = Functions.Identity;
    
                return this.Select(selector).ToArray().join(separator);
            },
    
    
            /* Action Methods */
    
            // Overload:function(action<element>)
            // Overload:function(action<element,index>)
            Do: function (action)
            {
                var source = this;
                action = Utils.CreateLambda(action);
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var index = 0;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            if (enumerator.MoveNext())
                            {
                                action(enumerator.Current(), index++);
                                return this.Yield(enumerator.Current());
                            }
                            return false;
                        },
                        function () { Utils.Dispose(enumerator); });
                });
            },
    
            // Overload:function(action<element>)
            // Overload:function(action<element,index>)
            // Overload:function(func<element,bool>)
            // Overload:function(func<element,index,bool>)
            ForEach: function (action)
            {
                action = Utils.CreateLambda(action);
    
                var index = 0;
                var enumerator = this.GetEnumerator();
                try
                {
                    while (enumerator.MoveNext())
                    {
                        if (action(enumerator.Current(), index++) === false) break;
                    }
                }
                finally { Utils.Dispose(enumerator); }
            },
    
            // Overload:function()
            // Overload:function(separator)
            // Overload:function(separator,selector)
            Write: function (separator, selector)
            {
                if (separator == null) separator = "";
                selector = Utils.CreateLambda(selector);
    
                var isFirst = true;
                this.ForEach(function (item)
                {
                    if (isFirst) isFirst = false;
                    else document.write(separator);
                    document.write(selector(item));
                });
            },
    
            // Overload:function()
            // Overload:function(selector)
            WriteLine: function (selector)
            {
                selector = Utils.CreateLambda(selector);
    
                this.ForEach(function (item)
                {
                    document.write(selector(item));
                    document.write("<br />");
                });
            },
    
            Force: function ()
            {
                var enumerator = this.GetEnumerator();
    
                try { while (enumerator.MoveNext()) { } }
                finally { Utils.Dispose(enumerator); }
            },
    
            /* Functional Methods */
    
            Let: function (func)
            {
                func = Utils.CreateLambda(func);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
    
                    return new IEnumerator(
                        function ()
                        {
                            enumerator = Enumerable.From(func(source)).GetEnumerator();
                        },
                        function ()
                        {
                            return (enumerator.MoveNext())
                                ? this.Yield(enumerator.Current())
                                : false;
                        },
                        function () { Utils.Dispose(enumerator); })
                });
            },
    
            Share: function ()
            {
                var source = this;
                var sharedEnumerator;
    
                return new Enumerable(function ()
                {
                    return new IEnumerator(
                        function ()
                        {
                            if (sharedEnumerator == null)
                            {
                                sharedEnumerator = source.GetEnumerator();
                            }
                        },
                        function ()
                        {
                            return (sharedEnumerator.MoveNext())
                                ? this.Yield(sharedEnumerator.Current())
                                : false;
                        },
                        Functions.Blank
                    )
                });
            },
    
            MemoizeAll: function ()
            {
                var source = this;
                var cache;
                var enumerator;
    
                return new Enumerable(function ()
                {
                    var index = -1;
    
                    return new IEnumerator(
                        function ()
                        {
                            if (enumerator == null)
                            {
                                enumerator = source.GetEnumerator();
                                cache = [];
                            }
                        },
                        function ()
                        {
                            index++;
                            if (cache.length <= index)
                            {
                                return (enumerator.MoveNext())
                                    ? this.Yield(cache[index] = enumerator.Current())
                                    : false;
                            }
    
                            return this.Yield(cache[index]);
                        },
                        Functions.Blank
                    )
                });
            },
    
            /* Error Handling Methods */
    
            Catch: function (handler)
            {
                handler = Utils.CreateLambda(handler);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            try
                            {
                                return (enumerator.MoveNext())
                                   ? this.Yield(enumerator.Current())
                                   : false;
                            }
                            catch (e)
                            {
                                handler(e);
                                return false;
                            }
                        },
                        function () { Utils.Dispose(enumerator); });
                });
            },
    
            Finally: function (finallyAction)
            {
                finallyAction = Utils.CreateLambda(finallyAction);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            return (enumerator.MoveNext())
                               ? this.Yield(enumerator.Current())
                               : false;
                        },
                        function ()
                        {
                            try { Utils.Dispose(enumerator); }
                            finally { finallyAction(); }
                        });
                });
            },
    
            /* For Debug Methods */
    
            // Overload:function()
            // Overload:function(message)
            // Overload:function(message,selector)
            Trace: function (message, selector)
            {
                if (message == null) message = "Trace";
                selector = Utils.CreateLambda(selector);
    
                return this.Do(function (item)
                {
                    console.log(message, ":", selector(item));
                });
            }
        }
    
        // private
    
        // static functions
        var Functions =
        {
            Identity: function (x) { return x; },
            True: function () { return true; },
            Blank: function () { }
        }
    
        // static const
        var Types =
        {
            Boolean: typeof true,
            Number: typeof 0,
            String: typeof "",
            Object: typeof {},
            Undefined: typeof undefined,
            Function: typeof function () { }
        }
    
        // static utility methods
        var Utils =
        {
            // Create anonymous function from lambda expression string
            CreateLambda: function (expression)
            {
                if (expression == null) return Functions.Identity;
                if (typeof expression == Types.String)
                {
                    if (expression == "")
                    {
                        return Functions.Identity;
                    }
                    else if (expression.indexOf("=>") == -1)
                    {
                        return new Function("$,$$,$$$,$$$$", "return " + expression);
                    }
                    else
                    {
                        var expr = expression.match(/^[(s]*([^()]*?)[)s]*=>(.*)/);
                        return new Function(expr[1], "return " + expr[2]);
                    }
                }
                return expression;
            },
    
            IsIEnumerable: function (obj)
            {
                if (typeof Enumerator != Types.Undefined)
                {
                    try
                    {
                        new Enumerator(obj);
                        return true;
                    }
                    catch (e) { }
                }
                return false;
            },
    
            Compare: function (a, b)
            {
                return (a === b) ? 0
                    : (a > b) ? 1
                    : -1;
            },
    
            Dispose: function (obj)
            {
                if (obj != null) obj.Dispose();
            }
        }
    
        // IEnumerator State
        var State = { Before: 0, Running: 1, After: 2 }
    
        // name "Enumerator" is conflict JScript's "Enumerator"
        var IEnumerator = function (initialize, tryGetNext, dispose)
        {
            var yielder = new Yielder();
            var state = State.Before;
    
            this.Current = yielder.Current;
            this.MoveNext = function ()
            {
                try
                {
                    switch (state)
                    {
                        case State.Before:
                            state = State.Running;
                            initialize(); // fall through
                        case State.Running:
                            if (tryGetNext.apply(yielder))
                            {
                                return true;
                            }
                            else
                            {
                                this.Dispose();
                                return false;
                            }
                        case State.After:
                            return false;
                    }
                }
                catch (e)
                {
                    this.Dispose();
                    throw e;
                }
            }
            this.Dispose = function ()
            {
                if (state != State.Running) return;
    
                try { dispose(); }
                finally { state = State.After; }
            }
        }
    
        // for tryGetNext
        var Yielder = function ()
        {
            var current = null;
            this.Current = function () { return current; }
            this.Yield = function (value)
            {
                current = value;
                return true;
            }
        }
    
        // for OrderBy/ThenBy
    
        var OrderedEnumerable = function (source, keySelector, descending, parent)
        {
            this.source = source;
            this.keySelector = Utils.CreateLambda(keySelector);
            this.descending = descending;
            this.parent = parent;
        }
        OrderedEnumerable.prototype = new Enumerable();
    
        OrderedEnumerable.prototype.CreateOrderedEnumerable = function (keySelector, descending)
        {
            return new OrderedEnumerable(this.source, keySelector, descending, this);
        }
    
        OrderedEnumerable.prototype.ThenBy = function (keySelector)
        {
            return this.CreateOrderedEnumerable(keySelector, false);
        }
    
        OrderedEnumerable.prototype.ThenByDescending = function (keySelector)
        {
            return this.CreateOrderedEnumerable(keySelector, true);
        }
    
        OrderedEnumerable.prototype.GetEnumerator = function ()
        {
            var self = this;
            var buffer;
            var indexes;
            var index = 0;
    
            return new IEnumerator(
                function ()
                {
                    buffer = [];
                    indexes = [];
                    self.source.ForEach(function (item, index)
                    {
                        buffer.push(item);
                        indexes.push(index);
                    });
                    var sortContext = SortContext.Create(self, null);
                    sortContext.GenerateKeys(buffer);
    
                    indexes.sort(function (a, b) { return sortContext.Compare(a, b); });
                },
                function ()
                {
                    return (index < indexes.length)
                        ? this.Yield(buffer[indexes[index++]])
                        : false;
                },
                Functions.Blank
            )
        }
    
        var SortContext = function (keySelector, descending, child)
        {
            this.keySelector = keySelector;
            this.descending = descending;
            this.child = child;
            this.keys = null;
        }
    
        SortContext.Create = function (orderedEnumerable, currentContext)
        {
            var context = new SortContext(orderedEnumerable.keySelector, orderedEnumerable.descending, currentContext);
            if (orderedEnumerable.parent != null) return SortContext.Create(orderedEnumerable.parent, context);
            return context;
        }
    
        SortContext.prototype.GenerateKeys = function (source)
        {
            var len = source.length;
            var keySelector = this.keySelector;
            var keys = new Array(len);
            for (var i = 0; i < len; i++) keys[i] = keySelector(source[i]);
            this.keys = keys;
    
            if (this.child != null) this.child.GenerateKeys(source);
        }
    
        SortContext.prototype.Compare = function (index1, index2)
        {
            var comparison = Utils.Compare(this.keys[index1], this.keys[index2]);
    
            if (comparison == 0)
            {
                if (this.child != null) return this.child.Compare(index1, index2)
                comparison = Utils.Compare(index1, index2);
            }
    
            return (this.descending) ? -comparison : comparison;
        }
    
        // optimize array or arraylike object
    
        var ArrayEnumerable = function (source)
        {
            this.source = source;
        }
        ArrayEnumerable.prototype = new Enumerable();
    
        ArrayEnumerable.prototype.Any = function (predicate)
        {
            return (predicate == null)
                ? (this.source.length > 0)
                : Enumerable.prototype.Any.apply(this, arguments);
        }
    
        ArrayEnumerable.prototype.Count = function (predicate)
        {
            return (predicate == null)
                ? this.source.length
                : Enumerable.prototype.Count.apply(this, arguments);
        }
    
        ArrayEnumerable.prototype.ElementAt = function (index)
        {
            return (0 <= index && index < this.source.length)
                ? this.source[index]
                : Enumerable.prototype.ElementAt.apply(this, arguments);
        }
    
        ArrayEnumerable.prototype.ElementAtOrDefault = function (index, defaultValue)
        {
            return (0 <= index && index < this.source.length)
                ? this.source[index]
                : defaultValue;
        }
    
        ArrayEnumerable.prototype.First = function (predicate)
        {
            return (predicate == null && this.source.length > 0)
                ? this.source[0]
                : Enumerable.prototype.First.apply(this, arguments);
        }
    
        ArrayEnumerable.prototype.FirstOrDefault = function (defaultValue, predicate)
        {
            if (predicate != null)
            {
                return Enumerable.prototype.FirstOrDefault.apply(this, arguments);
            }
    
            return this.source.length > 0 ? this.source[0] : defaultValue;
        }
    
        ArrayEnumerable.prototype.Last = function (predicate)
        {
            return (predicate == null && this.source.length > 0)
                ? this.source[this.source.length - 1]
                : Enumerable.prototype.Last.apply(this, arguments);
        }
    
        ArrayEnumerable.prototype.LastOrDefault = function (defaultValue, predicate)
        {
            if (predicate != null)
            {
                return Enumerable.prototype.LastOrDefault.apply(this, arguments);
            }
    
            return this.source.length > 0 ? this.source[this.source.length - 1] : defaultValue;
        }
    
        ArrayEnumerable.prototype.Skip = function (count)
        {
            var source = this.source;
    
            return new Enumerable(function ()
            {
                var index;
    
                return new IEnumerator(
                    function () { index = (count < 0) ? 0 : count },
                    function ()
                    {
                        return (index < source.length)
                            ? this.Yield(source[index++])
                            : false;
                    },
                    Functions.Blank);
            });
        };
    
        ArrayEnumerable.prototype.TakeExceptLast = function (count)
        {
            if (count == null) count = 1;
            return this.Take(this.source.length - count);
        }
    
        ArrayEnumerable.prototype.TakeFromLast = function (count)
        {
            return this.Skip(this.source.length - count);
        }
    
        ArrayEnumerable.prototype.Reverse = function ()
        {
            var source = this.source;
    
            return new Enumerable(function ()
            {
                var index;
    
                return new IEnumerator(
                    function ()
                    {
                        index = source.length;
                    },
                    function ()
                    {
                        return (index > 0)
                            ? this.Yield(source[--index])
                            : false;
                    },
                    Functions.Blank)
            });
        }
    
        ArrayEnumerable.prototype.SequenceEqual = function (second, compareSelector)
        {
            if ((second instanceof ArrayEnumerable || second instanceof Array)
                && compareSelector == null
                && Enumerable.From(second).Count() != this.Count())
            {
                return false;
            }
    
            return Enumerable.prototype.SequenceEqual.apply(this, arguments);
        }
    
        ArrayEnumerable.prototype.ToString = function (separator, selector)
        {
            if (selector != null || !(this.source instanceof Array))
            {
                return Enumerable.prototype.ToString.apply(this, arguments);
            }
    
            if (separator == null) separator = "";
            return this.source.join(separator);
        }
    
        ArrayEnumerable.prototype.GetEnumerator = function ()
        {
            var source = this.source;
            var index = 0;
    
            return new IEnumerator(
                Functions.Blank,
                function ()
                {
                    return (index < source.length)
                        ? this.Yield(source[index++])
                        : false;
                },
                Functions.Blank);
        }
    
        // Collections
    
        var Dictionary = (function ()
        {
            // static utility methods
            var HasOwnProperty = function (target, key)
            {
                return Object.prototype.hasOwnProperty.call(target, key);
            }
    
            var ComputeHashCode = function (obj)
            {
                if (obj === null) return "null";
                if (obj === undefined) return "undefined";
    
                return (typeof obj.toString === Types.Function)
                    ? obj.toString()
                    : Object.prototype.toString.call(obj);
            }
    
            // LinkedList for Dictionary
            var HashEntry = function (key, value)
            {
                this.Key = key;
                this.Value = value;
                this.Prev = null;
                this.Next = null;
            }
    
            var EntryList = function ()
            {
                this.First = null;
                this.Last = null;
            }
            EntryList.prototype =
            {
                AddLast: function (entry)
                {
                    if (this.Last != null)
                    {
                        this.Last.Next = entry;
                        entry.Prev = this.Last;
                        this.Last = entry;
                    }
                    else this.First = this.Last = entry;
                },
    
                Replace: function (entry, newEntry)
                {
                    if (entry.Prev != null)
                    {
                        entry.Prev.Next = newEntry;
                        newEntry.Prev = entry.Prev;
                    }
                    else this.First = newEntry;
    
                    if (entry.Next != null)
                    {
                        entry.Next.Prev = newEntry;
                        newEntry.Next = entry.Next;
                    }
                    else this.Last = newEntry;
    
                },
    
                Remove: function (entry)
                {
                    if (entry.Prev != null) entry.Prev.Next = entry.Next;
                    else this.First = entry.Next;
    
                    if (entry.Next != null) entry.Next.Prev = entry.Prev;
                    else this.Last = entry.Prev;
                }
            }
    
            // Overload:function()
            // Overload:function(compareSelector)
            var Dictionary = function (compareSelector)
            {
                this.count = 0;
                this.entryList = new EntryList();
                this.buckets = {}; // as Dictionary<string,List<object>>
                this.compareSelector = (compareSelector == null) ? Functions.Identity : compareSelector;
            }
    
            Dictionary.prototype =
            {
                Add: function (key, value)
                {
                    var compareKey = this.compareSelector(key);
                    var hash = ComputeHashCode(compareKey);
                    var entry = new HashEntry(key, value);
                    if (HasOwnProperty(this.buckets, hash))
                    {
                        var array = this.buckets[hash];
                        for (var i = 0; i < array.length; i++)
                        {
                            if (this.compareSelector(array[i].Key) === compareKey)
                            {
                                this.entryList.Replace(array[i], entry);
                                array[i] = entry;
                                return;
                            }
                        }
                        array.push(entry);
                    }
                    else
                    {
                        this.buckets[hash] = [entry];
                    }
                    this.count++;
                    this.entryList.AddLast(entry);
                },
    
                Get: function (key)
                {
                    var compareKey = this.compareSelector(key);
                    var hash = ComputeHashCode(compareKey);
                    if (!HasOwnProperty(this.buckets, hash)) return undefined;
    
                    var array = this.buckets[hash];
                    for (var i = 0; i < array.length; i++)
                    {
                        var entry = array[i];
                        if (this.compareSelector(entry.Key) === compareKey) return entry.Value;
                    }
                    return undefined;
                },
    
                Set: function (key, value)
                {
                    var compareKey = this.compareSelector(key);
                    var hash = ComputeHashCode(compareKey);
                    if (HasOwnProperty(this.buckets, hash))
                    {
                        var array = this.buckets[hash];
                        for (var i = 0; i < array.length; i++)
                        {
                            if (this.compareSelector(array[i].Key) === compareKey)
                            {
                                var newEntry = new HashEntry(key, value);
                                this.entryList.Replace(array[i], newEntry);
                                array[i] = newEntry;
                                return true;
                            }
                        }
                    }
                    return false;
                },
    
                Contains: function (key)
                {
                    var compareKey = this.compareSelector(key);
                    var hash = ComputeHashCode(compareKey);
                    if (!HasOwnProperty(this.buckets, hash)) return false;
    
                    var array = this.buckets[hash];
                    for (var i = 0; i < array.length; i++)
                    {
                        if (this.compareSelector(array[i].Key) === compareKey) return true;
                    }
                    return false;
                },
    
                Clear: function ()
                {
                    this.count = 0;
                    this.buckets = {};
                    this.entryList = new EntryList();
                },
    
                Remove: function (key)
                {
                    var compareKey = this.compareSelector(key);
                    var hash = ComputeHashCode(compareKey);
                    if (!HasOwnProperty(this.buckets, hash)) return;
    
                    var array = this.buckets[hash];
                    for (var i = 0; i < array.length; i++)
                    {
                        if (this.compareSelector(array[i].Key) === compareKey)
                        {
                            this.entryList.Remove(array[i]);
                            array.splice(i, 1);
                            if (array.length == 0) delete this.buckets[hash];
                            this.count--;
                            return;
                        }
                    }
                },
    
                Count: function ()
                {
                    return this.count;
                },
    
                ToEnumerable: function ()
                {
                    var self = this;
                    return new Enumerable(function ()
                    {
                        var currentEntry;
    
                        return new IEnumerator(
                            function () { currentEntry = self.entryList.First },
                            function ()
                            {
                                if (currentEntry != null)
                                {
                                    var result = { Key: currentEntry.Key, Value: currentEntry.Value };
                                    currentEntry = currentEntry.Next;
                                    return this.Yield(result);
                                }
                                return false;
                            },
                            Functions.Blank);
                    });
                }
            }
    
            return Dictionary;
        })();
    
        // dictionary = Dictionary<TKey, TValue[]>
        var Lookup = function (dictionary)
        {
            this.Count = function ()
            {
                return dictionary.Count();
            }
    
            this.Get = function (key)
            {
                return Enumerable.From(dictionary.Get(key));
            }
    
            this.Contains = function (key)
            {
                return dictionary.Contains(key);
            }
    
            this.ToEnumerable = function ()
            {
                return dictionary.ToEnumerable().Select(function (kvp)
                {
                    return new Grouping(kvp.Key, kvp.Value);
                });
            }
        }
    
        var Grouping = function (key, elements)
        {
            this.Key = function ()
            {
                return key;
            }
    
            ArrayEnumerable.call(this, elements);
        }
        Grouping.prototype = new ArrayEnumerable();
    
        // out to global
        return Enumerable;
    })()});
    
    // binding for jQuery
    // toEnumerable / TojQuery
    
    (function ($, Enumerable)
    {
        $.fn.toEnumerable = function ()
        {
            /// <summary>each contains elements. to Enumerable&lt;jQuery&gt;.</summary>
            /// <returns type="Enumerable"></returns>
            return Enumerable.From(this).Select(function (e) { return $(e) });
        }
    
        Enumerable.prototype.TojQuery = function ()
        {
            /// <summary>Enumerable to jQuery.</summary>
            /// <returns type="jQuery"></returns>
            return $(this.ToArray());
        }
    })(jQuery, this.Enumerable || this.jQuery.Enumerable)
    View Code

    linq.js

    /*--------------------------------------------------------------------------
    * linq.js - LINQ for JavaScript
    * ver 2.2.0.2 (Jan. 21th, 2011)
    *
    * created and maintained by neuecc <ils@neue.cc>
    * licensed under Microsoft Public License(Ms-PL)
    * http://neue.cc/
    * http://linqjs.codeplex.com/
    *--------------------------------------------------------------------------*/
    
    Enumerable = (function ()
    {
        var Enumerable = function (getEnumerator)
        {
            this.GetEnumerator = getEnumerator;
        }
    
        // Generator
    
        Enumerable.Choice = function () // variable argument
        {
            var args = (arguments[0] instanceof Array) ? arguments[0] : arguments;
    
            return new Enumerable(function ()
            {
                return new IEnumerator(
                    Functions.Blank,
                    function ()
                    {
                        return this.Yield(args[Math.floor(Math.random() * args.length)]);
                    },
                    Functions.Blank);
            });
        }
    
        Enumerable.Cycle = function () // variable argument
        {
            var args = (arguments[0] instanceof Array) ? arguments[0] : arguments;
    
            return new Enumerable(function ()
            {
                var index = 0;
                return new IEnumerator(
                    Functions.Blank,
                    function ()
                    {
                        if (index >= args.length) index = 0;
                        return this.Yield(args[index++]);
                    },
                    Functions.Blank);
            });
        }
    
        Enumerable.Empty = function ()
        {
            return new Enumerable(function ()
            {
                return new IEnumerator(
                    Functions.Blank,
                    function () { return false; },
                    Functions.Blank);
            });
        }
    
        Enumerable.From = function (obj)
        {
            if (obj == null)
            {
                return Enumerable.Empty();
            }
            if (obj instanceof Enumerable)
            {
                return obj;
            }
            if (typeof obj == Types.Number || typeof obj == Types.Boolean)
            {
                return Enumerable.Repeat(obj, 1);
            }
            if (typeof obj == Types.String)
            {
                return new Enumerable(function ()
                {
                    var index = 0;
                    return new IEnumerator(
                        Functions.Blank,
                        function ()
                        {
                            return (index < obj.length) ? this.Yield(obj.charAt(index++)) : false;
                        },
                        Functions.Blank);
                });
            }
            if (typeof obj != Types.Function)
            {
                // array or array like object
                if (typeof obj.length == Types.Number)
                {
                    return new ArrayEnumerable(obj);
                }
    
                // JScript's IEnumerable
                if (!(obj instanceof Object) && Utils.IsIEnumerable(obj))
                {
                    return new Enumerable(function ()
                    {
                        var isFirst = true;
                        var enumerator;
                        return new IEnumerator(
                            function () { enumerator = new Enumerator(obj); },
                            function ()
                            {
                                if (isFirst) isFirst = false;
                                else enumerator.moveNext();
    
                                return (enumerator.atEnd()) ? false : this.Yield(enumerator.item());
                            },
                            Functions.Blank);
                    });
                }
            }
    
            // case function/object : Create KeyValuePair[]
            return new Enumerable(function ()
            {
                var array = [];
                var index = 0;
    
                return new IEnumerator(
                    function ()
                    {
                        for (var key in obj)
                        {
                            if (!(obj[key] instanceof Function))
                            {
                                array.push({ Key: key, Value: obj[key] });
                            }
                        }
                    },
                    function ()
                    {
                        return (index < array.length)
                            ? this.Yield(array[index++])
                            : false;
                    },
                    Functions.Blank);
            });
        },
    
        Enumerable.Return = function (element)
        {
            return Enumerable.Repeat(element, 1);
        }
    
        // Overload:function(input, pattern)
        // Overload:function(input, pattern, flags)
        Enumerable.Matches = function (input, pattern, flags)
        {
            if (flags == null) flags = "";
            if (pattern instanceof RegExp)
            {
                flags += (pattern.ignoreCase) ? "i" : "";
                flags += (pattern.multiline) ? "m" : "";
                pattern = pattern.source;
            }
            if (flags.indexOf("g") === -1) flags += "g";
    
            return new Enumerable(function ()
            {
                var regex;
                return new IEnumerator(
                    function () { regex = new RegExp(pattern, flags) },
                    function ()
                    {
                        var match = regex.exec(input);
                        return (match) ? this.Yield(match) : false;
                    },
                    Functions.Blank);
            });
        }
    
        // Overload:function(start, count)
        // Overload:function(start, count, step)
        Enumerable.Range = function (start, count, step)
        {
            if (step == null) step = 1;
            return Enumerable.ToInfinity(start, step).Take(count);
        }
    
        // Overload:function(start, count)
        // Overload:function(start, count, step)
        Enumerable.RangeDown = function (start, count, step)
        {
            if (step == null) step = 1;
            return Enumerable.ToNegativeInfinity(start, step).Take(count);
        }
    
        // Overload:function(start, to)
        // Overload:function(start, to, step)
        Enumerable.RangeTo = function (start, to, step)
        {
            if (step == null) step = 1;
            return (start < to)
                ? Enumerable.ToInfinity(start, step).TakeWhile(function (i) { return i <= to; })
                : Enumerable.ToNegativeInfinity(start, step).TakeWhile(function (i) { return i >= to; })
        }
    
        // Overload:function(obj)
        // Overload:function(obj, num)
        Enumerable.Repeat = function (obj, num)
        {
            if (num != null) return Enumerable.Repeat(obj).Take(num);
    
            return new Enumerable(function ()
            {
                return new IEnumerator(
                    Functions.Blank,
                    function () { return this.Yield(obj); },
                    Functions.Blank);
            });
        }
    
        Enumerable.RepeatWithFinalize = function (initializer, finalizer)
        {
            initializer = Utils.CreateLambda(initializer);
            finalizer = Utils.CreateLambda(finalizer);
    
            return new Enumerable(function ()
            {
                var element;
                return new IEnumerator(
                    function () { element = initializer(); },
                    function () { return this.Yield(element); },
                    function ()
                    {
                        if (element != null)
                        {
                            finalizer(element);
                            element = null;
                        }
                    });
            });
        }
    
        // Overload:function(func)
        // Overload:function(func, count)
        Enumerable.Generate = function (func, count)
        {
            if (count != null) return Enumerable.Generate(func).Take(count);
            func = Utils.CreateLambda(func);
    
            return new Enumerable(function ()
            {
                return new IEnumerator(
                    Functions.Blank,
                    function () { return this.Yield(func()); },
                    Functions.Blank);
            });
        }
    
        // Overload:function()
        // Overload:function(start)
        // Overload:function(start, step)
        Enumerable.ToInfinity = function (start, step)
        {
            if (start == null) start = 0;
            if (step == null) step = 1;
    
            return new Enumerable(function ()
            {
                var value;
                return new IEnumerator(
                    function () { value = start - step },
                    function () { return this.Yield(value += step); },
                    Functions.Blank);
            });
        }
    
        // Overload:function()
        // Overload:function(start)
        // Overload:function(start, step)
        Enumerable.ToNegativeInfinity = function (start, step)
        {
            if (start == null) start = 0;
            if (step == null) step = 1;
    
            return new Enumerable(function ()
            {
                var value;
                return new IEnumerator(
                    function () { value = start + step },
                    function () { return this.Yield(value -= step); },
                    Functions.Blank);
            });
        }
    
        Enumerable.Unfold = function (seed, func)
        {
            func = Utils.CreateLambda(func);
    
            return new Enumerable(function ()
            {
                var isFirst = true;
                var value;
                return new IEnumerator(
                    Functions.Blank,
                    function ()
                    {
                        if (isFirst)
                        {
                            isFirst = false;
                            value = seed;
                            return this.Yield(value);
                        }
                        value = func(value);
                        return this.Yield(value);
                    },
                    Functions.Blank);
            });
        }
    
        // Extension Methods
    
        Enumerable.prototype =
        {
            /* Projection and Filtering Methods */
    
            // Overload:function(func)
            // Overload:function(func, resultSelector<element>)
            // Overload:function(func, resultSelector<element, nestLevel>)
            CascadeBreadthFirst: function (func, resultSelector)
            {
                var source = this;
                func = Utils.CreateLambda(func);
                resultSelector = Utils.CreateLambda(resultSelector);
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var nestLevel = 0;
                    var buffer = [];
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            while (true)
                            {
                                if (enumerator.MoveNext())
                                {
                                    buffer.push(enumerator.Current());
                                    return this.Yield(resultSelector(enumerator.Current(), nestLevel));
                                }
    
                                var next = Enumerable.From(buffer).SelectMany(function (x) { return func(x); });
                                if (!next.Any())
                                {
                                    return false;
                                }
                                else
                                {
                                    nestLevel++;
                                    buffer = [];
                                    Utils.Dispose(enumerator);
                                    enumerator = next.GetEnumerator();
                                }
                            }
                        },
                        function () { Utils.Dispose(enumerator); });
                });
            },
    
            // Overload:function(func)
            // Overload:function(func, resultSelector<element>)
            // Overload:function(func, resultSelector<element, nestLevel>)
            CascadeDepthFirst: function (func, resultSelector)
            {
                var source = this;
                func = Utils.CreateLambda(func);
                resultSelector = Utils.CreateLambda(resultSelector);
    
                return new Enumerable(function ()
                {
                    var enumeratorStack = [];
                    var enumerator;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            while (true)
                            {
                                if (enumerator.MoveNext())
                                {
                                    var value = resultSelector(enumerator.Current(), enumeratorStack.length);
                                    enumeratorStack.push(enumerator);
                                    enumerator = Enumerable.From(func(enumerator.Current())).GetEnumerator();
                                    return this.Yield(value);
                                }
    
                                if (enumeratorStack.length <= 0) return false;
                                Utils.Dispose(enumerator);
                                enumerator = enumeratorStack.pop();
                            }
                        },
                        function ()
                        {
                            try { Utils.Dispose(enumerator); }
                            finally { Enumerable.From(enumeratorStack).ForEach(function (s) { s.Dispose(); }) }
                        });
                });
            },
    
            Flatten: function ()
            {
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var middleEnumerator = null;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            while (true)
                            {
                                if (middleEnumerator != null)
                                {
                                    if (middleEnumerator.MoveNext())
                                    {
                                        return this.Yield(middleEnumerator.Current());
                                    }
                                    else
                                    {
                                        middleEnumerator = null;
                                    }
                                }
    
                                if (enumerator.MoveNext())
                                {
                                    if (enumerator.Current() instanceof Array)
                                    {
                                        Utils.Dispose(middleEnumerator);
                                        middleEnumerator = Enumerable.From(enumerator.Current())
                                            .SelectMany(Functions.Identity)
                                            .Flatten()
                                            .GetEnumerator();
                                        continue;
                                    }
                                    else
                                    {
                                        return this.Yield(enumerator.Current());
                                    }
                                }
    
                                return false;
                            }
                        },
                        function ()
                        {
                            try { Utils.Dispose(enumerator); }
                            finally { Utils.Dispose(middleEnumerator); }
                        });
                });
            },
    
            Pairwise: function (selector)
            {
                var source = this;
                selector = Utils.CreateLambda(selector);
    
                return new Enumerable(function ()
                {
                    var enumerator;
    
                    return new IEnumerator(
                        function ()
                        {
                            enumerator = source.GetEnumerator();
                            enumerator.MoveNext();
                        },
                        function ()
                        {
                            var prev = enumerator.Current();
                            return (enumerator.MoveNext())
                                ? this.Yield(selector(prev, enumerator.Current()))
                                : false;
                        },
                        function () { Utils.Dispose(enumerator); });
                });
            },
    
            // Overload:function(func)
            // Overload:function(seed,func<value,element>)
            // Overload:function(seed,func<value,element>,resultSelector)
            Scan: function (seed, func, resultSelector)
            {
                if (resultSelector != null) return this.Scan(seed, func).Select(resultSelector);
    
                var isUseSeed;
                if (func == null)
                {
                    func = Utils.CreateLambda(seed); // arguments[0]
                    isUseSeed = false;
                }
                else
                {
                    func = Utils.CreateLambda(func);
                    isUseSeed = true;
                }
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var value;
                    var isFirst = true;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            if (isFirst)
                            {
                                isFirst = false;
                                if (!isUseSeed)
                                {
                                    if (enumerator.MoveNext())
                                    {
                                        return this.Yield(value = enumerator.Current());
                                    }
                                }
                                else
                                {
                                    return this.Yield(value = seed);
                                }
                            }
    
                            return (enumerator.MoveNext())
                                ? this.Yield(value = func(value, enumerator.Current()))
                                : false;
                        },
                        function () { Utils.Dispose(enumerator); });
                });
            },
    
            // Overload:function(selector<element>)
            // Overload:function(selector<element,index>)
            Select: function (selector)
            {
                var source = this;
                selector = Utils.CreateLambda(selector);
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var index = 0;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            return (enumerator.MoveNext())
                                ? this.Yield(selector(enumerator.Current(), index++))
                                : false;
                        },
                        function () { Utils.Dispose(enumerator); })
                });
            },
    
            // Overload:function(collectionSelector<element>)
            // Overload:function(collectionSelector<element,index>)
            // Overload:function(collectionSelector<element>,resultSelector)
            // Overload:function(collectionSelector<element,index>,resultSelector)
            SelectMany: function (collectionSelector, resultSelector)
            {
                var source = this;
                collectionSelector = Utils.CreateLambda(collectionSelector);
                if (resultSelector == null) resultSelector = function (a, b) { return b; }
                resultSelector = Utils.CreateLambda(resultSelector);
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var middleEnumerator = undefined;
                    var index = 0;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            if (middleEnumerator === undefined)
                            {
                                if (!enumerator.MoveNext()) return false;
                            }
                            do
                            {
                                if (middleEnumerator == null)
                                {
                                    var middleSeq = collectionSelector(enumerator.Current(), index++);
                                    middleEnumerator = Enumerable.From(middleSeq).GetEnumerator();
                                }
                                if (middleEnumerator.MoveNext())
                                {
                                    return this.Yield(resultSelector(enumerator.Current(), middleEnumerator.Current()));
                                }
                                Utils.Dispose(middleEnumerator);
                                middleEnumerator = null;
                            } while (enumerator.MoveNext())
                            return false;
                        },
                        function ()
                        {
                            try { Utils.Dispose(enumerator); }
                            finally { Utils.Dispose(middleEnumerator); }
                        })
                });
            },
    
            // Overload:function(predicate<element>)
            // Overload:function(predicate<element,index>)
            Where: function (predicate)
            {
                predicate = Utils.CreateLambda(predicate);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var index = 0;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            while (enumerator.MoveNext())
                            {
                                if (predicate(enumerator.Current(), index++))
                                {
                                    return this.Yield(enumerator.Current());
                                }
                            }
                            return false;
                        },
                        function () { Utils.Dispose(enumerator); })
                });
            },
    
            OfType: function (type)
            {
                var typeName;
                switch (type)
                {
                    case Number: typeName = Types.Number; break;
                    case String: typeName = Types.String; break;
                    case Boolean: typeName = Types.Boolean; break;
                    case Function: typeName = Types.Function; break;
                    default: typeName = null; break;
                }
                return (typeName === null)
                    ? this.Where(function (x) { return x instanceof type })
                    : this.Where(function (x) { return typeof x === typeName });
            },
    
            // Overload:function(second,selector<outer,inner>)
            // Overload:function(second,selector<outer,inner,index>)
            Zip: function (second, selector)
            {
                selector = Utils.CreateLambda(selector);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var firstEnumerator;
                    var secondEnumerator;
                    var index = 0;
    
                    return new IEnumerator(
                        function ()
                        {
                            firstEnumerator = source.GetEnumerator();
                            secondEnumerator = Enumerable.From(second).GetEnumerator();
                        },
                        function ()
                        {
                            if (firstEnumerator.MoveNext() && secondEnumerator.MoveNext())
                            {
                                return this.Yield(selector(firstEnumerator.Current(), secondEnumerator.Current(), index++));
                            }
                            return false;
                        },
                        function ()
                        {
                            try { Utils.Dispose(firstEnumerator); }
                            finally { Utils.Dispose(secondEnumerator); }
                        })
                });
            },
    
            /* Join Methods */
    
            // Overload:function (inner, outerKeySelector, innerKeySelector, resultSelector)
            // Overload:function (inner, outerKeySelector, innerKeySelector, resultSelector, compareSelector)
            Join: function (inner, outerKeySelector, innerKeySelector, resultSelector, compareSelector)
            {
                outerKeySelector = Utils.CreateLambda(outerKeySelector);
                innerKeySelector = Utils.CreateLambda(innerKeySelector);
                resultSelector = Utils.CreateLambda(resultSelector);
                compareSelector = Utils.CreateLambda(compareSelector);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var outerEnumerator;
                    var lookup;
                    var innerElements = null;
                    var innerCount = 0;
    
                    return new IEnumerator(
                        function ()
                        {
                            outerEnumerator = source.GetEnumerator();
                            lookup = Enumerable.From(inner).ToLookup(innerKeySelector, Functions.Identity, compareSelector);
                        },
                        function ()
                        {
                            while (true)
                            {
                                if (innerElements != null)
                                {
                                    var innerElement = innerElements[innerCount++];
                                    if (innerElement !== undefined)
                                    {
                                        return this.Yield(resultSelector(outerEnumerator.Current(), innerElement));
                                    }
    
                                    innerElement = null;
                                    innerCount = 0;
                                }
    
                                if (outerEnumerator.MoveNext())
                                {
                                    var key = outerKeySelector(outerEnumerator.Current());
                                    innerElements = lookup.Get(key).ToArray();
                                }
                                else
                                {
                                    return false;
                                }
                            }
                        },
                        function () { Utils.Dispose(outerEnumerator); })
                });
            },
    
            // Overload:function (inner, outerKeySelector, innerKeySelector, resultSelector)
            // Overload:function (inner, outerKeySelector, innerKeySelector, resultSelector, compareSelector)
            GroupJoin: function (inner, outerKeySelector, innerKeySelector, resultSelector, compareSelector)
            {
                outerKeySelector = Utils.CreateLambda(outerKeySelector);
                innerKeySelector = Utils.CreateLambda(innerKeySelector);
                resultSelector = Utils.CreateLambda(resultSelector);
                compareSelector = Utils.CreateLambda(compareSelector);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator = source.GetEnumerator();
                    var lookup = null;
    
                    return new IEnumerator(
                        function ()
                        {
                            enumerator = source.GetEnumerator();
                            lookup = Enumerable.From(inner).ToLookup(innerKeySelector, Functions.Identity, compareSelector);
                        },
                        function ()
                        {
                            if (enumerator.MoveNext())
                            {
                                var innerElement = lookup.Get(outerKeySelector(enumerator.Current()));
                                return this.Yield(resultSelector(enumerator.Current(), innerElement));
                            }
                            return false;
                        },
                        function () { Utils.Dispose(enumerator); })
                });
            },
    
            /* Set Methods */
    
            All: function (predicate)
            {
                predicate = Utils.CreateLambda(predicate);
    
                var result = true;
                this.ForEach(function (x)
                {
                    if (!predicate(x))
                    {
                        result = false;
                        return false; // break
                    }
                });
                return result;
            },
    
            // Overload:function()
            // Overload:function(predicate)
            Any: function (predicate)
            {
                predicate = Utils.CreateLambda(predicate);
    
                var enumerator = this.GetEnumerator();
                try
                {
                    if (arguments.length == 0) return enumerator.MoveNext(); // case:function()
    
                    while (enumerator.MoveNext()) // case:function(predicate)
                    {
                        if (predicate(enumerator.Current())) return true;
                    }
                    return false;
                }
                finally { Utils.Dispose(enumerator); }
            },
    
            Concat: function (second)
            {
                var source = this;
    
                return new Enumerable(function ()
                {
                    var firstEnumerator;
                    var secondEnumerator;
    
                    return new IEnumerator(
                        function () { firstEnumerator = source.GetEnumerator(); },
                        function ()
                        {
                            if (secondEnumerator == null)
                            {
                                if (firstEnumerator.MoveNext()) return this.Yield(firstEnumerator.Current());
                                secondEnumerator = Enumerable.From(second).GetEnumerator();
                            }
                            if (secondEnumerator.MoveNext()) return this.Yield(secondEnumerator.Current());
                            return false;
                        },
                        function ()
                        {
                            try { Utils.Dispose(firstEnumerator); }
                            finally { Utils.Dispose(secondEnumerator); }
                        })
                });
            },
    
            Insert: function (index, second)
            {
                var source = this;
    
                return new Enumerable(function ()
                {
                    var firstEnumerator;
                    var secondEnumerator;
                    var count = 0;
                    var isEnumerated = false;
    
                    return new IEnumerator(
                        function ()
                        {
                            firstEnumerator = source.GetEnumerator();
                            secondEnumerator = Enumerable.From(second).GetEnumerator();
                        },
                        function ()
                        {
                            if (count == index && secondEnumerator.MoveNext())
                            {
                                isEnumerated = true;
                                return this.Yield(secondEnumerator.Current());
                            }
                            if (firstEnumerator.MoveNext())
                            {
                                count++;
                                return this.Yield(firstEnumerator.Current());
                            }
                            if (!isEnumerated && secondEnumerator.MoveNext())
                            {
                                return this.Yield(secondEnumerator.Current());
                            }
                            return false;
                        },
                        function ()
                        {
                            try { Utils.Dispose(firstEnumerator); }
                            finally { Utils.Dispose(secondEnumerator); }
                        })
                });
            },
    
            Alternate: function (value)
            {
                value = Enumerable.Return(value);
                return this.SelectMany(function (elem)
                {
                    return Enumerable.Return(elem).Concat(value);
                }).TakeExceptLast();
            },
    
            // Overload:function(value)
            // Overload:function(value, compareSelector)
            Contains: function (value, compareSelector)
            {
                compareSelector = Utils.CreateLambda(compareSelector);
                var enumerator = this.GetEnumerator();
                try
                {
                    while (enumerator.MoveNext())
                    {
                        if (compareSelector(enumerator.Current()) === value) return true;
                    }
                    return false;
                }
                finally { Utils.Dispose(enumerator) }
            },
    
            DefaultIfEmpty: function (defaultValue)
            {
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var isFirst = true;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            if (enumerator.MoveNext())
                            {
                                isFirst = false;
                                return this.Yield(enumerator.Current());
                            }
                            else if (isFirst)
                            {
                                isFirst = false;
                                return this.Yield(defaultValue);
                            }
                            return false;
                        },
                        function () { Utils.Dispose(enumerator); })
                });
            },
    
            // Overload:function()
            // Overload:function(compareSelector)
            Distinct: function (compareSelector)
            {
                return this.Except(Enumerable.Empty(), compareSelector);
            },
    
            // Overload:function(second)
            // Overload:function(second, compareSelector)
            Except: function (second, compareSelector)
            {
                compareSelector = Utils.CreateLambda(compareSelector);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var keys;
    
                    return new IEnumerator(
                        function ()
                        {
                            enumerator = source.GetEnumerator();
                            keys = new Dictionary(compareSelector);
                            Enumerable.From(second).ForEach(function (key) { keys.Add(key); });
                        },
                        function ()
                        {
                            while (enumerator.MoveNext())
                            {
                                var current = enumerator.Current();
                                if (!keys.Contains(current))
                                {
                                    keys.Add(current);
                                    return this.Yield(current);
                                }
                            }
                            return false;
                        },
                        function () { Utils.Dispose(enumerator); })
                });
            },
    
            // Overload:function(second)
            // Overload:function(second, compareSelector)
            Intersect: function (second, compareSelector)
            {
                compareSelector = Utils.CreateLambda(compareSelector);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var keys;
                    var outs;
    
                    return new IEnumerator(
                        function ()
                        {
                            enumerator = source.GetEnumerator();
    
                            keys = new Dictionary(compareSelector);
                            Enumerable.From(second).ForEach(function (key) { keys.Add(key); });
                            outs = new Dictionary(compareSelector);
                        },
                        function ()
                        {
                            while (enumerator.MoveNext())
                            {
                                var current = enumerator.Current();
                                if (!outs.Contains(current) && keys.Contains(current))
                                {
                                    outs.Add(current);
                                    return this.Yield(current);
                                }
                            }
                            return false;
                        },
                        function () { Utils.Dispose(enumerator); })
                });
            },
    
            // Overload:function(second)
            // Overload:function(second, compareSelector)
            SequenceEqual: function (second, compareSelector)
            {
                compareSelector = Utils.CreateLambda(compareSelector);
    
                var firstEnumerator = this.GetEnumerator();
                try
                {
                    var secondEnumerator = Enumerable.From(second).GetEnumerator();
                    try
                    {
                        while (firstEnumerator.MoveNext())
                        {
                            if (!secondEnumerator.MoveNext()
                                || compareSelector(firstEnumerator.Current()) !== compareSelector(secondEnumerator.Current()))
                            {
                                return false;
                            }
                        }
    
                        if (secondEnumerator.MoveNext()) return false;
                        return true;
                    }
                    finally { Utils.Dispose(secondEnumerator); }
                }
                finally { Utils.Dispose(firstEnumerator); }
            },
    
            Union: function (second, compareSelector)
            {
                compareSelector = Utils.CreateLambda(compareSelector);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var firstEnumerator;
                    var secondEnumerator;
                    var keys;
    
                    return new IEnumerator(
                        function ()
                        {
                            firstEnumerator = source.GetEnumerator();
                            keys = new Dictionary(compareSelector);
                        },
                        function ()
                        {
                            var current;
                            if (secondEnumerator === undefined)
                            {
                                while (firstEnumerator.MoveNext())
                                {
                                    current = firstEnumerator.Current();
                                    if (!keys.Contains(current))
                                    {
                                        keys.Add(current);
                                        return this.Yield(current);
                                    }
                                }
                                secondEnumerator = Enumerable.From(second).GetEnumerator();
                            }
                            while (secondEnumerator.MoveNext())
                            {
                                current = secondEnumerator.Current();
                                if (!keys.Contains(current))
                                {
                                    keys.Add(current);
                                    return this.Yield(current);
                                }
                            }
                            return false;
                        },
                        function ()
                        {
                            try { Utils.Dispose(firstEnumerator); }
                            finally { Utils.Dispose(secondEnumerator); }
                        })
                });
            },
    
            /* Ordering Methods */
    
            OrderBy: function (keySelector)
            {
                return new OrderedEnumerable(this, keySelector, false);
            },
    
            OrderByDescending: function (keySelector)
            {
                return new OrderedEnumerable(this, keySelector, true);
            },
    
            Reverse: function ()
            {
                var source = this;
    
                return new Enumerable(function ()
                {
                    var buffer;
                    var index;
    
                    return new IEnumerator(
                        function ()
                        {
                            buffer = source.ToArray();
                            index = buffer.length;
                        },
                        function ()
                        {
                            return (index > 0)
                                ? this.Yield(buffer[--index])
                                : false;
                        },
                        Functions.Blank)
                });
            },
    
            Shuffle: function ()
            {
                var source = this;
    
                return new Enumerable(function ()
                {
                    var buffer;
    
                    return new IEnumerator(
                        function () { buffer = source.ToArray(); },
                        function ()
                        {
                            if (buffer.length > 0)
                            {
                                var i = Math.floor(Math.random() * buffer.length);
                                return this.Yield(buffer.splice(i, 1)[0]);
                            }
                            return false;
                        },
                        Functions.Blank)
                });
            },
    
            /* Grouping Methods */
    
            // Overload:function(keySelector)
            // Overload:function(keySelector,elementSelector)
            // Overload:function(keySelector,elementSelector,resultSelector)
            // Overload:function(keySelector,elementSelector,resultSelector,compareSelector)
            GroupBy: function (keySelector, elementSelector, resultSelector, compareSelector)
            {
                var source = this;
                keySelector = Utils.CreateLambda(keySelector);
                elementSelector = Utils.CreateLambda(elementSelector);
                if (resultSelector != null) resultSelector = Utils.CreateLambda(resultSelector);
                compareSelector = Utils.CreateLambda(compareSelector);
    
                return new Enumerable(function ()
                {
                    var enumerator;
    
                    return new IEnumerator(
                        function ()
                        {
                            enumerator = source.ToLookup(keySelector, elementSelector, compareSelector)
                                .ToEnumerable()
                                .GetEnumerator();
                        },
                        function ()
                        {
                            while (enumerator.MoveNext())
                            {
                                return (resultSelector == null)
                                    ? this.Yield(enumerator.Current())
                                    : this.Yield(resultSelector(enumerator.Current().Key(), enumerator.Current()));
                            }
                            return false;
                        },
                        function () { Utils.Dispose(enumerator); })
                });
            },
    
            // Overload:function(keySelector)
            // Overload:function(keySelector,elementSelector)
            // Overload:function(keySelector,elementSelector,resultSelector)
            // Overload:function(keySelector,elementSelector,resultSelector,compareSelector)
            PartitionBy: function (keySelector, elementSelector, resultSelector, compareSelector)
            {
    
                var source = this;
                keySelector = Utils.CreateLambda(keySelector);
                elementSelector = Utils.CreateLambda(elementSelector);
                compareSelector = Utils.CreateLambda(compareSelector);
                var hasResultSelector;
                if (resultSelector == null)
                {
                    hasResultSelector = false;
                    resultSelector = function (key, group) { return new Grouping(key, group) }
                }
                else
                {
                    hasResultSelector = true;
                    resultSelector = Utils.CreateLambda(resultSelector);
                }
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var key;
                    var compareKey;
                    var group = [];
    
                    return new IEnumerator(
                        function ()
                        {
                            enumerator = source.GetEnumerator();
                            if (enumerator.MoveNext())
                            {
                                key = keySelector(enumerator.Current());
                                compareKey = compareSelector(key);
                                group.push(elementSelector(enumerator.Current()));
                            }
                        },
                        function ()
                        {
                            var hasNext;
                            while ((hasNext = enumerator.MoveNext()) == true)
                            {
                                if (compareKey === compareSelector(keySelector(enumerator.Current())))
                                {
                                    group.push(elementSelector(enumerator.Current()));
                                }
                                else break;
                            }
    
                            if (group.length > 0)
                            {
                                var result = (hasResultSelector)
                                    ? resultSelector(key, Enumerable.From(group))
                                    : resultSelector(key, group);
                                if (hasNext)
                                {
                                    key = keySelector(enumerator.Current());
                                    compareKey = compareSelector(key);
                                    group = [elementSelector(enumerator.Current())];
                                }
                                else group = [];
    
                                return this.Yield(result);
                            }
    
                            return false;
                        },
                        function () { Utils.Dispose(enumerator); })
                });
            },
    
            BufferWithCount: function (count)
            {
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
    
                    return new IEnumerator(
                    function () { enumerator = source.GetEnumerator(); },
                    function ()
                    {
                        var array = [];
                        var index = 0;
                        while (enumerator.MoveNext())
                        {
                            array.push(enumerator.Current());
                            if (++index >= count) return this.Yield(array);
                        }
                        if (array.length > 0) return this.Yield(array);
                        return false;
                    },
                    function () { Utils.Dispose(enumerator); })
                });
            },
    
            /* Aggregate Methods */
    
            // Overload:function(func)
            // Overload:function(seed,func)
            // Overload:function(seed,func,resultSelector)
            Aggregate: function (seed, func, resultSelector)
            {
                return this.Scan(seed, func, resultSelector).Last();
            },
    
            // Overload:function()
            // Overload:function(selector)
            Average: function (selector)
            {
                selector = Utils.CreateLambda(selector);
    
                var sum = 0;
                var count = 0;
                this.ForEach(function (x)
                {
                    sum += selector(x);
                    ++count;
                });
    
                return sum / count;
            },
    
            // Overload:function()
            // Overload:function(predicate)
            Count: function (predicate)
            {
                predicate = (predicate == null) ? Functions.True : Utils.CreateLambda(predicate);
    
                var count = 0;
                this.ForEach(function (x, i)
                {
                    if (predicate(x, i)) ++count;
                });
                return count;
            },
    
            // Overload:function()
            // Overload:function(selector)
            Max: function (selector)
            {
                if (selector == null) selector = Functions.Identity;
                return this.Select(selector).Aggregate(function (a, b) { return (a > b) ? a : b; });
            },
    
            // Overload:function()
            // Overload:function(selector)
            Min: function (selector)
            {
                if (selector == null) selector = Functions.Identity;
                return this.Select(selector).Aggregate(function (a, b) { return (a < b) ? a : b; });
            },
    
            MaxBy: function (keySelector)
            {
                keySelector = Utils.CreateLambda(keySelector);
                return this.Aggregate(function (a, b) { return (keySelector(a) > keySelector(b)) ? a : b });
            },
    
            MinBy: function (keySelector)
            {
                keySelector = Utils.CreateLambda(keySelector);
                return this.Aggregate(function (a, b) { return (keySelector(a) < keySelector(b)) ? a : b });
            },
    
            // Overload:function()
            // Overload:function(selector)
            Sum: function (selector)
            {
                if (selector == null) selector = Functions.Identity;
                return this.Select(selector).Aggregate(0, function (a, b) { return a + b; });
            },
    
            /* Paging Methods */
    
            ElementAt: function (index)
            {
                var value;
                var found = false;
                this.ForEach(function (x, i)
                {
                    if (i == index)
                    {
                        value = x;
                        found = true;
                        return false;
                    }
                });
    
                if (!found) throw new Error("index is less than 0 or greater than or equal to the number of elements in source.");
                return value;
            },
    
            ElementAtOrDefault: function (index, defaultValue)
            {
                var value;
                var found = false;
                this.ForEach(function (x, i)
                {
                    if (i == index)
                    {
                        value = x;
                        found = true;
                        return false;
                    }
                });
    
                return (!found) ? defaultValue : value;
            },
    
            // Overload:function()
            // Overload:function(predicate)
            First: function (predicate)
            {
                if (predicate != null) return this.Where(predicate).First();
    
                var value;
                var found = false;
                this.ForEach(function (x)
                {
                    value = x;
                    found = true;
                    return false;
                });
    
                if (!found) throw new Error("First:No element satisfies the condition.");
                return value;
            },
    
            // Overload:function(defaultValue)
            // Overload:function(defaultValue,predicate)
            FirstOrDefault: function (defaultValue, predicate)
            {
                if (predicate != null) return this.Where(predicate).FirstOrDefault(defaultValue);
    
                var value;
                var found = false;
                this.ForEach(function (x)
                {
                    value = x;
                    found = true;
                    return false;
                });
                return (!found) ? defaultValue : value;
            },
    
            // Overload:function()
            // Overload:function(predicate)
            Last: function (predicate)
            {
                if (predicate != null) return this.Where(predicate).Last();
    
                var value;
                var found = false;
                this.ForEach(function (x)
                {
                    found = true;
                    value = x;
                });
    
                if (!found) throw new Error("Last:No element satisfies the condition.");
                return value;
            },
    
            // Overload:function(defaultValue)
            // Overload:function(defaultValue,predicate)
            LastOrDefault: function (defaultValue, predicate)
            {
                if (predicate != null) return this.Where(predicate).LastOrDefault(defaultValue);
    
                var value;
                var found = false;
                this.ForEach(function (x)
                {
                    found = true;
                    value = x;
                });
                return (!found) ? defaultValue : value;
            },
    
            // Overload:function()
            // Overload:function(predicate)
            Single: function (predicate)
            {
                if (predicate != null) return this.Where(predicate).Single();
    
                var value;
                var found = false;
                this.ForEach(function (x)
                {
                    if (!found)
                    {
                        found = true;
                        value = x;
                    }
                    else throw new Error("Single:sequence contains more than one element.");
                });
    
                if (!found) throw new Error("Single:No element satisfies the condition.");
                return value;
            },
    
            // Overload:function(defaultValue)
            // Overload:function(defaultValue,predicate)
            SingleOrDefault: function (defaultValue, predicate)
            {
                if (predicate != null) return this.Where(predicate).SingleOrDefault(defaultValue);
    
                var value;
                var found = false;
                this.ForEach(function (x)
                {
                    if (!found)
                    {
                        found = true;
                        value = x;
                    }
                    else throw new Error("Single:sequence contains more than one element.");
                });
    
                return (!found) ? defaultValue : value;
            },
    
            Skip: function (count)
            {
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var index = 0;
    
                    return new IEnumerator(
                        function ()
                        {
                            enumerator = source.GetEnumerator();
                            while (index++ < count && enumerator.MoveNext()) { };
                        },
                        function ()
                        {
                            return (enumerator.MoveNext())
                                ? this.Yield(enumerator.Current())
                                : false;
                        },
                        function () { Utils.Dispose(enumerator); })
                });
            },
    
            // Overload:function(predicate<element>)
            // Overload:function(predicate<element,index>)
            SkipWhile: function (predicate)
            {
                predicate = Utils.CreateLambda(predicate);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var index = 0;
                    var isSkipEnd = false;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            while (!isSkipEnd)
                            {
                                if (enumerator.MoveNext())
                                {
                                    if (!predicate(enumerator.Current(), index++))
                                    {
                                        isSkipEnd = true;
                                        return this.Yield(enumerator.Current());
                                    }
                                    continue;
                                }
                                else return false;
                            }
    
                            return (enumerator.MoveNext())
                                ? this.Yield(enumerator.Current())
                                : false;
    
                        },
                        function () { Utils.Dispose(enumerator); });
                });
            },
    
            Take: function (count)
            {
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var index = 0;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            return (index++ < count && enumerator.MoveNext())
                                ? this.Yield(enumerator.Current())
                                : false;
                        },
                        function () { Utils.Dispose(enumerator); }
                    )
                });
            },
    
            // Overload:function(predicate<element>)
            // Overload:function(predicate<element,index>)
            TakeWhile: function (predicate)
            {
                predicate = Utils.CreateLambda(predicate);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var index = 0;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            return (enumerator.MoveNext() && predicate(enumerator.Current(), index++))
                                ? this.Yield(enumerator.Current())
                                : false;
                        },
                        function () { Utils.Dispose(enumerator); });
                });
            },
    
            // Overload:function()
            // Overload:function(count)
            TakeExceptLast: function (count)
            {
                if (count == null) count = 1;
                var source = this;
    
                return new Enumerable(function ()
                {
                    if (count <= 0) return source.GetEnumerator(); // do nothing
    
                    var enumerator;
                    var q = [];
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            while (enumerator.MoveNext())
                            {
                                if (q.length == count)
                                {
                                    q.push(enumerator.Current());
                                    return this.Yield(q.shift());
                                }
                                q.push(enumerator.Current());
                            }
                            return false;
                        },
                        function () { Utils.Dispose(enumerator); });
                });
            },
    
            TakeFromLast: function (count)
            {
                if (count <= 0 || count == null) return Enumerable.Empty();
                var source = this;
    
                return new Enumerable(function ()
                {
                    var sourceEnumerator;
                    var enumerator;
                    var q = [];
    
                    return new IEnumerator(
                        function () { sourceEnumerator = source.GetEnumerator(); },
                        function ()
                        {
                            while (sourceEnumerator.MoveNext())
                            {
                                if (q.length == count) q.shift()
                                q.push(sourceEnumerator.Current());
                            }
                            if (enumerator == null)
                            {
                                enumerator = Enumerable.From(q).GetEnumerator();
                            }
                            return (enumerator.MoveNext())
                                ? this.Yield(enumerator.Current())
                                : false;
                        },
                        function () { Utils.Dispose(enumerator); });
                });
            },
    
            IndexOf: function (item)
            {
                var found = null;
                this.ForEach(function (x, i)
                {
                    if (x === item)
                    {
                        found = i;
                        return true;
                    }
                });
    
                return (found !== null) ? found : -1;
            },
    
            LastIndexOf: function (item)
            {
                var result = -1;
                this.ForEach(function (x, i)
                {
                    if (x === item) result = i;
                });
    
                return result;
            },
    
            /* Convert Methods */
    
            ToArray: function ()
            {
                var array = [];
                this.ForEach(function (x) { array.push(x) });
                return array;
            },
    
            // Overload:function(keySelector)
            // Overload:function(keySelector, elementSelector)
            // Overload:function(keySelector, elementSelector, compareSelector)
            ToLookup: function (keySelector, elementSelector, compareSelector)
            {
                keySelector = Utils.CreateLambda(keySelector);
                elementSelector = Utils.CreateLambda(elementSelector);
                compareSelector = Utils.CreateLambda(compareSelector);
    
                var dict = new Dictionary(compareSelector);
                this.ForEach(function (x)
                {
                    var key = keySelector(x);
                    var element = elementSelector(x);
    
                    var array = dict.Get(key);
                    if (array !== undefined) array.push(element);
                    else dict.Add(key, [element]);
                });
                return new Lookup(dict);
            },
    
            ToObject: function (keySelector, elementSelector)
            {
                keySelector = Utils.CreateLambda(keySelector);
                elementSelector = Utils.CreateLambda(elementSelector);
    
                var obj = {};
                this.ForEach(function (x)
                {
                    obj[keySelector(x)] = elementSelector(x);
                });
                return obj;
            },
    
            // Overload:function(keySelector, elementSelector)
            // Overload:function(keySelector, elementSelector, compareSelector)
            ToDictionary: function (keySelector, elementSelector, compareSelector)
            {
                keySelector = Utils.CreateLambda(keySelector);
                elementSelector = Utils.CreateLambda(elementSelector);
                compareSelector = Utils.CreateLambda(compareSelector);
    
                var dict = new Dictionary(compareSelector);
                this.ForEach(function (x)
                {
                    dict.Add(keySelector(x), elementSelector(x));
                });
                return dict;
            },
    
            // Overload:function()
            // Overload:function(replacer)
            // Overload:function(replacer, space)
            ToJSON: function (replacer, space)
            {
                return JSON.stringify(this.ToArray(), replacer, space);
            },
    
            // Overload:function()
            // Overload:function(separator)
            // Overload:function(separator,selector)
            ToString: function (separator, selector)
            {
                if (separator == null) separator = "";
                if (selector == null) selector = Functions.Identity;
    
                return this.Select(selector).ToArray().join(separator);
            },
    
    
            /* Action Methods */
    
            // Overload:function(action<element>)
            // Overload:function(action<element,index>)
            Do: function (action)
            {
                var source = this;
                action = Utils.CreateLambda(action);
    
                return new Enumerable(function ()
                {
                    var enumerator;
                    var index = 0;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            if (enumerator.MoveNext())
                            {
                                action(enumerator.Current(), index++);
                                return this.Yield(enumerator.Current());
                            }
                            return false;
                        },
                        function () { Utils.Dispose(enumerator); });
                });
            },
    
            // Overload:function(action<element>)
            // Overload:function(action<element,index>)
            // Overload:function(func<element,bool>)
            // Overload:function(func<element,index,bool>)
            ForEach: function (action)
            {
                action = Utils.CreateLambda(action);
    
                var index = 0;
                var enumerator = this.GetEnumerator();
                try
                {
                    while (enumerator.MoveNext())
                    {
                        if (action(enumerator.Current(), index++) === false) break;
                    }
                }
                finally { Utils.Dispose(enumerator); }
            },
    
            // Overload:function()
            // Overload:function(separator)
            // Overload:function(separator,selector)
            Write: function (separator, selector)
            {
                if (separator == null) separator = "";
                selector = Utils.CreateLambda(selector);
    
                var isFirst = true;
                this.ForEach(function (item)
                {
                    if (isFirst) isFirst = false;
                    else document.write(separator);
                    document.write(selector(item));
                });
            },
    
            // Overload:function()
            // Overload:function(selector)
            WriteLine: function (selector)
            {
                selector = Utils.CreateLambda(selector);
    
                this.ForEach(function (item)
                {
                    document.write(selector(item));
                    document.write("<br />");
                });
            },
    
            Force: function ()
            {
                var enumerator = this.GetEnumerator();
    
                try { while (enumerator.MoveNext()) { } }
                finally { Utils.Dispose(enumerator); }
            },
    
            /* Functional Methods */
    
            Let: function (func)
            {
                func = Utils.CreateLambda(func);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
    
                    return new IEnumerator(
                        function ()
                        {
                            enumerator = Enumerable.From(func(source)).GetEnumerator();
                        },
                        function ()
                        {
                            return (enumerator.MoveNext())
                                ? this.Yield(enumerator.Current())
                                : false;
                        },
                        function () { Utils.Dispose(enumerator); })
                });
            },
    
            Share: function ()
            {
                var source = this;
                var sharedEnumerator;
    
                return new Enumerable(function ()
                {
                    return new IEnumerator(
                        function ()
                        {
                            if (sharedEnumerator == null)
                            {
                                sharedEnumerator = source.GetEnumerator();
                            }
                        },
                        function ()
                        {
                            return (sharedEnumerator.MoveNext())
                                ? this.Yield(sharedEnumerator.Current())
                                : false;
                        },
                        Functions.Blank
                    )
                });
            },
    
            MemoizeAll: function ()
            {
                var source = this;
                var cache;
                var enumerator;
    
                return new Enumerable(function ()
                {
                    var index = -1;
    
                    return new IEnumerator(
                        function ()
                        {
                            if (enumerator == null)
                            {
                                enumerator = source.GetEnumerator();
                                cache = [];
                            }
                        },
                        function ()
                        {
                            index++;
                            if (cache.length <= index)
                            {
                                return (enumerator.MoveNext())
                                    ? this.Yield(cache[index] = enumerator.Current())
                                    : false;
                            }
    
                            return this.Yield(cache[index]);
                        },
                        Functions.Blank
                    )
                });
            },
    
            /* Error Handling Methods */
    
            Catch: function (handler)
            {
                handler = Utils.CreateLambda(handler);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            try
                            {
                                return (enumerator.MoveNext())
                                   ? this.Yield(enumerator.Current())
                                   : false;
                            }
                            catch (e)
                            {
                                handler(e);
                                return false;
                            }
                        },
                        function () { Utils.Dispose(enumerator); });
                });
            },
    
            Finally: function (finallyAction)
            {
                finallyAction = Utils.CreateLambda(finallyAction);
                var source = this;
    
                return new Enumerable(function ()
                {
                    var enumerator;
    
                    return new IEnumerator(
                        function () { enumerator = source.GetEnumerator(); },
                        function ()
                        {
                            return (enumerator.MoveNext())
                               ? this.Yield(enumerator.Current())
                               : false;
                        },
                        function ()
                        {
                            try { Utils.Dispose(enumerator); }
                            finally { finallyAction(); }
                        });
                });
            },
    
            /* For Debug Methods */
    
            // Overload:function()
            // Overload:function(message)
            // Overload:function(message,selector)
            Trace: function (message, selector)
            {
                if (message == null) message = "Trace";
                selector = Utils.CreateLambda(selector);
    
                return this.Do(function (item)
                {
                    console.log(message, ":", selector(item));
                });
            }
        }
    
        // private
    
        // static functions
        var Functions =
        {
            Identity: function (x) { return x; },
            True: function () { return true; },
            Blank: function () { }
        }
    
        // static const
        var Types =
        {
            Boolean: typeof true,
            Number: typeof 0,
            String: typeof "",
            Object: typeof {},
            Undefined: typeof undefined,
            Function: typeof function () { }
        }
    
        // static utility methods
        var Utils =
        {
            // Create anonymous function from lambda expression string
            CreateLambda: function (expression)
            {
                if (expression == null) return Functions.Identity;
                if (typeof expression == Types.String)
                {
                    if (expression == "")
                    {
                        return Functions.Identity;
                    }
                    else if (expression.indexOf("=>") == -1)
                    {
                        return new Function("$,$$,$$$,$$$$", "return " + expression);
                    }
                    else
                    {
                        var expr = expression.match(/^[(s]*([^()]*?)[)s]*=>(.*)/);
                        return new Function(expr[1], "return " + expr[2]);
                    }
                }
                return expression;
            },
    
            IsIEnumerable: function (obj)
            {
                if (typeof Enumerator != Types.Undefined)
                {
                    try
                    {
                        new Enumerator(obj);
                        return true;
                    }
                    catch (e) { }
                }
                return false;
            },
    
            Compare: function (a, b)
            {
                return (a === b) ? 0
                    : (a > b) ? 1
                    : -1;
            },
    
            Dispose: function (obj)
            {
                if (obj != null) obj.Dispose();
            }
        }
    
        // IEnumerator State
        var State = { Before: 0, Running: 1, After: 2 }
    
        // name "Enumerator" is conflict JScript's "Enumerator"
        var IEnumerator = function (initialize, tryGetNext, dispose)
        {
            var yielder = new Yielder();
            var state = State.Before;
    
            this.Current = yielder.Current;
            this.MoveNext = function ()
            {
                try
                {
                    switch (state)
                    {
                        case State.Before:
                            state = State.Running;
                            initialize(); // fall through
                        case State.Running:
                            if (tryGetNext.apply(yielder))
                            {
                                return true;
                            }
                            else
                            {
                                this.Dispose();
                                return false;
                            }
                        case State.After:
                            return false;
                    }
                }
                catch (e)
                {
                    this.Dispose();
                    throw e;
                }
            }
            this.Dispose = function ()
            {
                if (state != State.Running) return;
    
                try { dispose(); }
                finally { state = State.After; }
            }
        }
    
        // for tryGetNext
        var Yielder = function ()
        {
            var current = null;
            this.Current = function () { return current; }
            this.Yield = function (value)
            {
                current = value;
                return true;
            }
        }
    
        // for OrderBy/ThenBy
    
        var OrderedEnumerable = function (source, keySelector, descending, parent)
        {
            this.source = source;
            this.keySelector = Utils.CreateLambda(keySelector);
            this.descending = descending;
            this.parent = parent;
        }
        OrderedEnumerable.prototype = new Enumerable();
    
        OrderedEnumerable.prototype.CreateOrderedEnumerable = function (keySelector, descending)
        {
            return new OrderedEnumerable(this.source, keySelector, descending, this);
        }
    
        OrderedEnumerable.prototype.ThenBy = function (keySelector)
        {
            return this.CreateOrderedEnumerable(keySelector, false);
        }
    
        OrderedEnumerable.prototype.ThenByDescending = function (keySelector)
        {
            return this.CreateOrderedEnumerable(keySelector, true);
        }
    
        OrderedEnumerable.prototype.GetEnumerator = function ()
        {
            var self = this;
            var buffer;
            var indexes;
            var index = 0;
    
            return new IEnumerator(
                function ()
                {
                    buffer = [];
                    indexes = [];
                    self.source.ForEach(function (item, index)
                    {
                        buffer.push(item);
                        indexes.push(index);
                    });
                    var sortContext = SortContext.Create(self, null);
                    sortContext.GenerateKeys(buffer);
    
                    indexes.sort(function (a, b) { return sortContext.Compare(a, b); });
                },
                function ()
                {
                    return (index < indexes.length)
                        ? this.Yield(buffer[indexes[index++]])
                        : false;
                },
                Functions.Blank
            )
        }
    
        var SortContext = function (keySelector, descending, child)
        {
            this.keySelector = keySelector;
            this.descending = descending;
            this.child = child;
            this.keys = null;
        }
    
        SortContext.Create = function (orderedEnumerable, currentContext)
        {
            var context = new SortContext(orderedEnumerable.keySelector, orderedEnumerable.descending, currentContext);
            if (orderedEnumerable.parent != null) return SortContext.Create(orderedEnumerable.parent, context);
            return context;
        }
    
        SortContext.prototype.GenerateKeys = function (source)
        {
            var len = source.length;
            var keySelector = this.keySelector;
            var keys = new Array(len);
            for (var i = 0; i < len; i++) keys[i] = keySelector(source[i]);
            this.keys = keys;
    
            if (this.child != null) this.child.GenerateKeys(source);
        }
    
        SortContext.prototype.Compare = function (index1, index2)
        {
            var comparison = Utils.Compare(this.keys[index1], this.keys[index2]);
    
            if (comparison == 0)
            {
                if (this.child != null) return this.child.Compare(index1, index2)
                comparison = Utils.Compare(index1, index2);
            }
    
            return (this.descending) ? -comparison : comparison;
        }
    
        // optimize array or arraylike object
    
        var ArrayEnumerable = function (source)
        {
            this.source = source;
        }
        ArrayEnumerable.prototype = new Enumerable();
    
        ArrayEnumerable.prototype.Any = function (predicate)
        {
            return (predicate == null)
                ? (this.source.length > 0)
                : Enumerable.prototype.Any.apply(this, arguments);
        }
    
        ArrayEnumerable.prototype.Count = function (predicate)
        {
            return (predicate == null)
                ? this.source.length
                : Enumerable.prototype.Count.apply(this, arguments);
        }
    
        ArrayEnumerable.prototype.ElementAt = function (index)
        {
            return (0 <= index && index < this.source.length)
                ? this.source[index]
                : Enumerable.prototype.ElementAt.apply(this, arguments);
        }
    
        ArrayEnumerable.prototype.ElementAtOrDefault = function (index, defaultValue)
        {
            return (0 <= index && index < this.source.length)
                ? this.source[index]
                : defaultValue;
        }
    
        ArrayEnumerable.prototype.First = function (predicate)
        {
            return (predicate == null && this.source.length > 0)
                ? this.source[0]
                : Enumerable.prototype.First.apply(this, arguments);
        }
    
        ArrayEnumerable.prototype.FirstOrDefault = function (defaultValue, predicate)
        {
            if (predicate != null)
            {
                return Enumerable.prototype.FirstOrDefault.apply(this, arguments);
            }
    
            return this.source.length > 0 ? this.source[0] : defaultValue;
        }
    
        ArrayEnumerable.prototype.Last = function (predicate)
        {
            return (predicate == null && this.source.length > 0)
                ? this.source[this.source.length - 1]
                : Enumerable.prototype.Last.apply(this, arguments);
        }
    
        ArrayEnumerable.prototype.LastOrDefault = function (defaultValue, predicate)
        {
            if (predicate != null)
            {
                return Enumerable.prototype.LastOrDefault.apply(this, arguments);
            }
    
            return this.source.length > 0 ? this.source[this.source.length - 1] : defaultValue;
        }
    
        ArrayEnumerable.prototype.Skip = function (count)
        {
            var source = this.source;
    
            return new Enumerable(function ()
            {
                var index;
    
                return new IEnumerator(
                    function () { index = (count < 0) ? 0 : count },
                    function ()
                    {
                        return (index < source.length)
                            ? this.Yield(source[index++])
                            : false;
                    },
                    Functions.Blank);
            });
        };
    
        ArrayEnumerable.prototype.TakeExceptLast = function (count)
        {
            if (count == null) count = 1;
            return this.Take(this.source.length - count);
        }
    
        ArrayEnumerable.prototype.TakeFromLast = function (count)
        {
            return this.Skip(this.source.length - count);
        }
    
        ArrayEnumerable.prototype.Reverse = function ()
        {
            var source = this.source;
    
            return new Enumerable(function ()
            {
                var index;
    
                return new IEnumerator(
                    function ()
                    {
                        index = source.length;
                    },
                    function ()
                    {
                        return (index > 0)
                            ? this.Yield(source[--index])
                            : false;
                    },
                    Functions.Blank)
            });
        }
    
        ArrayEnumerable.prototype.SequenceEqual = function (second, compareSelector)
        {
            if ((second instanceof ArrayEnumerable || second instanceof Array)
                && compareSelector == null
                && Enumerable.From(second).Count() != this.Count())
            {
                return false;
            }
    
            return Enumerable.prototype.SequenceEqual.apply(this, arguments);
        }
    
        ArrayEnumerable.prototype.ToString = function (separator, selector)
        {
            if (selector != null || !(this.source instanceof Array))
            {
                return Enumerable.prototype.ToString.apply(this, arguments);
            }
    
            if (separator == null) separator = "";
            return this.source.join(separator);
        }
    
        ArrayEnumerable.prototype.GetEnumerator = function ()
        {
            var source = this.source;
            var index = 0;
    
            return new IEnumerator(
                Functions.Blank,
                function ()
                {
                    return (index < source.length)
                        ? this.Yield(source[index++])
                        : false;
                },
                Functions.Blank);
        }
    
        // Collections
    
        var Dictionary = (function ()
        {
            // static utility methods
            var HasOwnProperty = function (target, key)
            {
                return Object.prototype.hasOwnProperty.call(target, key);
            }
    
            var ComputeHashCode = function (obj)
            {
                if (obj === null) return "null";
                if (obj === undefined) return "undefined";
    
                return (typeof obj.toString === Types.Function)
                    ? obj.toString()
                    : Object.prototype.toString.call(obj);
            }
    
            // LinkedList for Dictionary
            var HashEntry = function (key, value)
            {
                this.Key = key;
                this.Value = value;
                this.Prev = null;
                this.Next = null;
            }
    
            var EntryList = function ()
            {
                this.First = null;
                this.Last = null;
            }
            EntryList.prototype =
            {
                AddLast: function (entry)
                {
                    if (this.Last != null)
                    {
                        this.Last.Next = entry;
                        entry.Prev = this.Last;
                        this.Last = entry;
                    }
                    else this.First = this.Last = entry;
                },
    
                Replace: function (entry, newEntry)
                {
                    if (entry.Prev != null)
                    {
                        entry.Prev.Next = newEntry;
                        newEntry.Prev = entry.Prev;
                    }
                    else this.First = newEntry;
    
                    if (entry.Next != null)
                    {
                        entry.Next.Prev = newEntry;
                        newEntry.Next = entry.Next;
                    }
                    else this.Last = newEntry;
    
                },
    
                Remove: function (entry)
                {
                    if (entry.Prev != null) entry.Prev.Next = entry.Next;
                    else this.First = entry.Next;
    
                    if (entry.Next != null) entry.Next.Prev = entry.Prev;
                    else this.Last = entry.Prev;
                }
            }
    
            // Overload:function()
            // Overload:function(compareSelector)
            var Dictionary = function (compareSelector)
            {
                this.count = 0;
                this.entryList = new EntryList();
                this.buckets = {}; // as Dictionary<string,List<object>>
                this.compareSelector = (compareSelector == null) ? Functions.Identity : compareSelector;
            }
    
            Dictionary.prototype =
            {
                Add: function (key, value)
                {
                    var compareKey = this.compareSelector(key);
                    var hash = ComputeHashCode(compareKey);
                    var entry = new HashEntry(key, value);
                    if (HasOwnProperty(this.buckets, hash))
                    {
                        var array = this.buckets[hash];
                        for (var i = 0; i < array.length; i++)
                        {
                            if (this.compareSelector(array[i].Key) === compareKey)
                            {
                                this.entryList.Replace(array[i], entry);
                                array[i] = entry;
                                return;
                            }
                        }
                        array.push(entry);
                    }
                    else
                    {
                        this.buckets[hash] = [entry];
                    }
                    this.count++;
                    this.entryList.AddLast(entry);
                },
    
                Get: function (key)
                {
                    var compareKey = this.compareSelector(key);
                    var hash = ComputeHashCode(compareKey);
                    if (!HasOwnProperty(this.buckets, hash)) return undefined;
    
                    var array = this.buckets[hash];
                    for (var i = 0; i < array.length; i++)
                    {
                        var entry = array[i];
                        if (this.compareSelector(entry.Key) === compareKey) return entry.Value;
                    }
                    return undefined;
                },
    
                Set: function (key, value)
                {
                    var compareKey = this.compareSelector(key);
                    var hash = ComputeHashCode(compareKey);
                    if (HasOwnProperty(this.buckets, hash))
                    {
                        var array = this.buckets[hash];
                        for (var i = 0; i < array.length; i++)
                        {
                            if (this.compareSelector(array[i].Key) === compareKey)
                            {
                                var newEntry = new HashEntry(key, value);
                                this.entryList.Replace(array[i], newEntry);
                                array[i] = newEntry;
                                return true;
                            }
                        }
                    }
                    return false;
                },
    
                Contains: function (key)
                {
                    var compareKey = this.compareSelector(key);
                    var hash = ComputeHashCode(compareKey);
                    if (!HasOwnProperty(this.buckets, hash)) return false;
    
                    var array = this.buckets[hash];
                    for (var i = 0; i < array.length; i++)
                    {
                        if (this.compareSelector(array[i].Key) === compareKey) return true;
                    }
                    return false;
                },
    
                Clear: function ()
                {
                    this.count = 0;
                    this.buckets = {};
                    this.entryList = new EntryList();
                },
    
                Remove: function (key)
                {
                    var compareKey = this.compareSelector(key);
                    var hash = ComputeHashCode(compareKey);
                    if (!HasOwnProperty(this.buckets, hash)) return;
    
                    var array = this.buckets[hash];
                    for (var i = 0; i < array.length; i++)
                    {
                        if (this.compareSelector(array[i].Key) === compareKey)
                        {
                            this.entryList.Remove(array[i]);
                            array.splice(i, 1);
                            if (array.length == 0) delete this.buckets[hash];
                            this.count--;
                            return;
                        }
                    }
                },
    
                Count: function ()
                {
                    return this.count;
                },
    
                ToEnumerable: function ()
                {
                    var self = this;
                    return new Enumerable(function ()
                    {
                        var currentEntry;
    
                        return new IEnumerator(
                            function () { currentEntry = self.entryList.First },
                            function ()
                            {
                                if (currentEntry != null)
                                {
                                    var result = { Key: currentEntry.Key, Value: currentEntry.Value };
                                    currentEntry = currentEntry.Next;
                                    return this.Yield(result);
                                }
                                return false;
                            },
                            Functions.Blank);
                    });
                }
            }
    
            return Dictionary;
        })();
    
        // dictionary = Dictionary<TKey, TValue[]>
        var Lookup = function (dictionary)
        {
            this.Count = function ()
            {
                return dictionary.Count();
            }
    
            this.Get = function (key)
            {
                return Enumerable.From(dictionary.Get(key));
            }
    
            this.Contains = function (key)
            {
                return dictionary.Contains(key);
            }
    
            this.ToEnumerable = function ()
            {
                return dictionary.ToEnumerable().Select(function (kvp)
                {
                    return new Grouping(kvp.Key, kvp.Value);
                });
            }
        }
    
        var Grouping = function (key, elements)
        {
            this.Key = function ()
            {
                return key;
            }
    
            ArrayEnumerable.call(this, elements);
        }
        Grouping.prototype = new ArrayEnumerable();
    
        // out to global
        return Enumerable;
    })()
    View Code

    自己备着

  • 相关阅读:
    如何理解「复位 」?
    menuconfig配置
    编译Linux内核过程中遇到的问题与解决
    解决qt 5.14版本 qt.network.ssl: QSslSocket::connectToHostEncrypted: TLS initialization faile问题
    认真教好软件工程
    2016同学们博客链接汇总
    车站订票系统可行性分析报告
    第四纪与地貌学(1)——长江口第四纪沉积物中构造与古气候耦合作用的探讨
    软件工程(1)——对书本的温习
    四则运算
  • 原文地址:https://www.cnblogs.com/luo1240465012/p/11308664.html
Copyright © 2020-2023  润新知