diff --git a/ix.js/ix-tests.ts b/ix.js/ix-tests.ts
new file mode 100644
index 000000000..6953621ca
--- /dev/null
+++ b/ix.js/ix-tests.ts
@@ -0,0 +1,116 @@
+///
+
+var ec_ns = (a: number, b: string) => a.toString() == b; //equality comparer on number,string
+var ec_ss = (a: string, b: string) => a == b; //equality comparer on string,string
+var ec_nn = (a: number, b: number) => a === b; //equality comparer on number,number
+var c_nn = (a: number, b: number) => a - b; //comparer on number,number
+
+// static
+
+Ix.Enumerable.throw(new Error("error"));
+Ix.Enumerable.throwException(new Error("error"));
+
+var ax = Ix.Enumerable.generate(-100, a => a < 100, a=> a + 10, a=> a * 2);
+
+Ix.Enumerable.defer(() => ax);
+
+Ix.Enumerable.using(() => ax.getEnumerator(), e => Ix.Enumerable.return(e.getCurrent()));
+
+Ix.Enumerable.catch(ax, ax, ax);
+Ix.Enumerable.catchException(ax, ax, ax);
+Ix.Enumerable.catch();
+Ix.Enumerable.catchException();
+
+Ix.Enumerable.onErrorResumeNext(ax, ax, ax);
+Ix.Enumerable.onErrorResumeNext();
+
+Ix.Enumerable.while(x => x.count() > 0, ax);
+Ix.Enumerable.whileDo(x => x.count() > 0, ax);
+
+Ix.Enumerable.if(() => true, ax, ax);
+Ix.Enumerable.ifThen(() => true, ax, ax);
+Ix.Enumerable.if(() => true, ax);
+Ix.Enumerable.ifThen(() => true, ax);
+
+Ix.Enumerable.doWhile(ax, x => x.count() > 0);
+
+Ix.Enumerable.case(() => 42, { 42: ax }, ax);
+Ix.Enumerable.switchCase(() => 42, { 42: ax }, ax);
+Ix.Enumerable.case(() => 42, { 42: ax });
+Ix.Enumerable.switchCase(() => 42, { 42: ax });
+Ix.Enumerable.case(() => "42", { "42": ax }, ax);
+Ix.Enumerable.switchCase(() => "42", { "42": ax }, ax);
+Ix.Enumerable.case(() => "42", { "42": ax });
+Ix.Enumerable.switchCase(() => "42", { "42": ax });
+
+Ix.Enumerable.for(ax, a => ax);
+Ix.Enumerable.forIn(ax, a => ax);
+
+// instance
+
+var bx: Ix.Enumerable;
+
+ax.isEmpty();
+
+bx.minBy(b => b.length, c_nn);
+bx.minBy(b => b.length);
+bx.maxBy(b => b.length, c_nn);
+bx.maxBy(b => b.length);
+
+ax.share(ax => bx);
+ax.share();
+
+ax.publish(ax => bx);
+ax.publish();
+
+ax.memoize();
+
+ax.do({ onNext: (a: number) => console.log(a), onError: err => console.log(err), onCompleted: () => console.log("completed") });
+ax.do(a => console.log(a), err => console.log(err), () => console.log("completed"));
+ax.do(a => console.log(a), err => console.log(err));
+ax.do((a: number) => console.log(a));
+ax.doAction({ onNext: (a: number) => console.log(a), onError: err => console.log(err), onCompleted: () => console.log("completed") });
+ax.doAction(a => console.log(a), err => console.log(err), () => console.log("completed"));
+ax.doAction(a => console.log(a), err => console.log(err));
+ax.doAction((a: number) => console.log(a));
+
+ax.bufferWithCount(10, 20);
+ax.bufferWithCount(10);
+
+ax.ignoreElements();
+
+bx.distinctBy(b => b.length, ec_nn);
+bx.distinctBy(b => b.length);
+
+bx.distinctUntilChanged(b => b.length, ec_nn);
+bx.distinctUntilChanged(b => b.length);
+bx.distinctUntilChanged();
+bx.distinctUntilChanged(false, ec_ss);
+
+ax.expand(a => ax);
+
+ax.startWith(10, 20);
+
+ax.scan(0, (acc, a) => acc + a);
+ax.scan((acc, a) => acc + a);
+
+ax.takeLast(10);
+ax.skipLast(10);
+
+ax.repeat(10);
+ax.repeat();
+
+ax.catch(ax, ax, ax);
+ax.catchException(ax, ax, ax);
+ax.catch(ax);
+ax.catchException(ax);
+ax.catch(err => ax);
+ax.catchException(err => ax);
+
+ax.finally(() => { });
+ax.finallyDo(() => { });
+
+ax.onErrorResumeNext(ax);
+
+ax.retry(10);
+ax.retry();
diff --git a/ix.js/ix.d.ts b/ix.js/ix.d.ts
new file mode 100644
index 000000000..614a950fb
--- /dev/null
+++ b/ix.js/ix.d.ts
@@ -0,0 +1,112 @@
+// Type definitions for IxJS 1.0.6 / ix.js
+// Project: https://github.com/Reactive-Extensions/IxJS
+// Definitions by: Igor Oleinikov
+
+///
+
+declare module Ix {
+
+ export interface Observer {
+ onNext? (value: T): void;
+ onError? (error: Error): void;
+ onCompleted? (): void;
+ }
+
+ export interface Enumerable {
+ isEmpty(): boolean;
+
+ minBy(keySelector: (item: T) => TKey, comparer: Comparer): Enumerable;
+ minBy(keySelector: (item: T) => number): Enumerable;
+ maxBy(keySelector: (item: T) => TKey, comparer: Comparer): Enumerable;
+ maxBy(keySelector: (item: T) => number): Enumerable;
+
+ share(selector: (source: Enumerable) => Enumerable): Enumerable;
+ share(): Enumerable;
+
+ publish(selector: (source: Enumerable) => Enumerable): Enumerable;
+ publish(): Enumerable;
+
+ memoize(): Enumerable;
+
+ do(onNext: (value: T) => void, onError?: (error: Error) => void, onCompleted?: () => void): Enumerable;
+ doAction(onNext: (value: T) => void, onError?: (error: Error) => void, onCompleted?: () => void): Enumerable;
+ do(onbserver: Observer): Enumerable;
+ doAction(onbserver: Observer): Enumerable;
+
+ bufferWithCount(count: number, skip?: number): Enumerable;
+
+ ignoreElements(): Enumerable;
+
+ distinctBy(keySelector: (item: T) => TKey, comparer?: EqualityComparer): Enumerable;
+
+ distinctUntilChanged(keySelector: (item: T) => TKey, comparer?: EqualityComparer): Enumerable;
+ distinctUntilChanged(): Enumerable;
+ // if need to set comparer without keySelector
+ distinctUntilChanged(_: boolean, comparer: EqualityComparer): Enumerable;
+
+ expand(selector: (item: T) => Enumerable): Enumerable;
+
+ startWith(...values: T[]): Enumerable;
+
+ scan(seed: TSeed, accumulate: (acc: TAccumulator, item: T) => TAccumulator): Enumerable;
+ scan(accumulate: (acc: T, item: T) => T): Enumerable;
+
+ takeLast(count: number): Enumerable;
+ skipLast(count: number): Enumerable;
+
+ repeat(count?: number): Enumerable;
+
+ catch(handler: (error: Error) => Enumerable): Enumerable;
+ catchException(handler: (error: Error) => Enumerable): Enumerable;
+ catch(second: Enumerable, ...other: Enumerable[]): Enumerable;
+ catchException(second: Enumerable, ...other: Enumerable[]): Enumerable;
+
+ // todo: Enumerable>.catch(): Enumerable
+ //catch>(): Enumerable;
+
+ finally(finallyAction: () => void): Enumerable;
+ finallyDo(finallyAction: () => void): Enumerable;
+
+ onErrorResumeNext(second: Enumerable): Enumerable;
+
+ retry(retryCount?: number): Enumerable;
+ }
+
+ export interface EnumerableStatic {
+ throw(error: Error): Enumerable;
+ throwException(error: Error): Enumerable;
+
+ defer(enumerableFactory: () => Enumerable): Enumerable;
+
+ generate(
+ initialState: TState,
+ condition: Predicate,
+ iterate: (state: TState) => TState,
+ resultSelector: (state: TState) => TResult): Enumerable;
+
+ using(
+ resourceFactory: () => TResource,
+ enumerableFactory: (resource: TResource) => Enumerable): Enumerable;
+
+ catch(...sources: Enumerable[]): Enumerable;
+ catchException(...sources: Enumerable[]): Enumerable;
+
+ onErrorResumeNext(...sources: Enumerable[]): Enumerable;
+
+ while(condition: EnumerablePredicate>, source: Enumerable): Enumerable;
+ whileDo(condition: EnumerablePredicate>, source: Enumerable): Enumerable;
+
+ if(condition: () => boolean, thenSource: Enumerable, elseSource?: Enumerable): Enumerable;
+ ifThen(condition: () => boolean, thenSource: Enumerable, elseSource?: Enumerable): Enumerable;
+
+ doWhile(source: Enumerable, condition: EnumerablePredicate>): Enumerable;
+
+ case(selector: () => number, sources: { [key: number]: Enumerable; }, defaultSource?: Enumerable): Enumerable;
+ case(selector: () => string, sources: { [key: string]: Enumerable; }, defaultSource?: Enumerable): Enumerable;
+ switchCase(selector: () => number, sources: { [key: number]: Enumerable; }, defaultSource?: Enumerable): Enumerable;
+ switchCase(selector: () => string, sources: { [key: string]: Enumerable; }, defaultSource?: Enumerable): Enumerable;
+
+ for(source: Enumerable, resultSelector: EnumerableFunc): Enumerable;
+ forIn(source: Enumerable, resultSelector: EnumerableFunc): Enumerable;
+ }
+}
diff --git a/ix.js/l2o-tests.ts b/ix.js/l2o-tests.ts
new file mode 100644
index 000000000..2399d4e9f
--- /dev/null
+++ b/ix.js/l2o-tests.ts
@@ -0,0 +1,221 @@
+///
+
+var ec_ns = (a: number, b: string) => a.toString() == b; //equality comparer on number,string
+var ec_nn = (a: number, b: number) => a === b; //equality comparer on number,number
+var c_nn = (a: number, b: number) => a - b; //comparer on number,number
+
+// static
+
+var ax = Ix.Enumerable.fromArray([0, 2, 7, 3, 4, 5]);
+
+var bx = Ix.Enumerable.create(() => {
+ var current = ".";
+ return Ix.Enumerator.create(
+ () => { current += "."; return true; },
+ () => current,
+ () => { });
+});
+
+Ix.Enumerator.create(() => true, () => 1); // without dispose method
+
+var cx = Ix.Enumerable.empty();
+
+var dx = Ix.Enumerable.concat(ax, cx);
+
+var ex = Ix.Enumerable.return(42);
+var fx = Ix.Enumerable.returnValue("42");
+
+var gx = Ix.Enumerable.range(-100, 200);
+
+Ix.Enumerable.repeat(42, 42);
+Ix.Enumerable.repeat(42); // infinite
+
+Ix.Enumerable.sequenceEqual(ax, fx, ec_ns);
+Ix.Enumerable.sequenceEqual(ax, ex); // default comparer on same type
+
+// instance
+
+ax.getEnumerator();
+
+ax.aggregate("", (acc, i) => acc + i, acc=> acc.length);
+ax.aggregate("", (acc, i) => acc + i);
+ax.aggregate((acc, i) => acc + i);
+
+ax.reduce((acc, i) => acc + i, 100);
+ax.reduce((acc, i) => acc + i);
+
+ax.all(item => true);
+ax.all(item => true, bx);
+ax.every(item => true);
+ax.every(item => true, bx);
+
+ax.any();
+ax.any(item => true);
+ax.any(item => true, bx);
+ax.some();
+ax.some(item => true);
+ax.some(item => true, bx);
+
+ax.average();
+bx.average(item => item.length);
+ax.min();
+bx.min(item => item.length);
+ax.max();
+bx.max(item => item.length);
+ax.sum();
+bx.sum(item => item.length);
+
+ax.concat(ax, cx, dx, ex, gx);
+
+ax.contains(10);
+ax.contains("10", ec_ns);
+
+ax.count();
+ax.count(item=>false);
+ax.count(item=> false, {});
+
+cx.defaultIfEmpty();
+cx.defaultIfEmpty(10);
+
+dx.distinct();
+dx.distinct((d1, d2) => d1 === d2);
+
+ax.elementAt(2);
+ax.elementAtOrDefault(2);
+
+//ax.except(bx, ec_ns); // bug https://typescript.codeplex.com/workitem/1841
+bx.except(fx);
+
+ax.first();
+ax.firstOrDefault();
+ax.last();
+ax.lastOrDefault();
+ax.single();
+ax.singleOrDefault();
+
+ax.forEach(a => console.log(a));
+ax.forEach(a => console.log(a), cx);
+
+//bx.groupBy(b => b.length); // spec 3.5.2, waiting for restriction on generative recursion removal
+bx.groupBy(b => b.length, b => "[" + b + "]");
+bx.groupBy(b => b.length, b => "[" + b + "]", (l, values) => l + values.count());
+bx.groupBy(b => b.length, false, (l, values) => l + values.count());
+bx.groupBy(b => b.length, b => "[" + b + "]", (l, values) => l + values.count(), ec_nn);
+bx.groupBy(b => b.length, b => "[" + b + "]", false, (x, y) => x == y);
+bx.groupBy(b => b.length, false, (l, values) => l + values.count(), ec_nn);
+//bx.groupBy(b => b.length, false, false, ec_nn); // spec 3.5.2, waiting for restriction on generative recursion removal
+
+ax.groupJoin(bx, a => a, b => b, (a, b) => [a, b], ec_ns);
+ax.groupJoin(bx, a => a, b => b.length, (a, b) => [a, b]);
+
+ax.join(bx, a => a, b => b, (a, b) => [a, b], ec_ns);
+ax.join(bx, a => a, b => b.length, (a, b) => [a, b]);
+
+//ax.intersect(bx, ec_ns); // bug https://typescript.codeplex.com/workitem/1841
+ax.intersect(cx);
+ax.union(cx);
+
+ax.orderBy(a=> -a).thenBy(a => a);
+ax.orderBy(a=> -a, c_nn).thenBy(a => a, c_nn);
+ax.orderByDescending(a=> -a).thenByDescending(a => a);
+ax.orderByDescending(a=> -a, c_nn).thenByDescending(a => a, c_nn);
+
+ax.reverse();
+
+ax.select(a=> a.toString());
+ax.select(a=> a.toString(), {});
+ax.map(a=> a.toString());
+ax.map(a=> a.toString(), {});
+
+ax.selectMany(a=> bx);
+ax.selectMany(a=> bx, (a, b) => [a, b]);
+
+ax.sequenceEqual(fx, ec_ns);
+ax.sequenceEqual(ax, ec_nn);
+ax.sequenceEqual(cx);
+
+ax.skip(10);
+ax.skipWhile(a => a > 10);
+ax.take(10);
+ax.takeWhile(a => a > 10);
+
+ax.toArray();
+
+bx.toDictionary(b => b.length, b => 10, ec_nn);
+//bx.toDictionary(b => b.length, false, ec_nn); // spec 3.5.2, waiting for restriction on generative recursion removal
+bx.toDictionary(b => b.length, b => 10);
+//bx.toDictionary(b => b.length); // spec 3.5.2, waiting for restriction on generative recursion removal
+
+bx.toLookup(b => b.length, b => 10, ec_nn);
+//bx.toLookup(b => b.length, false, ec_nn); // spec 3.5.2, waiting for restriction on generative recursion removal
+bx.toLookup(b => b.length, b => 10);
+//bx.toLookup(b => b.length); // spec 3.5.2, waiting for restriction on generative recursion removal
+
+ax.where(a=> a > 10, {});
+ax.where(a=> a > 10);
+ax.filter(a=> a > 10, {});
+ax.filter(a=> a > 10);
+
+ax.zip(bx, (a: number, b: string) => [a, b]);
+ax.zip(bx, (a, b) => [a, b]);
+
+// Disposable
+
+{
+ var d: Ix.Disposable;
+
+ d.dispose();
+}
+
+// Enumerator
+
+{
+ var e: Ix.Enumerator;
+
+ try {
+ while (e.moveNext()) { var c = e.getCurrent(); }
+ }
+ finally {
+ e.dispose();
+ }
+}
+
+// Dictionary
+
+{
+ var dic = new Ix.Dictionary(0, ec_nn);
+
+ var key = dic.toEnumerable().first().key;
+ var value = dic.toEnumerable().first().value;
+
+ dic.add(1, "1");
+ dic.remove(1);
+ dic.clear();
+ dic.length();
+ dic.tryGetValue(1);
+ dic.get(1);
+ dic.set(1, "1");
+ dic.getValues();
+ dic.has(1);
+}
+
+// KeyValuePair
+
+{
+ var kv: Ix.KeyValuePair;
+ var key = kv.key;
+ var value = kv.value;
+}
+
+// Lookup
+
+{
+ var lookup: Ix.Lookup;
+
+ var key = lookup.toEnumerable().first().key;
+ lookup.toEnumerable().first().first();
+
+ lookup.has(1);
+ lookup.length();
+ lookup.get(1).first();
+}
\ No newline at end of file
diff --git a/ix.js/l2o.d.ts b/ix.js/l2o.d.ts
new file mode 100644
index 000000000..c3f3c415e
--- /dev/null
+++ b/ix.js/l2o.d.ts
@@ -0,0 +1,256 @@
+// Type definitions for IxJS 1.0.6 / l2o.js
+// Project: https://github.com/Reactive-Extensions/IxJS
+// Definitions by: Igor Oleinikov
+
+declare module Ix {
+ export interface Disposable {
+ dispose(): void;
+ }
+
+ export interface Enumerator extends Disposable {
+ moveNext(): boolean;
+ getCurrent(): T;
+ }
+
+ export interface EnumeratorStatic {
+ new (moveNext: () => boolean, getCurrent: () => T, dispose: () => void): Enumerator;
+ create(moveNext: () => boolean, getCurrent: () => T, dispose?: () => void): Enumerator;
+ }
+
+ var Enumerator: EnumeratorStatic;
+
+ export interface EnumerableFunc {
+ (item: T, index: number, self: Enumerable): TResult;
+ }
+ export interface EnumerablePredicate extends EnumerableFunc { }
+ export interface Predicate {
+ (item: T): boolean;
+ }
+ export interface EqualityComparer {
+ (item1: TFirst, item2: TSecond): boolean;
+ }
+ export interface Comparer {
+ (item1: TFirst, item2: TSecond): number;
+ }
+
+ export interface Enumerable {
+ // base functions
+ getEnumerator(): Enumerator;
+
+ // "extension" functions
+
+ aggregate(seed: TAccumulate, func: (accumulate: TAccumulate, current: T, index: number, self: Enumerable) => TAccumulate, resultSelector: (accumulate: TAccumulate) => TResult): TResult;
+ aggregate(seed: TAccumulate, func: (accumulate: TAccumulate, current: T, index: number, self: Enumerable) => TAccumulate): TAccumulate;
+ aggregate(func: (accumulate: T, current: T, index: number, self: Enumerable) => T): T;
+
+ reduce(func: (accumulate: T, current: T, index: number, self: Enumerable) => T): T;
+ reduce(func: (accumulate: TAccumulate, current: T, index: number, self: Enumerable) => TAccumulate, seed: TAccumulate): TAccumulate;
+
+ all(predicate: EnumerablePredicate, thisArg?: any): boolean;
+ every(predicate: EnumerablePredicate, thisArg?: any): boolean; // alias
+
+ any(predicate?: EnumerablePredicate, thisArg?: any): boolean;
+ some(predicate?: EnumerablePredicate, thisArg?: any): boolean; // alias
+
+ average(selector?: EnumerableFunc): number;
+ max(selector?: EnumerableFunc): number;
+ min(selector?: EnumerableFunc): number;
+ sum(selector?: EnumerableFunc): number;
+
+ concat(...sources: Enumerable[]): Enumerable;
+
+ contains(value: TValue, comparer: EqualityComparer): boolean;
+ contains(value: T): boolean;
+
+ count(predicate?: EnumerablePredicate, thisArg?: any): number;
+
+ defaultIfEmpty(defaultValue?: T): Enumerable;
+
+ distinct(comparer?: EqualityComparer): Enumerable;
+
+ elementAt(index: number): T;
+ elementAtOrDefault(index: number): T;
+
+ except(second: Enumerable, comparer: EqualityComparer): Enumerable;
+ except(second: Enumerable): Enumerable;
+
+ first(predicate?: Predicate): T;
+ firstOrDefault(predicate?: Predicate): T;
+ last(predicate?: Predicate): T;
+ lastOrDefault(predicate?: Predicate): T;
+ single(predicate?: Predicate): T;
+ singleOrDefault(predicate?: Predicate): T;
+
+ forEach(action: EnumerableFunc, thisArg?: any): void;
+
+ groupBy(
+ keySelector: (item: T) => TKey,
+ elementSelector: (item: T) => TElement,
+ resultSelector: (key: TKey, values: Enumerable) => TResult,
+ comparer?: EqualityComparer): Enumerable;
+ groupBy(
+ keySelector: (item: T) => TKey,
+ elementSelector: (item: T) => TElement): Grouping;
+ // spec 3.5.2, waiting for restriction on generative recursion removal
+ /*groupBy(
+ keySelector: (item: T) => TKey): Grouping;*/
+
+ // if need to set comparer without resultSelector
+ groupBy(
+ keySelector: (item: T) => TKey,
+ elementSelector: (item: T) => TElement,
+ _: boolean,
+ comparer: EqualityComparer): Grouping;
+ // if need to set resultSelector without elementSelector
+ groupBy(
+ keySelector: (item: T) => TKey,
+ _: boolean,
+ resultSelector: (key: TKey, values: Enumerable) => TResult,
+ comparer?: EqualityComparer): Enumerable;
+ // if need to set comparer without elementSelector and resultSelector
+ // spec 3.5.2, waiting for restriction on generative recursion removal
+ /*groupBy(
+ keySelector: (item: T) => TKey,
+ _: boolean,
+ __: boolean,
+ comparer: EqualityComparer): Grouping;*/
+
+ groupJoin(
+ inner: Enumerable,
+ outerKeySelector: (item: T) => TOuterKey,
+ innerKeySelector: (item: TInner) => TInnerKey,
+ resultSelector: (outer: T, innerSequence: Enumerable) => TResult,
+ comparer: EqualityComparer): Enumerable;
+ groupJoin(
+ inner: Enumerable,
+ outerKeySelector: (item: T) => TKey,
+ innerKeySelector: (item: TInner) => TKey,
+ resultSelector: (outer: T, innerSequence: Enumerable) => TResult): Enumerable;
+
+ join(
+ inner: Enumerable,
+ outerKeySelector: (item: T) => TOuterKey,
+ innerKeySelector: (item: TInner) => TInnerKey,
+ resultSelector: (outer: T, inner: TInner) => TResult,
+ comparer: EqualityComparer): Enumerable;
+ join(
+ inner: Enumerable,
+ outerKeySelector: (item: T) => TKey,
+ innerKeySelector: (item: TInner) => TKey,
+ resultSelector: (outer: T, inner: TInner) => TResult): Enumerable;
+
+ intersect(second: Enumerable, comparer: EqualityComparer): Enumerable;
+ intersect(second: Enumerable): Enumerable;
+ union(second: Enumerable, comparer?: EqualityComparer): Enumerable;
+
+ orderBy(keySelector: (item: T) => TKey, comparer?: Comparer): OrderedEnumerable;
+ orderByDescending(keySelector: (item: T) => TKey, comparer?: Comparer): OrderedEnumerable;
+
+ reverse(): Enumerable;
+
+ select(selector: EnumerableFunc, thisArg?: any): Enumerable;
+ map(selector: EnumerableFunc, thisArg?: any): Enumerable;
+
+ selectMany(collectionSelector: (item: T, index: number) => Enumerable,
+ resultSelector: (outer: T, inner: TCollection) => TResult): Enumerable;
+ selectMany