From 33e507256a1f51d7a07039c7d458503c9f03cb1d Mon Sep 17 00:00:00 2001 From: Adrien Cadet Date: Sun, 16 Nov 2014 20:36:11 +0100 Subject: [PATCH] Adds SortedList ; Updates deps --- app/dependencies.ts | 2 +- app/helpers/VersionHelper.ts | 20 +- app/libs/ludivine.1.1.0.min.ts | 1 - app/libs/ludivine.1.2.0.min.ts | 1 + app/models/business/ITagBookmarkBusiness.ts | 7 +- .../business/impl/TagBookmarkBusiness.ts | 48 ++- app/presenters/MainPresenter/BookmarkList.ts | 283 +----------------- testing/buildLauncher.py | 13 +- ...{oscar.1.0.2.min.ts => oscar.1.0.4.min.ts} | 2 +- testing/src/references.ts | 2 +- 10 files changed, 55 insertions(+), 324 deletions(-) delete mode 100755 app/libs/ludivine.1.1.0.min.ts create mode 100755 app/libs/ludivine.1.2.0.min.ts mode change 100644 => 100755 testing/buildLauncher.py rename testing/src/libs/{oscar.1.0.2.min.ts => oscar.1.0.4.min.ts} (75%) diff --git a/app/dependencies.ts b/app/dependencies.ts index c732a98..1be669b 100644 --- a/app/dependencies.ts +++ b/app/dependencies.ts @@ -2,7 +2,7 @@ /// /// -/// +/// // System part diff --git a/app/helpers/VersionHelper.ts b/app/helpers/VersionHelper.ts index 71bcbf3..87e9559 100644 --- a/app/helpers/VersionHelper.ts +++ b/app/helpers/VersionHelper.ts @@ -3,24 +3,24 @@ // TODO : test class VersionHelper { //region Fields - + private static _target : string = 'http://yimello.adriencadet.com/version'; - private static _version : string = '0.3.2'; + private static _version : string = '0.3.3'; //endregion Fields - + //region Constructors - + //endregion Constructors - + //region Methods - + //region Private Methods - + //endregion Private Methods - + //region Public Methods - + static isUpToDate(callback : Action, errorHandler? : Action) : void { var get : GetRequest; @@ -47,6 +47,6 @@ class VersionHelper { } //endregion Public Methods - + //endregion Methods } diff --git a/app/libs/ludivine.1.1.0.min.ts b/app/libs/ludivine.1.1.0.min.ts deleted file mode 100755 index 5f06b55..0000000 --- a/app/libs/ludivine.1.1.0.min.ts +++ /dev/null @@ -1 +0,0 @@ -interface Action0 { () : void; } interface Action { (t : T) : void; } interface Action2 { (t : T, u : U) : void; } interface Action3 { (t : T, u : U, v : V) : void; } interface Action4 { (t : T, u : U, v : V, w : W) : void; }class Exception { private _error : any; constructor(msg : string, name : string = 'Exception') { this._error = new Error(msg); this._error.name = name; } getMessage() : string { return this._error.message; } getName() : string { return this._error.name; } getStackTrace() : string { return this._error.stack; } toString() : string { return this._error.name + ': ' + this._error.message; } }interface Func0 { () : U; } interface Func { (t: T) : U; } interface Func2 { (t : T, u : U) : V; } interface Func3 { (t : T, u : U, v : V) : W } interface Func4 { (t : T, u : U, v : V, w : W) : X }class Guid { static _randomString(length : number) : string { if (length < 1) { return null; } else { var charSet : string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; var outcome : string = ''; for (var i = 0; i < length; i++) { var index : number; index = Math.floor(Math.random() * charSet.length); outcome += charSet.charAt(index); } return outcome; } } static newGuid() : string { var outcome : StringBuffer; outcome = new StringBuffer(); outcome.append(Guid._randomString(8)); outcome.append('-'); outcome.append(Guid._randomString(4)); outcome.append('-'); outcome.append(Guid._randomString(4)); outcome.append('-'); outcome.append(Guid._randomString(4)); outcome.append('-'); outcome.append(Guid._randomString(12)); return outcome.toString(); } }class KeyValuePair { private _key : T; private _value : U; constructor(key? : T, value? : U) { this._key = key; this._value = value; } getKey() : T { return this._key; } setKey(key : T) : void { this._key = key; } getValue() : U { return this._value; } setValue(value : U) : void { this._value = value; } }enum LogLevel { Debug = 0, Test = 1, Production = 2, Opaque = 3 } class Log { private static _currentLevel : LogLevel = LogLevel.Debug; static setLevel(level : LogLevel) : void { Log._currentLevel = level; } static debug(msg : string) : void { if (this._currentLevel <= LogLevel.Debug) { console.log('DEBUG: ' + msg); } } static inform(msg : string) : void { if (this._currentLevel <= LogLevel.Test) { console.log('%cINFORM: ' + msg, 'color: DeepSkyBlue;'); } } static warn(msg : string) : void { if (this._currentLevel <= LogLevel.Production) { console.log('%cWARN: ' + msg, 'color: orange;'); } } static error(error : Exception) : void { console.error('Error: ' + error.toString()); } }class PeriodicTimer { private _timer : any; constructor(handler : Action, period : number, argument? : T) { this._timer = setInterval( () => { handler(argument); }, period ); } stop() : void { clearInterval(this._timer); } }class StringBuffer { private _content : Array; constructor(first : string = '') { this._content = new Array(); this._content.push(first); } append(s: string) : StringBuffer { this._content.push(s); return this; } toString() : string { var result : string = ''; for (var i = 0; i < this._content.length; i++) { result += this._content[i]; } return result; } }class Timer { private _timer : any; constructor(handler : Action, delay : number, argument? : T) { this._timer = setTimeout( () => { handler(argument); }, delay ); } stop() : void { clearTimeout(this._timer); } }class ArrayList implements IList { private _content : Array; constructor(source? : ICollection) { this._content = new Array(); if (source !== null && source !== undefined) { source.forEach(x => this.add(x)); } } insertAt(index : number, value : T) : void { if (index < 0) { throw new CollectionException('Unbound index'); } if (index >= this._content.length) { this.add(value); } else { var tmp : T; tmp = this._content[index]; this._content[index] = value; this.insertAt(index + 1, tmp); } } add(value : T) : void { this._content.push(value); } getAt(index : number) : T { if (index < 0 || index >= this._content.length) { throw new CollectionException('Unbound index'); } return this._content[index]; } getLength() : number { return this._content.length; } remove(value : T) : void { var a : Array; var size : number; var done : boolean; size = this.getLength(); if (size === 0) { return; } a = new Array(); done = false; for (var i = 0; i < size; i++) { var e : T; e = this._content[i]; if (e !== value) { a.push(e); } else { if (done) { a.push(e); } else { done = true; } } } this._content = a; } removeAt(index : number) : void { var size : number; var a : Array; size = this.getLength(); if (index < 0 || index >= size) { throw new CollectionException('Unbound index'); } a = new Array(); for (var i = 0; i < size; i++) { if (i !== index) { a.push(this.getAt(i)); } } this._content = a; } removeIf(func : Func) : void { var a : Array; var size : number; size = this.getLength(); if (size === 0) { return; } a = new Array(); for (var i = 0; i < size; i++) { var e : T; e = this._content[i]; if (!func(e)) { a.push(e); } } this._content = a; } orderBy(getter : Func) : ISortableCollection { var a : Array; var outcome : ArrayList; outcome = new ArrayList(); if (this.getLength() === 0) { return outcome; } a = new Array(); this.forEach(e => a.push(e)); CollectionUtils.ArrayUtils.sort(a, getter); for (var i = 0; i < a.length; i++) { outcome.add(a[i]); } return outcome; } orderByDesc(getter : Func) : ISortableCollection { var a : Array; var outcome : ArrayList; outcome = new ArrayList(); if (this.getLength() === 0) { return outcome; } a = new Array(); this.forEach(e => a.push(e)); CollectionUtils.ArrayUtils.sort(a, getter, false); for (var i = 0; i < a.length; i++) { outcome.add(a[i]); } return outcome; } reverse() : ISortableCollection { var outcome : ArrayList; outcome = new ArrayList(); for (var i = this.getLength() - 1; i >= 0; i--) { outcome.add(this.getAt(i)); } return outcome; } find(selector : Func) : T { var size : number; size = this.getLength(); for (var i = 0; i < size; i++) { var e : T; e = this.getAt(i); if (selector(e)) { return e; } } return null; } forEach(action : Action) : void { var size : number; size = this.getLength(); for (var i = 0; i < size; i++) { action(this.getAt(i)); } } map(action : Func) : ICollection { var outcome : ArrayList; outcome = new ArrayList(); this.forEach(e => outcome.add(action(e))); return outcome; } max(getter : Func) : T { var max : number; var current : T; if (this.getLength() === 0) { return null; } current = this.getAt(0); max = getter(current); this.forEach( (e) => { var value : number; value = getter(e); if (value > max) { max = value; current = e; } } ); return current; } min(getter : Func) : T { var min : number; var current : T; if (this.getLength() === 0) { return null; } current = this.getAt(0); min = getter(current); this.forEach( (e) => { var value : number; value = getter(e); if (value < min) { min = value; current = e; } } ); return current; } select(selector : Func) : ICollection { var outcome : ArrayList; outcome = new ArrayList(); this.forEach( (e) => { if (selector(e)) { outcome.add(e); } } ); return outcome; } sum(getter : Func) : number { var acc : number; acc = 0; this.forEach(e => acc += getter(e)); return acc; } toArray() : Array { var outcome : Array; outcome = new Array(); this.forEach(x => outcome.push(x)); return outcome; } toDictionary(keyGetter : Func, valueGetter : Func) : IDictionary { var outcome : IDictionary; outcome = new Dictionary(); this.forEach(x => outcome.add(keyGetter(x), valueGetter(x))); return outcome; } toList() : IList { return new ArrayList(this); } }class Dictionary implements IDictionary { private _content : Array>; constructor(source? : ICollection>) { this._content = new Array>(); if (source !== null && source !== undefined) { source.forEach(x => this.add(x.getKey(), x.getValue())); } } add(key : K, value : V) : void { if (this.hasKey(key)) { throw new CollectionException('Unable to add value: key already exists'); } else { this._content.push(new KeyValuePair(key, value)); } } get(key : K) : V { var size : number; size = this._content.length; for (var i = 0; i < size; i++) { var pair : KeyValuePair; pair = this._content[i]; if (pair.getKey() === key) { return pair.getValue(); } } throw new CollectionException('No value found for provided key'); } getSize() : number { return this._content.length; } hasKey(key : K) : boolean { var size : number; size = this._content.length; for (var i = 0; i < size; i++) { var pair : KeyValuePair; pair = this._content[i]; if (pair.getKey() === key) { return true; } } return false; } remove(key : K) : void { var size : number; var a : Array>; a = new Array>(); size = this._content.length; for (var i = 0; i < size; i++) { var pair : KeyValuePair; pair = this._content[i]; if (pair.getKey() !== key) { a.push(pair); } } if (a.length === size) { throw new CollectionException('Unable to remove pair: key does not exist'); } this._content = a; } removeIf(func : Func, boolean>) : void { var size : number; var a : Array>; a = new Array>(); size = this._content.length; for (var i = 0; i < size; i++) { var pair : KeyValuePair; pair = this._content[i]; if (!func(pair)) { a.push(pair); } } this._content = a; } find(selector : Func, boolean>) : KeyValuePair { var size : number; size = this._content.length; for (var i = 0; i < size; i++) { var pair : KeyValuePair; pair = this._content[i]; if (selector(pair)) { return pair; } } return null; } forEach(action : Action>) : void { var size : number; size = this._content.length; for (var i = 0; i < size; i++) { action(this._content[i]); } } map(action : Func, KeyValuePair>) : ICollection> { var outcome : Dictionary; outcome = new Dictionary(); this.forEach( (pair) => { var result : KeyValuePair; result = action(pair); outcome.add(result.getKey(), result.getValue()); } ); return outcome; } max(getter : Func, number>) : KeyValuePair { var max : number; var e : KeyValuePair; if (this.getSize() === 0) { return null; } e = this._content[0]; max = getter(e); this.forEach( (x) => { var value : number; value = getter(x); if (value > max) { max = value; e = x; } } ); return e; } min(getter : Func, number>) : KeyValuePair { var min : number; var e : KeyValuePair; if (this.getSize() === 0) { return null; } e = this._content[0]; min = getter(e); this.forEach( (x) => { var value : number; value = getter(x); if (value < min) { min = value; e = x; } } ); return e; } select(selector : Func, boolean>) : ICollection> { var outcome : Dictionary; outcome = new Dictionary(); this.forEach( (pair) => { if (selector(pair)) { outcome.add(pair.getKey(), pair.getValue()); } } ); return outcome; } sum(getter : Func, number>) : number { var acc : number; acc = 0; this.forEach(x => acc += getter(x)); return acc; } toArray() : Array> { var outcome : Array>; outcome = new Array>(); this.forEach(x => outcome.push(x)); return outcome; } toDictionary( keyGetter : Func, A>, valueGetter : Func, B>) : IDictionary { var outcome : IDictionary; outcome = new Dictionary(); this.forEach(x => outcome.add(keyGetter(x), valueGetter(x))); return outcome; } toList() : IList> { return new ArrayList>(this); } }module LinkedListUtils { export class LinkedListElement { private _content : T; private _next : LinkedListElement; constructor(content? : T) { this._content = content; this._next = null; } getContent() : T { return this._content; } setContent(value : T) : void { this._content = value; } getNext() : LinkedListElement { return this._next; } setNext(value : LinkedListElement) : void { this._next = value; } hasNext() : boolean { return this._next !== null && this._next !== undefined; } } } class LinkedList implements IList { private _head : LinkedListUtils.LinkedListElement; private _tail : LinkedListUtils.LinkedListElement; private _size : number; constructor(source? : ICollection) { this._size = 0; if (source !== null && source !== undefined) { source.forEach(x => this.add(x)); } } insertAt(index : number, value : T) : void { if (index < 0) { throw new CollectionException('Unbound index'); } if (index >= this.getLength()) { this.add(value); } else { var prev : LinkedListUtils.LinkedListElement, current : LinkedListUtils.LinkedListElement; var e : LinkedListUtils.LinkedListElement; e = new LinkedListUtils.LinkedListElement(value); current = this._head; for (var i = 0; i < this.getLength(); i++) { if (i === index) { if (i === 0) { e.setNext(this._head); this._head = e; } else { prev.setNext(e); e.setNext(current); } this._size++; return; } prev = current; current = current.getNext(); } } } add(value : T) : void { var e : LinkedListUtils.LinkedListElement; e = new LinkedListUtils.LinkedListElement(value); if (this.getLength() === 0) { this._head = e; this._tail = e; } else { this._tail.setNext(e); this._tail = e; } this._size++; } getAt(index : number) : T { var e : LinkedListUtils.LinkedListElement; if (index < 0 || index >= this._size) { throw new CollectionException('Unbound index'); } e = this._head; for (var i = 0; i < this.getLength(); i++) { if (i === index) { return e.getContent(); } e = e.getNext(); } } getLength() : number { return this._size; } remove(value : T) : void { var prev : LinkedListUtils.LinkedListElement, current : LinkedListUtils.LinkedListElement; current = this._head; prev = null; for (var i = 0; i < this.getLength(); i++) { if (current.getContent() === value) { if (i === 0) { this._head = current.getNext(); } else { prev.setNext(current.getNext()); } if (i === this.getLength() - 1) { this._tail = prev; } this._size--; return; } prev = current; current = current.getNext(); } } removeAt(index : number) : void { var prev : LinkedListUtils.LinkedListElement, current : LinkedListUtils.LinkedListElement; if (index < 0 || index >= this.getLength()) { throw new CollectionException('Unbound index'); } current = this._head; prev = null; for (var i = 0; i < this.getLength(); i++) { if (i === index) { if (i === 0) { this._head = current.getNext(); } else { prev.setNext(current.getNext()); } if (i === this.getLength() - 1) { this._tail = prev; } this._size--; return; } prev = current; current = current.getNext(); } } removeIf(func : Func) : void { var prev : LinkedListUtils.LinkedListElement, current : LinkedListUtils.LinkedListElement; prev = null; current = this._head; for (var i = 0; i < this.getLength(); i++) { if (func(current.getContent())) { if (prev === null || prev === undefined) { this._head = current.getNext(); } else { prev.setNext(current.getNext()); } if (i === this.getLength() - 1) { this._tail = prev; } this._size--; } else { prev = current; } current = current.getNext(); } } orderBy(getter : Func) : ISortableCollection { var a : Array; var size : number; var outcome : LinkedList; outcome = new LinkedList(); if (this.getLength() === 0) { return outcome; } a = this.toArray(); CollectionUtils.ArrayUtils.sort(a, getter); size = a.length; for (var i = 0; i < size; i++) { outcome.add(a[i]); } return outcome; } orderByDesc(getter : Func) : ISortableCollection { var a : Array; var size : number; var outcome : LinkedList; outcome = new LinkedList(); if (this.getLength() === 0) { return outcome; } a = this.toArray(); CollectionUtils.ArrayUtils.sort(a, getter, false); size = a.length; for (var i = 0; i < size; i++) { outcome.add(a[i]); } return outcome; } reverse() : ISortableCollection { var outcome : LinkedList; var a : Array; outcome = new LinkedList(); a = this.toArray(); for (var i = a.length - 1; i >= 0; i--) { outcome.add(a[i]); } return outcome; } find(selector : Func) : T { var cursor : LinkedListUtils.LinkedListElement; var e : T; if (this.getLength() === 0) { return null; } cursor = this._head; while (cursor.hasNext()) { e = cursor.getContent(); if (selector(e)) { return e; } cursor = cursor.getNext(); } e = cursor.getContent(); if (selector(e)) { return e; } else { return null; } } forEach(action : Action) : void { var cursor : LinkedListUtils.LinkedListElement; if (this.getLength() === 0) { return; } cursor = this._head; while (cursor.hasNext()) { action(cursor.getContent()); cursor = cursor.getNext(); } action(cursor.getContent()); } map(action : Func) : ICollection { var outcome : LinkedList; outcome = new LinkedList(); this.forEach(x => outcome.add(action(x))); return outcome; } max(getter : Func) : T { var max : number; var current : T; if (this.getLength() === 0) { return null; } current = this._head.getContent(); max = getter(current); this.forEach( (e) => { var value : number; value = getter(e); if (value > max) { max = value; current = e; } } ); return current; } min(getter : Func) : T { var min : number; var current : T; if (this.getLength() === 0) { return null; } current = this._head.getContent(); min = getter(current); this.forEach( (e) => { var value : number; value = getter(e); if (value < min) { min = value; current = e; } } ); return current; } select(selector : Func) : ICollection { var outcome : LinkedList; outcome = new LinkedList(); this.forEach( (e) => { if (selector(e)) { outcome.add(e); } } ); return outcome; } sum(getter : Func) : number { var acc : number; acc = 0; this.forEach(x => acc += getter(x)); return acc; } toArray() : Array { var outcome : Array; outcome = new Array(); this.forEach(x => outcome.push(x)); return outcome; } toDictionary(keyGetter : Func, valueGetter : Func) : IDictionary { var outcome : IDictionary; outcome = new Dictionary(); this.forEach(x => outcome.add(keyGetter(x), valueGetter(x))); return outcome; } toList() : IList { return new ArrayList(this); } }module QueueUtils { export class QueueElement { private _content : T; private _next : QueueElement; constructor(content? : T) { this._content = content; this._next = null; } getContent() : T { return this._content; } setContent(value : T) : void { this._content = value; } getNext() : QueueElement { return this._next; } setNext(value : QueueElement) : void { this._next = value; } hasNext() : boolean { return (this._next !== null && this._next !== undefined); } } } class Queue implements ISortableCollection { private _top : QueueUtils.QueueElement; private _bottom : QueueUtils.QueueElement; private _size : number; constructor(source? : ICollection) { this._size = 0; if (source !== null && source !== undefined) { source.forEach(x => this.push(x)); } } getSize() : number { return this._size; } top() : T { if (this._size === 0) { return null; } else { return this._top.getContent(); } } pop() : T { if (this._size === 0) { return null; } else { var outcome : T; outcome = this._top.getContent(); if (this._size === 1) { this._top = null; this._bottom = null; } else { this._top = this._top.getNext(); } this._size--; return outcome; } } push(value : T) : void { var e : QueueUtils.QueueElement; e = new QueueUtils.QueueElement(value); if (this._size === 0) { this._top = e; this._bottom = e; } else { this._bottom.setNext(e); this._bottom = e; } this._size++; } orderBy(getter : Func) : ISortableCollection { var a : Array; var outcome : Queue; outcome = new Queue(); if (this.getSize() === 0) { return outcome; } a = new Array(); this.forEach(e => a.push(e)); CollectionUtils.ArrayUtils.sort(a, getter); for (var i = 0; i < a.length; i++) { outcome.push(a[i]); } return outcome; } orderByDesc(getter : Func) : ISortableCollection { var a : Array; var outcome : Queue; outcome = new Queue(); if (this.getSize() === 0) { return outcome; } a = new Array(); this.forEach(e => a.push(e)); CollectionUtils.ArrayUtils.sort(a, getter, false); for (var i = 0; i < a.length; i++) { outcome.push(a[i]); } return outcome; } reverse() : ISortableCollection { var outcome : Queue; var a : Array; outcome = new Queue(); if (this.getSize() === 0) { return outcome; } a = new Array(); this.forEach(x => a.push(x)); for (var i = a.length - 1; i >= 0; i--) { outcome.push(a[i]); } return outcome; } find(selector : Func) : T { var cursor : QueueUtils.QueueElement; var e : T; if (this.getSize() === 0) { return null; } cursor = this._top; while (cursor.hasNext()) { e = cursor.getContent(); if (selector(e)) { return e; } cursor = cursor.getNext(); } e = cursor.getContent(); if (selector(e)) { return e; } return null; } forEach(action : Action) : void { var cursor : QueueUtils.QueueElement; if (this.getSize() === 0) { return; } cursor = this._top; while (cursor.hasNext()) { action(cursor.getContent()); cursor = cursor.getNext(); } action(cursor.getContent()); } map(action : Func) : ICollection { var outcome : Queue; outcome = new Queue(); this.forEach( (e) => { outcome.push(action(e)); } ); return outcome; } max(getter : Func) : T { var max : number; var outcome : T; if (this.getSize() === 0) { return null; } outcome = this._top.getContent(); max = getter(outcome); this.forEach( (e) => { var value : number; value = getter(e); if (value > max) { max = value; outcome = e; } } ); return outcome; } min(getter : Func) : T { var min : number; var outcome : T; if (this.getSize() === 0) { return null; } outcome = this._top.getContent(); min = getter(outcome); this.forEach( (e) => { var value : number; value = getter(e); if (value < min) { min = value; outcome = e; } } ); return outcome; } select(selector : Func) : ICollection { var outcome : Queue; outcome = new Queue(); this.forEach( (e) => { if (selector(e)) { outcome.push(e); } } ); return outcome; } sum(getter : Func) : number { var total : number; total = 0; this.forEach(e => total += getter(e)); return total; } toArray() : Array { var outcome : Array; outcome = new Array(); this.forEach(x => outcome.push(x)); return outcome; } toDictionary(keyGetter : Func, valueGetter : Func) : IDictionary { var outcome : IDictionary; outcome = new Dictionary(); this.forEach(x => outcome.add(keyGetter(x), valueGetter(x))); return outcome; } toList() : IList { return new ArrayList(this); } }module SortedListUtils { export class SortedListElement { private _content : T; private _next : SortedListElement; constructor(content? : T) { this._content = content; this._next = null; } getContent() : T { return this._content; } setContent(value : T) : void { this._content = value; } getNext() : SortedListElement { return this._next; } setNext(value : SortedListElement) : void { this._next = value; } hasNext() : boolean { return this._next !== null && this._next !== undefined; } } export class SortedListCursor { private _previous : SortedListElement; private _current : SortedListElement; constructor(previous? : SortedListElement, current? : SortedListElement) { this._previous = previous; this._current = current; } getPrevious() : SortedListElement { return this._previous; } setPrevious(value : SortedListElement) : void { this._previous = value; } hasPrevious() : boolean { return this._previous !== null && this._previous !== undefined; } getCurrent() : SortedListElement { return this._current; } setCurrent(value : SortedListElement) : void { this._current = value; } } } class SortedList implements IListableCollection { private _head : SortedListUtils.SortedListElement; private _getter : Func; private _size : number; private _asc : boolean; constructor(getter : Func, ascending? : boolean) { this._getter = getter; this._size = 0; if (ascending !== null && ascending !== undefined) { this._asc = ascending; } else { this._asc = true; } } private _forEach(func : Func, boolean>) : boolean { var prev : SortedListUtils.SortedListElement, current : SortedListUtils.SortedListElement; if (this.getLength() === 0) { return false; } current = this._head; prev = null; while (current.hasNext()) { if (func(new SortedListUtils.SortedListCursor(prev, current))) { return true; } prev = current; current = current.getNext(); } return func(new SortedListUtils.SortedListCursor(prev, current)); } add(value : A) : void { var e : SortedListUtils.SortedListElement; e = new SortedListUtils.SortedListElement(value); if (this.getLength() === 0) { this._head = e; } else { var success : boolean; var latestCursor : SortedListUtils.SortedListCursor; var comparator : Func2; if (this._asc) { comparator = (a, b) => { return a < b; }; } else { comparator = (a, b) => { return a > b; }; } success = this._forEach( (cursor) => { var current : SortedListUtils.SortedListElement; current = cursor.getCurrent(); latestCursor = cursor; if (comparator(this._getter(value), this._getter(current.getContent()))) { if (cursor.hasPrevious()) { cursor.getPrevious().setNext(e); } else { this._head = e; } e.setNext(current); return true; } else { return false; } } ); if (!success) { latestCursor.getCurrent().setNext(e); } } this._size++; } getAt(index : number) : A { var outcome : A; var i : number; if (index < 0 || index >= this.getLength()) { throw new CollectionException('Unbound index'); } i = 0; this._forEach( (cursor) => { if (i === index) { outcome = cursor.getCurrent().getContent(); return true; } else { i++; return false; } } ); return outcome; } getLength() : number { return this._size; } remove(value : A) : void { var done : boolean; done = this._forEach( (cursor) => { if (cursor.getCurrent().getContent() === value) { if (cursor.hasPrevious()) { cursor.getPrevious().setNext(cursor.getCurrent().getNext()); } else { this._head = cursor.getCurrent().getNext(); } return true; } else { return false; } } ); if (done) { this._size--; } } removeAt(index : number) : void { var i : number; if (index < 0 || index >= this.getLength()) { throw new CollectionException('Unbound index'); } i = 0; this._forEach( (cursor) => { if (i === index) { var e : SortedListUtils.SortedListElement; e = cursor.getCurrent().getNext(); if (cursor.hasPrevious()) { cursor.getPrevious().setNext(e); } else { this._head = e; } return true; } i++; } ); this._size--; } removeIf(func : Func) : void { var prev : SortedListUtils.SortedListElement, current : SortedListUtils.SortedListElement; var size : number; size = this.getLength(); prev = null; current = this._head; for (var i = 0; i < size; i++) { if (func(current.getContent())) { if (prev !== null && prev !== undefined) { prev.setNext(current.getNext()); } else { this._head = current.getNext(); } this._size--; } else { prev = current; } current = current.getNext(); } } orderBy(getter : Func) : ISortableCollection { var outcome : SortedList; outcome = new SortedList(getter); this.forEach(e => outcome.add(e)); return outcome; } orderByDesc(getter : Func) : ISortableCollection { var outcome : SortedList; outcome = new SortedList(getter, false); this.forEach(e => outcome.add(e)); return outcome; } reverse() : ISortableCollection { var outcome : SortedList; outcome = new SortedList(this._getter, !this._asc); this.forEach(e => outcome.add(e)); return outcome; } find(selector : Func) : A { var outcome : A; outcome = null; this._forEach( (cursor) => { var content : A; content = cursor.getCurrent().getContent(); if (selector(content)) { outcome = content; return true; } return false; } ); return outcome; } forEach(action : Action) : void { this._forEach( (cursor) => { action(cursor.getCurrent().getContent()); return false; } ); } map(action : Func) : ICollection { var outcome : SortedList; outcome = new SortedList(this._getter, this._asc); this.forEach( (e) => { outcome.add(action(e)); } ); return outcome; } max(getter : Func) : A { var max : number; var current : A; if (this.getLength() === 0) { return null; } current = this._head.getContent(); max = getter(current); this.forEach( (e) => { var value : number; value = getter(e); if (value > max) { max = value; current = e; } } ); return current; } min(getter : Func) : A { var min : number; var current : A; if (this.getLength() === 0) { return null; } current = this._head.getContent(); min = getter(current); this.forEach( (e) => { var value : number; value = getter(e); if (value < min) { min = value; current = e; } } ); return current; } select(selector : Func) : ICollection { var outcome : SortedList; outcome = new SortedList(this._getter, this._asc); this.forEach( (e) => { if (selector(e)) { outcome.add(e); } } ); return outcome; } sum(getter : Func) : number { var acc : number; acc = 0; this.forEach(e => acc += getter(e)); return acc; } toArray() : Array { var outcome : Array; outcome = new Array(); this.forEach(e => outcome.push(e)); return outcome; } toDictionary(keyGetter : Func, valueGetter : Func) : IDictionary { var outcome : IDictionary; outcome = new Dictionary(); this.forEach(x => outcome.add(keyGetter(x), valueGetter(x))); return outcome; } toList() : IList { return new ArrayList(this); } }module StackUtils { export class StackElement { private _prev : StackElement; private _content : T; constructor(content? : T) { this._content = content; this._prev = null; } getContent() : T { return this._content; } setContent(value : T) : void { this._content = value; } getPrev() : StackElement { return this._prev; } setPrev(value : StackElement) : void { this._prev = value; } hasPrev() : boolean { return this._prev !== null && this._prev !== undefined; } } } class Stack implements ISortableCollection { private _tail : StackUtils.StackElement; private _size : number; constructor(source? : ICollection) { this._size = 0; if (source !== null && source !== undefined) { source.forEach(x => this.push(x)); } } private _forEachInversed(action : Action) : void { var a : Array; var cursor : StackUtils.StackElement; a = new Array(); cursor = this._tail; while (cursor.hasPrev()) { a.push(cursor.getContent()); cursor = cursor.getPrev(); } a.push(cursor.getContent()); for (var i = a.length - 1; i >= 0; i--) { action(a[i]); } } getSize() : number { return this._size; } top() : T { if (this.getSize() === 0) { return null; } else { return this._tail.getContent(); } } pop() : T { if (this.getSize() === 0) { return null; } else { var e : T; e = this._tail.getContent(); this._size--; this._tail = this._tail.getPrev(); return e; } } push(value : T) : void { var e : StackUtils.StackElement; e = new StackUtils.StackElement(value); if (this.getSize() === 0) { this._tail = e; } else { e.setPrev(this._tail); this._tail = e; } this._size++; } orderBy(getter : Func) : ISortableCollection { var outcome : Stack; var a : Array; outcome = new Stack(); if (this.getSize() === 0) { return outcome; } a = new Array(); this.forEach(e => a.push(e)); CollectionUtils.ArrayUtils.sort(a, getter); for (var i = a.length - 1; i >= 0; i--) { outcome.push(a[i]); } return outcome; } orderByDesc(getter : Func) : ISortableCollection { var outcome : Stack; var a : Array; outcome = new Stack(); if (this.getSize() === 0) { return outcome; } a = new Array(); this.forEach(e => a.push(e)); CollectionUtils.ArrayUtils.sort(a, getter); for (var i = 0; i < a.length; i++) { outcome.push(a[i]); } return outcome; } reverse() : ISortableCollection { var outcome : Stack; outcome = new Stack(); this.forEach(e => outcome.push(e)); return outcome; } find(selector : Func) : T { var cursor : StackUtils.StackElement; var e : T; if (this.getSize() === 0) { return null; } cursor = this._tail; while (cursor.hasPrev()) { e = cursor.getContent(); if (selector(e)) { return e; } cursor = cursor.getPrev(); } e = cursor.getContent(); if (selector(e)) { return e; } else { return null; } } forEach(action : Action) : void { var cursor : StackUtils.StackElement; if (this.getSize() === 0) { return; } cursor = this._tail; while (cursor.hasPrev()) { action(cursor.getContent()); cursor = cursor.getPrev(); } action(cursor.getContent()); } map(action : Func) : ICollection { var outcome : Stack; outcome = new Stack(); this._forEachInversed(e => outcome.push(action(e))); return outcome; } max(getter : Func) : T { var max : number; var e : T; if (this.getSize() === 0) { return null; } e = this._tail.getContent(); max = getter(e); this.forEach( (x) => { var value : number; value = getter(x); if (value > max) { max = value; e = x; } } ); return e; } min(getter : Func) : T { var min : number; var e : T; if (this.getSize() === 0) { return null; } e = this._tail.getContent(); min = getter(e); this.forEach( (x) => { var value : number; value = getter(x); if (value < min) { min = value; e = x; } } ); return e; } select(selector : Func) : ICollection { var outcome : Stack; outcome = new Stack(); this._forEachInversed( (e) => { if (selector(e)) { outcome.push(e); } } ); return outcome; } sum(getter : Func) : number { var total : number; total = 0; this.forEach(x => total += getter(x)); return total; } toArray() : Array { var outcome : Array; outcome = new Array(); this.forEach(x => outcome.push(x)); return outcome; } toDictionary(keyGetter : Func, valueGetter : Func) : IDictionary { var outcome : IDictionary; outcome = new Dictionary(); this.forEach(x => outcome.add(keyGetter(x), valueGetter(x))); return outcome; } toList() : IList { return new ArrayList(this); } }interface ICollection { find(selector : Func) : T; forEach(action : Action) : void; map(action : Func) : ICollection; max(getter : Func) : T; min(getter : Func) : T; select(selector : Func) : ICollection; sum(getter : Func) : number; toArray() : Array; toDictionary(keyGetter : Func, valueGetter : Func) : IDictionary; toList() : IList; }interface IDictionary extends ICollection> { add(key : K, value : V) : void; get(key : K) : V; getSize() : number; hasKey(key : K) : boolean; remove(key : K) : void; removeIf(func : Func, boolean>) : void; }interface IList extends IListableCollection { insertAt(index : number, value : T) : void; }interface IListableCollection extends ISortableCollection { add(value : T) : void; getAt(index : number) : T; getLength() : number; remove(value : T) : void; removeAt(index : number) : void; removeIf(func : Func) : void; }interface ISortableCollection extends ICollection { orderBy(getter : Func) : ISortableCollection; orderByDesc(getter : Func) : ISortableCollection; reverse() : ISortableCollection; }module CollectionUtils { export class ArrayUtils { private static _swap(source : Array, i : number, j : number) : void { var tmp : T; tmp = source[i]; source[i] = source[j]; source[j] = tmp; } private static _partition( source : Array, getter : Func, comparator : Func2, first : number, last : number, pivot : number) : number { var j : number; var pivotValue : U; j = pivot; pivotValue = getter(source[pivot]); for (var i = first; i <= last; i++) { var value : U; value = getter(source[i]); if (comparator(value, pivotValue)) { if (j < i) { ArrayUtils._swap(source, j + 1, i); ArrayUtils._swap(source, j, j + 1); j++; } } else { if (i < j) { ArrayUtils._swap(source, i, j); j = i; } } } return j; } private static _sort( source : Array, getter : Func, comparator : Func2, first : number, last : number) : void { if (first < last) { var pivot : number; pivot = Math.round(Math.random() * (last - first)); pivot = ArrayUtils._partition(source, getter, comparator, first, last, pivot); ArrayUtils._sort(source, getter, comparator, first, pivot - 1); ArrayUtils._sort(source, getter, comparator, pivot + 1, last); } } static sort(source : Array, getter : Func, asc : boolean = true) : void { var comparator : Func2; if (source.length === 0) { return; } if (asc) { comparator = (a, b) => { return a <= b; }; } else { comparator = (a, b) => { return a >= b; }; } ArrayUtils._sort(source, getter, comparator, 0, source.length - 1); } } }class CollectionException extends Exception { constructor(msg : string) { super(msg, 'CollectionException'); } } \ No newline at end of file diff --git a/app/libs/ludivine.1.2.0.min.ts b/app/libs/ludivine.1.2.0.min.ts new file mode 100755 index 0000000..97a0055 --- /dev/null +++ b/app/libs/ludivine.1.2.0.min.ts @@ -0,0 +1 @@ +interface Action0 { () : void; } interface Action { (t : T) : void; } interface Action2 { (t : T, u : U) : void; } interface Action3 { (t : T, u : U, v : V) : void; } interface Action4 { (t : T, u : U, v : V, w : W) : void; }class Exception { private _error : any; constructor(msg : string, name : string = 'Exception') { this._error = new Error(msg); this._error.name = name; } getMessage() : string { return this._error.message; } getName() : string { return this._error.name; } getStackTrace() : string { return this._error.stack; } toString() : string { return this._error.name + ': ' + this._error.message; } }interface Func0 { () : U; } interface Func { (t: T) : U; } interface Func2 { (t : T, u : U) : V; } interface Func3 { (t : T, u : U, v : V) : W } interface Func4 { (t : T, u : U, v : V, w : W) : X }class Guid { static _randomString(length : number) : string { if (length < 1) { return null; } else { var charSet : string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; var outcome : string = ''; for (var i = 0; i < length; i++) { var index : number; index = Math.floor(Math.random() * charSet.length); outcome += charSet.charAt(index); } return outcome; } } static newGuid() : string { var outcome : StringBuffer; outcome = new StringBuffer(); outcome.append(Guid._randomString(8)); outcome.append('-'); outcome.append(Guid._randomString(4)); outcome.append('-'); outcome.append(Guid._randomString(4)); outcome.append('-'); outcome.append(Guid._randomString(4)); outcome.append('-'); outcome.append(Guid._randomString(12)); return outcome.toString(); } }class KeyValuePair { private _key : T; private _value : U; constructor(key? : T, value? : U) { this._key = key; this._value = value; } getKey() : T { return this._key; } setKey(key : T) : void { this._key = key; } getValue() : U { return this._value; } setValue(value : U) : void { this._value = value; } }enum LogLevel { Debug = 0, Test = 1, Production = 2, Opaque = 3 } class Log { private static _currentLevel : LogLevel = LogLevel.Debug; static setLevel(level : LogLevel) : void { Log._currentLevel = level; } static debug(msg : string) : void { if (this._currentLevel <= LogLevel.Debug) { console.log('DEBUG: ' + msg); } } static inform(msg : string) : void { if (this._currentLevel <= LogLevel.Test) { console.log('%cINFORM: ' + msg, 'color: DeepSkyBlue;'); } } static warn(msg : string) : void { if (this._currentLevel <= LogLevel.Production) { console.log('%cWARN: ' + msg, 'color: orange;'); } } static error(error : Exception) : void { console.error('Error: ' + error.toString()); } }class PeriodicTimer { private _timer : any; constructor(handler : Action, period : number, argument? : T) { this._timer = setInterval( () => { handler(argument); }, period ); } stop() : void { clearInterval(this._timer); } }class StringBuffer { private _content : Array; constructor(first : string = '') { this._content = new Array(); this._content.push(first); } append(s: string) : StringBuffer { this._content.push(s); return this; } toString() : string { var result : string = ''; for (var i = 0; i < this._content.length; i++) { result += this._content[i]; } return result; } }class Timer { private _timer : any; constructor(handler : Action, delay : number, argument? : T) { this._timer = setTimeout( () => { handler(argument); }, delay ); } stop() : void { clearTimeout(this._timer); } }class ArrayList implements IList { private _content : Array; constructor(source? : ICollection) { this._content = new Array(); if (source !== null && source !== undefined) { source.forEach(x => this.add(x)); } } insertAt(index : number, value : T) : void { if (index < 0) { throw new CollectionException('Unbound index'); } if (index >= this._content.length) { this.add(value); } else { var tmp : T; tmp = this._content[index]; this._content[index] = value; this.insertAt(index + 1, tmp); } } add(value : T) : void { this._content.push(value); } getAt(index : number) : T { if (index < 0 || index >= this._content.length) { throw new CollectionException('Unbound index'); } return this._content[index]; } getLength() : number { return this._content.length; } remove(value : T) : void { var a : Array; var size : number; var done : boolean; size = this.getLength(); if (size === 0) { return; } a = new Array(); done = false; for (var i = 0; i < size; i++) { var e : T; e = this._content[i]; if (e !== value) { a.push(e); } else { if (done) { a.push(e); } else { done = true; } } } this._content = a; } removeAt(index : number) : void { var size : number; var a : Array; size = this.getLength(); if (index < 0 || index >= size) { throw new CollectionException('Unbound index'); } a = new Array(); for (var i = 0; i < size; i++) { if (i !== index) { a.push(this.getAt(i)); } } this._content = a; } removeIf(func : Func) : void { var a : Array; var size : number; size = this.getLength(); if (size === 0) { return; } a = new Array(); for (var i = 0; i < size; i++) { var e : T; e = this._content[i]; if (!func(e)) { a.push(e); } } this._content = a; } orderBy(getter : Func) : ISortableCollection { var a : Array; var outcome : ArrayList; outcome = new ArrayList(); if (this.getLength() === 0) { return outcome; } a = new Array(); this.forEach(e => a.push(e)); CollectionUtils.ArrayUtils.sort(a, getter); for (var i = 0; i < a.length; i++) { outcome.add(a[i]); } return outcome; } orderByDesc(getter : Func) : ISortableCollection { var a : Array; var outcome : ArrayList; outcome = new ArrayList(); if (this.getLength() === 0) { return outcome; } a = new Array(); this.forEach(e => a.push(e)); CollectionUtils.ArrayUtils.sort(a, getter, false); for (var i = 0; i < a.length; i++) { outcome.add(a[i]); } return outcome; } reverse() : ISortableCollection { var outcome : ArrayList; outcome = new ArrayList(); for (var i = this.getLength() - 1; i >= 0; i--) { outcome.add(this.getAt(i)); } return outcome; } average(getter : Func) : number { return CollectionUtils.CollectionHelper.average(this, getter); } exists(selector : Func) : boolean { return this.find(selector) !== null; } find(selector : Func) : T { var size : number; size = this.getLength(); for (var i = 0; i < size; i++) { var e : T; e = this.getAt(i); if (selector(e)) { return e; } } return null; } forEach(action : Action) : void { var size : number; size = this.getLength(); for (var i = 0; i < size; i++) { action(this.getAt(i)); } } intersect(collection : ICollection) : ICollection { var outcome : ArrayList; outcome = new ArrayList(); this.forEach( (x) => { if (collection.exists(e => e === x)) { outcome.add(x); } } ); return outcome; } map(action : Func) : ICollection { var outcome : ArrayList; outcome = new ArrayList(); this.forEach(e => outcome.add(action(e))); return outcome; } max(getter : Func) : T { return CollectionUtils.CollectionHelper.max(this, getter); } min(getter : Func) : T { return CollectionUtils.CollectionHelper.min(this, getter); } select(selector : Func) : ICollection { var outcome : ArrayList; outcome = new ArrayList(); this.forEach( (e) => { if (selector(e)) { outcome.add(e); } } ); return outcome; } sum(getter : Func) : number { return CollectionUtils.CollectionHelper.sum(this, getter); } toArray() : Array { return CollectionUtils.CollectionHelper.toArray(this); } toDictionary(keyGetter : Func, valueGetter : Func) : IDictionary { return CollectionUtils.CollectionHelper.toDictionary(this, keyGetter, valueGetter); } toList() : IList { return CollectionUtils.CollectionHelper.toList(this); } union(collection : ICollection) : ICollection { var outcome : ArrayList; outcome = new ArrayList(this); collection.forEach( (x) => { if (!this.exists(e => e === x)) { outcome.add(x); } } ); return outcome; } uniq() : ICollection { var outcome : ArrayList; outcome = new ArrayList(); this.forEach( (x) => { if (!outcome.exists(e => e === x)) { outcome.add(x); } } ); return outcome; } }class Dictionary implements IDictionary { private _content : Array>; constructor(source? : ICollection>) { this._content = new Array>(); if (source !== null && source !== undefined) { source.forEach(x => this.add(x.getKey(), x.getValue())); } } add(key : K, value : V) : void { if (this.hasKey(key)) { throw new CollectionException('Unable to add value: key already exists'); } else { this._content.push(new KeyValuePair(key, value)); } } get(key : K) : V { var size : number; size = this._content.length; for (var i = 0; i < size; i++) { var pair : KeyValuePair; pair = this._content[i]; if (pair.getKey() === key) { return pair.getValue(); } } throw new CollectionException('No value found for provided key'); } getSize() : number { return this._content.length; } hasKey(key : K) : boolean { var size : number; size = this._content.length; for (var i = 0; i < size; i++) { var pair : KeyValuePair; pair = this._content[i]; if (pair.getKey() === key) { return true; } } return false; } remove(key : K) : void { var size : number; var a : Array>; a = new Array>(); size = this._content.length; for (var i = 0; i < size; i++) { var pair : KeyValuePair; pair = this._content[i]; if (pair.getKey() !== key) { a.push(pair); } } if (a.length === size) { throw new CollectionException('Unable to remove pair: key does not exist'); } this._content = a; } removeIf(func : Func, boolean>) : void { var size : number; var a : Array>; a = new Array>(); size = this._content.length; for (var i = 0; i < size; i++) { var pair : KeyValuePair; pair = this._content[i]; if (!func(pair)) { a.push(pair); } } this._content = a; } average(getter : Func, number>) : number { return CollectionUtils.CollectionHelper.average(this, getter); } exists(selector : Func, boolean>) : boolean { return this.find(selector) !== null; } find(selector : Func, boolean>) : KeyValuePair { var size : number; size = this._content.length; for (var i = 0; i < size; i++) { var pair : KeyValuePair; pair = this._content[i]; if (selector(pair)) { return pair; } } return null; } forEach(action : Action>) : void { var size : number; size = this._content.length; for (var i = 0; i < size; i++) { action(this._content[i]); } } intersect(collection : ICollection>) : ICollection> { var outcome : Dictionary; outcome = new Dictionary(); this.forEach( (x) => { if (collection.exists(e => (e.getKey() === x.getKey()) && (e.getValue() === x.getValue()))) { outcome.add(x.getKey(), x.getValue()); } } ); return outcome; } map(action : Func, KeyValuePair>) : ICollection> { var outcome : Dictionary; outcome = new Dictionary(); this.forEach( (pair) => { var result : KeyValuePair; result = action(pair); outcome.add(result.getKey(), result.getValue()); } ); return outcome; } max(getter : Func, number>) : KeyValuePair { return CollectionUtils.CollectionHelper.max(this, getter); } min(getter : Func, number>) : KeyValuePair { return CollectionUtils.CollectionHelper.min(this, getter); } select(selector : Func, boolean>) : ICollection> { var outcome : Dictionary; outcome = new Dictionary(); this.forEach( (pair) => { if (selector(pair)) { outcome.add(pair.getKey(), pair.getValue()); } } ); return outcome; } sum(getter : Func, number>) : number { return CollectionUtils.CollectionHelper.sum(this, getter); } toArray() : Array> { return CollectionUtils.CollectionHelper.toArray(this); } toDictionary( keyGetter : Func, A>, valueGetter : Func, B>) : IDictionary { return CollectionUtils.CollectionHelper.toDictionary(this, keyGetter, valueGetter); } toList() : IList> { return CollectionUtils.CollectionHelper.toList(this); } union(collection : ICollection>) : ICollection> { var outcome : Dictionary; outcome = new Dictionary(this); collection.forEach( (x) => { if (!this.exists(e => (e.getKey() === x.getKey()) && (e.getValue() === x.getValue()))) { outcome.add(x.getKey(), x.getValue()); } } ); return outcome; } uniq() : ICollection> { return new Dictionary(this); } }module LinkedListUtils { export class LinkedListElement { private _content : T; private _next : LinkedListElement; constructor(content? : T) { this._content = content; this._next = null; } getContent() : T { return this._content; } setContent(value : T) : void { this._content = value; } getNext() : LinkedListElement { return this._next; } setNext(value : LinkedListElement) : void { this._next = value; } hasNext() : boolean { return this._next !== null && this._next !== undefined; } } } class LinkedList implements IList { private _head : LinkedListUtils.LinkedListElement; private _tail : LinkedListUtils.LinkedListElement; private _size : number; constructor(source? : ICollection) { this._size = 0; if (source !== null && source !== undefined) { source.forEach(x => this.add(x)); } } insertAt(index : number, value : T) : void { if (index < 0) { throw new CollectionException('Unbound index'); } if (index >= this.getLength()) { this.add(value); } else { var prev : LinkedListUtils.LinkedListElement, current : LinkedListUtils.LinkedListElement; var e : LinkedListUtils.LinkedListElement; e = new LinkedListUtils.LinkedListElement(value); current = this._head; for (var i = 0; i < this.getLength(); i++) { if (i === index) { if (i === 0) { e.setNext(this._head); this._head = e; } else { prev.setNext(e); e.setNext(current); } this._size++; return; } prev = current; current = current.getNext(); } } } add(value : T) : void { var e : LinkedListUtils.LinkedListElement; e = new LinkedListUtils.LinkedListElement(value); if (this.getLength() === 0) { this._head = e; this._tail = e; } else { this._tail.setNext(e); this._tail = e; } this._size++; } getAt(index : number) : T { var e : LinkedListUtils.LinkedListElement; if (index < 0 || index >= this._size) { throw new CollectionException('Unbound index'); } e = this._head; for (var i = 0; i < this.getLength(); i++) { if (i === index) { return e.getContent(); } e = e.getNext(); } } getLength() : number { return this._size; } remove(value : T) : void { var prev : LinkedListUtils.LinkedListElement, current : LinkedListUtils.LinkedListElement; current = this._head; prev = null; for (var i = 0; i < this.getLength(); i++) { if (current.getContent() === value) { if (i === 0) { this._head = current.getNext(); } else { prev.setNext(current.getNext()); } if (i === this.getLength() - 1) { this._tail = prev; } this._size--; return; } prev = current; current = current.getNext(); } } removeAt(index : number) : void { var prev : LinkedListUtils.LinkedListElement, current : LinkedListUtils.LinkedListElement; if (index < 0 || index >= this.getLength()) { throw new CollectionException('Unbound index'); } current = this._head; prev = null; for (var i = 0; i < this.getLength(); i++) { if (i === index) { if (i === 0) { this._head = current.getNext(); } else { prev.setNext(current.getNext()); } if (i === this.getLength() - 1) { this._tail = prev; } this._size--; return; } prev = current; current = current.getNext(); } } removeIf(func : Func) : void { var prev : LinkedListUtils.LinkedListElement, current : LinkedListUtils.LinkedListElement; prev = null; current = this._head; for (var i = 0; i < this.getLength(); i++) { if (func(current.getContent())) { if (prev === null || prev === undefined) { this._head = current.getNext(); } else { prev.setNext(current.getNext()); } if (i === this.getLength() - 1) { this._tail = prev; } this._size--; } else { prev = current; } current = current.getNext(); } } orderBy(getter : Func) : ISortableCollection { var a : Array; var size : number; var outcome : LinkedList; outcome = new LinkedList(); if (this.getLength() === 0) { return outcome; } a = this.toArray(); CollectionUtils.ArrayUtils.sort(a, getter); size = a.length; for (var i = 0; i < size; i++) { outcome.add(a[i]); } return outcome; } orderByDesc(getter : Func) : ISortableCollection { var a : Array; var size : number; var outcome : LinkedList; outcome = new LinkedList(); if (this.getLength() === 0) { return outcome; } a = this.toArray(); CollectionUtils.ArrayUtils.sort(a, getter, false); size = a.length; for (var i = 0; i < size; i++) { outcome.add(a[i]); } return outcome; } reverse() : ISortableCollection { var outcome : LinkedList; var a : Array; outcome = new LinkedList(); a = this.toArray(); for (var i = a.length - 1; i >= 0; i--) { outcome.add(a[i]); } return outcome; } average(getter : Func) : number { return CollectionUtils.CollectionHelper.average(this, getter); } exists(selector : Func) : boolean { return this.find(selector) !== null; } find(selector : Func) : T { var cursor : LinkedListUtils.LinkedListElement; var e : T; if (this.getLength() === 0) { return null; } cursor = this._head; while (cursor.hasNext()) { e = cursor.getContent(); if (selector(e)) { return e; } cursor = cursor.getNext(); } e = cursor.getContent(); if (selector(e)) { return e; } else { return null; } } forEach(action : Action) : void { var cursor : LinkedListUtils.LinkedListElement; if (this.getLength() === 0) { return; } cursor = this._head; while (cursor.hasNext()) { action(cursor.getContent()); cursor = cursor.getNext(); } action(cursor.getContent()); } intersect(collection : ICollection) : ICollection { var outcome : LinkedList; outcome = new LinkedList(); this.forEach( (x) => { if (collection.exists(e => e === x)) { outcome.add(x); } } ); return outcome; } map(action : Func) : ICollection { var outcome : LinkedList; outcome = new LinkedList(); this.forEach(x => outcome.add(action(x))); return outcome; } max(getter : Func) : T { return CollectionUtils.CollectionHelper.max(this, getter); } min(getter : Func) : T { return CollectionUtils.CollectionHelper.min(this, getter); } select(selector : Func) : ICollection { var outcome : LinkedList; outcome = new LinkedList(); this.forEach( (e) => { if (selector(e)) { outcome.add(e); } } ); return outcome; } sum(getter : Func) : number { return CollectionUtils.CollectionHelper.sum(this, getter); } toArray() : Array { return CollectionUtils.CollectionHelper.toArray(this); } toDictionary(keyGetter : Func, valueGetter : Func) : IDictionary { return CollectionUtils.CollectionHelper.toDictionary(this, keyGetter, valueGetter); } toList() : IList { return CollectionUtils.CollectionHelper.toList(this); } union(collection : ICollection) : ICollection { var outcome : LinkedList; outcome = new LinkedList(this); collection.forEach( (x) => { if (!this.exists(e => e === x)) { outcome.add(x); } } ); return outcome; } uniq() : ICollection { var outcome : LinkedList; outcome = new LinkedList(); this.forEach( (x) => { if (!outcome.exists(e => e === x)) { outcome.add(x); } } ); return outcome; } }module QueueUtils { export class QueueElement { private _content : T; private _next : QueueElement; constructor(content? : T) { this._content = content; this._next = null; } getContent() : T { return this._content; } setContent(value : T) : void { this._content = value; } getNext() : QueueElement { return this._next; } setNext(value : QueueElement) : void { this._next = value; } hasNext() : boolean { return (this._next !== null && this._next !== undefined); } } } class Queue implements ISortableCollection { private _top : QueueUtils.QueueElement; private _bottom : QueueUtils.QueueElement; private _size : number; constructor(source? : ICollection) { this._size = 0; if (source !== null && source !== undefined) { source.forEach(x => this.push(x)); } } getSize() : number { return this._size; } top() : T { if (this._size === 0) { return null; } else { return this._top.getContent(); } } pop() : T { if (this._size === 0) { return null; } else { var outcome : T; outcome = this._top.getContent(); if (this._size === 1) { this._top = null; this._bottom = null; } else { this._top = this._top.getNext(); } this._size--; return outcome; } } push(value : T) : void { var e : QueueUtils.QueueElement; e = new QueueUtils.QueueElement(value); if (this._size === 0) { this._top = e; this._bottom = e; } else { this._bottom.setNext(e); this._bottom = e; } this._size++; } orderBy(getter : Func) : ISortableCollection { var a : Array; var outcome : Queue; outcome = new Queue(); if (this.getSize() === 0) { return outcome; } a = new Array(); this.forEach(e => a.push(e)); CollectionUtils.ArrayUtils.sort(a, getter); for (var i = 0; i < a.length; i++) { outcome.push(a[i]); } return outcome; } orderByDesc(getter : Func) : ISortableCollection { var a : Array; var outcome : Queue; outcome = new Queue(); if (this.getSize() === 0) { return outcome; } a = new Array(); this.forEach(e => a.push(e)); CollectionUtils.ArrayUtils.sort(a, getter, false); for (var i = 0; i < a.length; i++) { outcome.push(a[i]); } return outcome; } reverse() : ISortableCollection { var outcome : Queue; var a : Array; outcome = new Queue(); if (this.getSize() === 0) { return outcome; } a = new Array(); this.forEach(x => a.push(x)); for (var i = a.length - 1; i >= 0; i--) { outcome.push(a[i]); } return outcome; } average(getter : Func) : number { return CollectionUtils.CollectionHelper.average(this, getter); } exists(selector : Func) : boolean { return this.find(selector) !== null; } find(selector : Func) : T { var cursor : QueueUtils.QueueElement; var e : T; if (this.getSize() === 0) { return null; } cursor = this._top; while (cursor.hasNext()) { e = cursor.getContent(); if (selector(e)) { return e; } cursor = cursor.getNext(); } e = cursor.getContent(); if (selector(e)) { return e; } return null; } forEach(action : Action) : void { var cursor : QueueUtils.QueueElement; if (this.getSize() === 0) { return; } cursor = this._top; while (cursor.hasNext()) { action(cursor.getContent()); cursor = cursor.getNext(); } action(cursor.getContent()); } intersect(collection : ICollection) : ICollection { var outcome : Queue; outcome = new Queue(); this.forEach( (x) => { if (collection.exists(e => e === x)) { outcome.push(x); } } ); return outcome; } map(action : Func) : ICollection { var outcome : Queue; outcome = new Queue(); this.forEach( (e) => { outcome.push(action(e)); } ); return outcome; } max(getter : Func) : T { return CollectionUtils.CollectionHelper.max(this, getter); } min(getter : Func) : T { return CollectionUtils.CollectionHelper.min(this, getter); } select(selector : Func) : ICollection { var outcome : Queue; outcome = new Queue(); this.forEach( (e) => { if (selector(e)) { outcome.push(e); } } ); return outcome; } sum(getter : Func) : number { return CollectionUtils.CollectionHelper.sum(this, getter); } toArray() : Array { return CollectionUtils.CollectionHelper.toArray(this); } toDictionary(keyGetter : Func, valueGetter : Func) : IDictionary { return CollectionUtils.CollectionHelper.toDictionary(this, keyGetter, valueGetter); } toList() : IList { return CollectionUtils.CollectionHelper.toList(this); } union(collection : ICollection) : ICollection { var outcome : Queue; outcome = new Queue(this); collection.forEach( (x) => { if (!this.exists(e => e === x)) { outcome.push(x); } } ); return outcome; } uniq() : ICollection { var outcome : Queue; outcome = new Queue(); this.forEach( (x) => { if (!outcome.exists(e => e === x)) { outcome.push(x); } } ); return outcome; } }module SortedListUtils { export class SortedListElement { private _content : T; private _next : SortedListElement; constructor(content? : T) { this._content = content; this._next = null; } getContent() : T { return this._content; } setContent(value : T) : void { this._content = value; } getNext() : SortedListElement { return this._next; } setNext(value : SortedListElement) : void { this._next = value; } hasNext() : boolean { return this._next !== null && this._next !== undefined; } } export class SortedListCursor { private _previous : SortedListElement; private _current : SortedListElement; constructor(previous? : SortedListElement, current? : SortedListElement) { this._previous = previous; this._current = current; } getPrevious() : SortedListElement { return this._previous; } setPrevious(value : SortedListElement) : void { this._previous = value; } hasPrevious() : boolean { return this._previous !== null && this._previous !== undefined; } getCurrent() : SortedListElement { return this._current; } setCurrent(value : SortedListElement) : void { this._current = value; } } } class SortedList implements IListableCollection { private _head : SortedListUtils.SortedListElement; private _getter : Func; private _size : number; private _asc : boolean; constructor(getter : Func, ascending? : boolean) { this._getter = getter; this._size = 0; if (ascending !== null && ascending !== undefined) { this._asc = ascending; } else { this._asc = true; } } private _forEach(func : Func, boolean>) : boolean { var prev : SortedListUtils.SortedListElement, current : SortedListUtils.SortedListElement; if (this.getLength() === 0) { return false; } current = this._head; prev = null; while (current.hasNext()) { if (func(new SortedListUtils.SortedListCursor(prev, current))) { return true; } prev = current; current = current.getNext(); } return func(new SortedListUtils.SortedListCursor(prev, current)); } add(value : A) : void { var e : SortedListUtils.SortedListElement; e = new SortedListUtils.SortedListElement(value); if (this.getLength() === 0) { this._head = e; } else { var success : boolean; var latestCursor : SortedListUtils.SortedListCursor; var comparator : Func2; if (this._asc) { comparator = (a, b) => { return a < b; }; } else { comparator = (a, b) => { return a > b; }; } success = this._forEach( (cursor) => { var current : SortedListUtils.SortedListElement; current = cursor.getCurrent(); latestCursor = cursor; if (comparator(this._getter(value), this._getter(current.getContent()))) { if (cursor.hasPrevious()) { cursor.getPrevious().setNext(e); } else { this._head = e; } e.setNext(current); return true; } else { return false; } } ); if (!success) { latestCursor.getCurrent().setNext(e); } } this._size++; } getAt(index : number) : A { var outcome : A; var i : number; if (index < 0 || index >= this.getLength()) { throw new CollectionException('Unbound index'); } i = 0; this._forEach( (cursor) => { if (i === index) { outcome = cursor.getCurrent().getContent(); return true; } else { i++; return false; } } ); return outcome; } getLength() : number { return this._size; } remove(value : A) : void { var done : boolean; done = this._forEach( (cursor) => { if (cursor.getCurrent().getContent() === value) { if (cursor.hasPrevious()) { cursor.getPrevious().setNext(cursor.getCurrent().getNext()); } else { this._head = cursor.getCurrent().getNext(); } return true; } else { return false; } } ); if (done) { this._size--; } } removeAt(index : number) : void { var i : number; if (index < 0 || index >= this.getLength()) { throw new CollectionException('Unbound index'); } i = 0; this._forEach( (cursor) => { if (i === index) { var e : SortedListUtils.SortedListElement; e = cursor.getCurrent().getNext(); if (cursor.hasPrevious()) { cursor.getPrevious().setNext(e); } else { this._head = e; } return true; } i++; } ); this._size--; } removeIf(func : Func) : void { var prev : SortedListUtils.SortedListElement, current : SortedListUtils.SortedListElement; var size : number; size = this.getLength(); prev = null; current = this._head; for (var i = 0; i < size; i++) { if (func(current.getContent())) { if (prev !== null && prev !== undefined) { prev.setNext(current.getNext()); } else { this._head = current.getNext(); } this._size--; } else { prev = current; } current = current.getNext(); } } orderBy(getter : Func) : ISortableCollection { var outcome : SortedList; outcome = new SortedList(getter); this.forEach(e => outcome.add(e)); return outcome; } orderByDesc(getter : Func) : ISortableCollection { var outcome : SortedList; outcome = new SortedList(getter, false); this.forEach(e => outcome.add(e)); return outcome; } reverse() : ISortableCollection { var outcome : SortedList; outcome = new SortedList(this._getter, !this._asc); this.forEach(e => outcome.add(e)); return outcome; } average(getter : Func) : number { return CollectionUtils.CollectionHelper.average(this, getter); } exists(selector : Func) : boolean { return this.find(selector) !== null; } find(selector : Func) : A { var outcome : A; outcome = null; this._forEach( (cursor) => { var content : A; content = cursor.getCurrent().getContent(); if (selector(content)) { outcome = content; return true; } return false; } ); return outcome; } forEach(action : Action) : void { this._forEach( (cursor) => { action(cursor.getCurrent().getContent()); return false; } ); } intersect(collection : ICollection) : ICollection { var outcome : SortedList; outcome = new SortedList(this._getter, this._asc); this.forEach( (x) => { if (collection.exists(e => e === x)) { outcome.add(x); } } ); return outcome; } map(action : Func) : ICollection { var outcome : SortedList; outcome = new SortedList(this._getter, this._asc); this.forEach( (e) => { outcome.add(action(e)); } ); return outcome; } max(getter : Func) : A { return CollectionUtils.CollectionHelper.max(this, getter); } min(getter : Func) : A { return CollectionUtils.CollectionHelper.min(this, getter); } select(selector : Func) : ICollection { var outcome : SortedList; outcome = new SortedList(this._getter, this._asc); this.forEach( (e) => { if (selector(e)) { outcome.add(e); } } ); return outcome; } sum(getter : Func) : number { return CollectionUtils.CollectionHelper.sum(this, getter); } toArray() : Array { return CollectionUtils.CollectionHelper.toArray(this); } toDictionary(keyGetter : Func, valueGetter : Func) : IDictionary { return CollectionUtils.CollectionHelper.toDictionary(this, keyGetter, valueGetter); } toList() : IList { return CollectionUtils.CollectionHelper.toList(this); } union(collection : ICollection) : ICollection { var outcome : SortedList; outcome = new SortedList(this._getter, this._asc); this.forEach(x => outcome.add(x)); collection.forEach( (x) => { if (!this.exists(e => e === x)) { outcome.add(x); } } ); return outcome; } uniq() : ICollection { var outcome : SortedList; outcome = new SortedList(this._getter, this._asc); this.forEach( (x) => { if (!outcome.exists(e => e === x)) { outcome.add(x); } } ); return outcome; } }module StackUtils { export class StackElement { private _prev : StackElement; private _content : T; constructor(content? : T) { this._content = content; this._prev = null; } getContent() : T { return this._content; } setContent(value : T) : void { this._content = value; } getPrev() : StackElement { return this._prev; } setPrev(value : StackElement) : void { this._prev = value; } hasPrev() : boolean { return this._prev !== null && this._prev !== undefined; } } } class Stack implements ISortableCollection { private _tail : StackUtils.StackElement; private _size : number; constructor(source? : ICollection) { this._size = 0; if (source !== null && source !== undefined) { source.forEach(x => this.push(x)); } } private _forEachInversed(action : Action) : void { var a : Array; var cursor : StackUtils.StackElement; if (this.getSize() === 0) { return; } a = new Array(); cursor = this._tail; while (cursor.hasPrev()) { a.push(cursor.getContent()); cursor = cursor.getPrev(); } a.push(cursor.getContent()); for (var i = a.length - 1; i >= 0; i--) { action(a[i]); } } getSize() : number { return this._size; } top() : T { if (this.getSize() === 0) { return null; } else { return this._tail.getContent(); } } pop() : T { if (this.getSize() === 0) { return null; } else { var e : T; e = this._tail.getContent(); this._size--; this._tail = this._tail.getPrev(); return e; } } push(value : T) : void { var e : StackUtils.StackElement; e = new StackUtils.StackElement(value); if (this.getSize() === 0) { this._tail = e; } else { e.setPrev(this._tail); this._tail = e; } this._size++; } orderBy(getter : Func) : ISortableCollection { var outcome : Stack; var a : Array; outcome = new Stack(); if (this.getSize() === 0) { return outcome; } a = new Array(); this.forEach(e => a.push(e)); CollectionUtils.ArrayUtils.sort(a, getter); for (var i = a.length - 1; i >= 0; i--) { outcome.push(a[i]); } return outcome; } orderByDesc(getter : Func) : ISortableCollection { var outcome : Stack; var a : Array; outcome = new Stack(); if (this.getSize() === 0) { return outcome; } a = new Array(); this.forEach(e => a.push(e)); CollectionUtils.ArrayUtils.sort(a, getter); for (var i = 0; i < a.length; i++) { outcome.push(a[i]); } return outcome; } reverse() : ISortableCollection { var outcome : Stack; outcome = new Stack(); this.forEach(e => outcome.push(e)); return outcome; } average(getter : Func) : number { return CollectionUtils.CollectionHelper.average(this, getter); } exists(selector : Func) : boolean { return this.find(selector) !== null; } find(selector : Func) : T { var cursor : StackUtils.StackElement; var e : T; if (this.getSize() === 0) { return null; } cursor = this._tail; while (cursor.hasPrev()) { e = cursor.getContent(); if (selector(e)) { return e; } cursor = cursor.getPrev(); } e = cursor.getContent(); if (selector(e)) { return e; } else { return null; } } forEach(action : Action) : void { var cursor : StackUtils.StackElement; if (this.getSize() === 0) { return; } cursor = this._tail; while (cursor.hasPrev()) { action(cursor.getContent()); cursor = cursor.getPrev(); } action(cursor.getContent()); } intersect(collection : ICollection) : ICollection { var outcome : Stack; outcome = new Stack(); this._forEachInversed( (x) => { if (collection.exists(e => e === x)) { outcome.push(x); } } ); return outcome; } map(action : Func) : ICollection { var outcome : Stack; outcome = new Stack(); this._forEachInversed(e => outcome.push(action(e))); return outcome; } max(getter : Func) : T { return CollectionUtils.CollectionHelper.max(this, getter); } min(getter : Func) : T { return CollectionUtils.CollectionHelper.min(this, getter); } select(selector : Func) : ICollection { var outcome : Stack; outcome = new Stack(); this._forEachInversed( (e) => { if (selector(e)) { outcome.push(e); } } ); return outcome; } sum(getter : Func) : number { return CollectionUtils.CollectionHelper.sum(this, getter); } toArray() : Array { return CollectionUtils.CollectionHelper.toArray(this); } toDictionary(keyGetter : Func, valueGetter : Func) : IDictionary { return CollectionUtils.CollectionHelper.toDictionary(this, keyGetter, valueGetter); } toList() : IList { return CollectionUtils.CollectionHelper.toList(this); } union(collection : ICollection) : ICollection { var outcome : Stack; outcome = new Stack(); this._forEachInversed(x => outcome.push(x)); collection.forEach( (x) => { if (!this.exists(e => e === x)) { outcome.push(x); } } ); return outcome; } uniq() : ICollection { var outcome : Stack; outcome = new Stack(); this._forEachInversed( (x) => { if (!outcome.exists(e => e === x)) { outcome.push(x); } } ); return outcome; } }interface ICollection { average(getter : Func) : number; exists(selector : Func) : boolean; find(selector : Func) : T; forEach(action : Action) : void; intersect(collection : ICollection) : ICollection; map(action : Func) : ICollection; max(getter : Func) : T; min(getter : Func) : T; select(selector : Func) : ICollection; sum(getter : Func) : number; toArray() : Array; toDictionary(keyGetter : Func, valueGetter : Func) : IDictionary; toList() : IList; union(collection : ICollection) : ICollection; uniq() : ICollection; }interface IDictionary extends ICollection> { add(key : K, value : V) : void; get(key : K) : V; getSize() : number; hasKey(key : K) : boolean; remove(key : K) : void; removeIf(func : Func, boolean>) : void; }interface IList extends IListableCollection { insertAt(index : number, value : T) : void; }interface IListableCollection extends ISortableCollection { add(value : T) : void; getAt(index : number) : T; getLength() : number; remove(value : T) : void; removeAt(index : number) : void; removeIf(func : Func) : void; }interface ISortableCollection extends ICollection { orderBy(getter : Func) : ISortableCollection; orderByDesc(getter : Func) : ISortableCollection; reverse() : ISortableCollection; }module CollectionUtils { export class ArrayUtils { private static _swap(source : Array, i : number, j : number) : void { var tmp : T; tmp = source[i]; source[i] = source[j]; source[j] = tmp; } private static _partition( source : Array, getter : Func, comparator : Func2, first : number, last : number, pivot : number) : number { var j : number; var pivotValue : U; j = pivot; pivotValue = getter(source[pivot]); for (var i = first; i <= last; i++) { var value : U; value = getter(source[i]); if (comparator(value, pivotValue)) { if (j < i) { ArrayUtils._swap(source, j + 1, i); ArrayUtils._swap(source, j, j + 1); j++; } } else { if (i < j) { ArrayUtils._swap(source, i, j); j = i; } } } return j; } private static _sort( source : Array, getter : Func, comparator : Func2, first : number, last : number) : void { if (first < last) { var pivot : number; pivot = Math.round(Math.random() * (last - first)); pivot = ArrayUtils._partition(source, getter, comparator, first, last, pivot); ArrayUtils._sort(source, getter, comparator, first, pivot - 1); ArrayUtils._sort(source, getter, comparator, pivot + 1, last); } } static sort(source : Array, getter : Func, asc : boolean = true) : void { var comparator : Func2; if (source.length === 0) { return; } if (asc) { comparator = (a, b) => { return a <= b; }; } else { comparator = (a, b) => { return a >= b; }; } ArrayUtils._sort(source, getter, comparator, 0, source.length - 1); } } }class CollectionException extends Exception { constructor(msg : string) { super(msg, 'CollectionException'); } }module CollectionUtils { export class CollectionHelper { private static _extrema( source : ICollection, getter : Func, comparator : Func2) : T { var outcome : T; var extrema : number; var isFirstTime : boolean; isFirstTime = true; source.forEach( (e) => { if (isFirstTime) { isFirstTime = false; outcome = e; extrema = getter(e); } else { var value : number; value = getter(e); if (comparator(value, extrema)) { outcome = e; extrema = value; } } } ); if (isFirstTime) { return null; } else { return outcome; } } static average(source : ICollection, getter : Func) : number { var outcome : number; var size : number; size = 0; outcome = 0; source.forEach( (x) => { outcome += getter(x); size++; } ); if (size === 0) { return 0; } else { return outcome / size; } } static max(source : ICollection, getter : Func) : T { return CollectionHelper._extrema(source, getter, (a, b) => a > b); } static min(source : ICollection, getter : Func) : T { return CollectionHelper._extrema(source, getter, (a, b) => a < b); } static sum(source : ICollection, getter : Func) : number { var outcome : number; outcome = 0; source.forEach(x => outcome += getter(x)); return outcome; } static toArray(source : ICollection) : Array { var outcome : Array; outcome = new Array(); source.forEach(x => outcome.push(x)); return outcome; } static toDictionary( source : ICollection, keyGetter : Func, valueGetter : Func) : IDictionary { var outcome : IDictionary; outcome = new Dictionary(); source.forEach(x => outcome.add(keyGetter(x), valueGetter(x))); return outcome; } static toList(source : ICollection) : IList { return new ArrayList(source); } } } \ No newline at end of file diff --git a/app/models/business/ITagBookmarkBusiness.ts b/app/models/business/ITagBookmarkBusiness.ts index 70c05d9..95077c5 100644 --- a/app/models/business/ITagBookmarkBusiness.ts +++ b/app/models/business/ITagBookmarkBusiness.ts @@ -24,7 +24,7 @@ interface ITagBookmarkBusiness { errorHandler? : Action) : void; /** - * Sorts all bookmarks by title ascending + * Sorts all bookmarks by title ascending * @param {TagDAO} tag [description] * @param {Action>} callback [description] */ @@ -37,7 +37,10 @@ interface ITagBookmarkBusiness { exportToBrowser(callback : Action, errorHandler? : Action) : void; - search(input : string, callback : Action>, errorHandler? : Action) : void; + search( + input : string, + callback : Action>, + errorHandler? : Action) : void; rawBackup(callback : Action, errorHandler? : Action) : void; diff --git a/app/models/business/impl/TagBookmarkBusiness.ts b/app/models/business/impl/TagBookmarkBusiness.ts index f2e9a69..4aaf67b 100644 --- a/app/models/business/impl/TagBookmarkBusiness.ts +++ b/app/models/business/impl/TagBookmarkBusiness.ts @@ -4,21 +4,21 @@ class TagBookmarkBusiness implements ITagBookmarkBusiness { //region Fields private _args : TagBookmarkBusinessArgs; - + //endregion Fields - + //region Constructors constructor(args : TagBookmarkBusinessArgs) { this._args = args; } - + //endregion Constructors - + //region Methods - + //region Private Methods - + private _browseDLNode( node : DOMElement, currentTags : IList, @@ -130,19 +130,6 @@ class TagBookmarkBusiness implements ITagBookmarkBusiness { ); } - private _addInScoredList(target : ScoredBookmark, list : IList) : void { - for (var i = 0; i < list.getLength(); i++) { - var e : ScoredBookmark = list.getAt(i); - - if (target.getScore() > e.getScore()) { - list.insertAt(i, target); - return; - } - } - - list.add(target); - } - private _addCouple(currentIndex : number, list : Array, callback? : Action0) : void { var e : any; var t : Tag; @@ -248,9 +235,9 @@ class TagBookmarkBusiness implements ITagBookmarkBusiness { } //endregion Private Methods - + //region Public Methods - + sortTagsByLabelAscForBookmark( bookmark : Bookmark, callback : Action>, @@ -469,7 +456,7 @@ class TagBookmarkBusiness implements ITagBookmarkBusiness { tag : Tag, callback : Action>, errorHandler? : Action) : void { - + errorHandler = ActionHelper.getValueOrDefault(errorHandler); if (!TSObject.exists(tag)) { @@ -574,7 +561,10 @@ class TagBookmarkBusiness implements ITagBookmarkBusiness { ); } - search(input : string, callback : Action>, errorHandler? : Action) : void { + search( + input : string, + callback : Action>, + errorHandler? : Action) : void { errorHandler = ActionHelper.getValueOrDefault(errorHandler); this @@ -583,7 +573,7 @@ class TagBookmarkBusiness implements ITagBookmarkBusiness { .sortBookmarksByTitleAscWithBoundTagsByLabelAsc( (outcome) => { var max : number; - var list : IList; + var list : SortedList; var keywords : IList; if (!TSObject.exists(outcome)) { @@ -593,7 +583,7 @@ class TagBookmarkBusiness implements ITagBookmarkBusiness { } max = 0.0; - list = new ArrayList(); + list = new SortedList(x => x.getScore(), false); keywords = StringHelper.extractWords(input); outcome.forEach( @@ -633,7 +623,7 @@ class TagBookmarkBusiness implements ITagBookmarkBusiness { max = (currentScore > max) ? currentScore : max; sbk.setScore(currentScore); - this._addInScoredList(sbk, list); + list.add(sbk); } ); @@ -715,7 +705,7 @@ class TagBookmarkBusiness implements ITagBookmarkBusiness { backup(callback? : Action0, errorHandler? : Action) : void { callback = ActionHelper.getValueOrDefaultNoArgs(callback); errorHandler = ActionHelper.getValueOrDefault(errorHandler); - + this.rawBackup( (result) => { FileAPI.writeFile( @@ -780,11 +770,11 @@ class TagBookmarkBusiness implements ITagBookmarkBusiness { } ); }; - + reader.readAsText(dataTransfer.files[0]); } //endregion Public Methods - + //endregion Methods } diff --git a/app/presenters/MainPresenter/BookmarkList.ts b/app/presenters/MainPresenter/BookmarkList.ts index d2ffb98..31e2dc0 100644 --- a/app/presenters/MainPresenter/BookmarkList.ts +++ b/app/presenters/MainPresenter/BookmarkList.ts @@ -19,9 +19,9 @@ class BookmarkList implements IBookmarkContextMenuListener { private _currentTag : Tag; private _currentLabel : DOMElement; - + //endregion Fields - + //region Constructors constructor(listener : IBookmarkListListener) { @@ -31,11 +31,11 @@ class BookmarkList implements IBookmarkContextMenuListener { this._ctxtMenu = new BookmarkContextMenu(this); this._currentLabel = DOMTree.findSingle('.js-current-tag'); } - + //endregion Constructors - + //region Methods - + //region Private Methods private _setCurrentLabel(value : string) : void { @@ -82,9 +82,9 @@ class BookmarkList implements IBookmarkContextMenuListener { } ); } - + //endregion Private Methods - + //region Public Methods sortMostPopular() : void { @@ -167,273 +167,8 @@ class BookmarkList implements IBookmarkContextMenuListener { } //endregion IBookmarkContextMenuListener - + //endregion Public Methods - + //endregion Methods } - -// class BookmarkList { -// //region Fields - -// private _subscriber : IBookmarkListSubscriber; - -// private _destList : DOMElement; -// private _wrapper : DOMElement; - -// private _defaultContent : DOMElement; -// private _isDefaultContentCurrent : boolean; -// private _keyboardEventObj : DOMElementEventObject; - -// //endregion Fields - -// //region Constructors - -// constructor(sub : IBookmarkListSubscriber) { -// this._subscriber = sub; -// this._wrapper = DOMTree.findSingle('.js-bookmark-wrapper'); -// this._destList = this._wrapper.findSingle('.js-bookmark-list'); -// this._defaultContent = this._wrapper.findSingle('.js-default-content'); -// this._isDefaultContentCurrent = false; - -// DOMTree -// .getDocument() -// .on( -// DOMElementEvents.KeyDown, -// (e) => { -// this._keyboardEventObj = e; -// } -// ); - -// DOMTree -// .getDocument() -// .on( -// DOMElementEvents.KeyUp, -// (e) => { -// this._keyboardEventObj = null; -// } -// ); -// } - -// //endregion Constructors - -// //region Methods - -// //region Private Methods - -// private _buildDOMBookmark(bookmark : Bookmark) : DOMElement { -// var e : DOMElement; -// var s : StringBuffer; -// var truncatedDescription : string; - -// s = new StringBuffer('
  • '); - -// s.append(FaviconHelper.getImgTag(bookmark.getURL()).toString()); -// s.append('

    ' + bookmark.getTitle() + '

    '); -// truncatedDescription = StringHelper.truncate(bookmark.getDescription(), 50); -// s.append('

    ' + truncatedDescription + '

    '); - -// e = DOMElement.fromString(s.toString()); -// e.setData('id', bookmark.getId()); - -// return e; -// } - -// private _buildDOMSearchResult(bookmark : ScoredBookmark) : DOMElement { -// var e : DOMElement; -// var s : StringBuffer; -// var score : string; - -// score = NumberHelper.toString(Math.round(bookmark.getScore() * 100)); - -// s = new StringBuffer('
  • '); -// s.append('
    '); -// s.append('
    '); -// s.append(FaviconHelper.getImgTag(bookmark.getURL()).toString()); -// s.append('

    ' + bookmark.getTitle() + '

    '); -// s.append('

    ' + bookmark.getDescription() + '

    '); -// s.append('
    '); -// s.append('

    ' + score + '%

    '); -// s.append('
  • '); - - -// e = DOMElement.fromString(s.toString()); -// e.setData('id', bookmark.getId()); - -// return e; -// } - -// private _subscribeTriggers() : void { -// this._destList -// .getChildren() -// .forEach( -// (e) => { -// e.on( -// DOMElementEvents.Click, -// (arg) => { -// if (TSObject.exists(this._keyboardEventObj)) { -// if (this._keyboardEventObj.getWhich() === 17 -// || this._keyboardEventObj.isMetaKey()) { -// this._keyboardEventObj = null; - -// BusinessFactory.buildBookmark( -// (business) => { -// business.find( -// e.getData('id'), -// (outcome) => { -// outcome.setViews(outcome.getViews() + 1); -// // TODO: test errors -// business.update(outcome); -// NodeWindow.openExternal(outcome.getURL()); -// } -// ); -// } -// ); -// } -// } else { -// this._subscriber.onBookmarkSelection(e.getData('id')); -// } -// } -// ); -// } -// ); -// } - -// private _reset() : void { -// this._hide(); -// this._destList.getChildren().forEach(e => e.off(DOMElementEvents.Click)); -// this._destList.getChildren().forEach(e => e.remove()); -// } - -// private _setDefaultContent() : void { -// if (this._isDefaultContentCurrent) { -// return; -// } - -// this._destList.setCss({ display : 'none' }); -// this._defaultContent.setCss({ display : 'block' }); -// this._isDefaultContentCurrent = true; -// } - -// private _removeDefaultContent() : void { -// if (!this._isDefaultContentCurrent) { -// return; -// } - -// this._destList.setCss({ display : 'block' }); -// this._defaultContent.setCss({ display : 'none' }); -// this._isDefaultContentCurrent = false; -// } - -// private _hide() : void { -// this._wrapper.setCss({opacity : 0}); -// } - -// private _show() : void { -// this._wrapper.animate( -// { -// opacity : 1 -// }, -// 500 -// ); -// } - -// //endregion Private Methods - -// //region Public Methods - -// displayMostPopular() : void { -// this._reset(); - -// BusinessFactory.buildBookmark( -// (business) => { -// business.sortByViewsDescThenByTitleAsc( -// (outcome) => { -// if (outcome.getLength() < 1) { -// this._setDefaultContent(); -// } else { -// this._removeDefaultContent(); -// outcome.forEach( -// (e) => { -// this._destList.append(this._buildDOMBookmark(e)); -// } -// ); -// this._subscribeTriggers(); -// } -// this._show(); -// } -// ); -// } -// ); -// } - -// displayForTag(tag : Tag) : void { -// this._reset(); - -// BusinessFactory.buildTagBookmark( -// (business) => { -// business.sortBookmarksByTitleAscForTag( -// tag, -// (outcome) => { -// if (outcome.getLength() < 1) { -// this._setDefaultContent(); -// } elseĀ { -// this._removeDefaultContent(); -// outcome.forEach( -// (e) => { -// this._destList.append(this._buildDOMBookmark(e)); -// } -// ); -// this._subscribeTriggers(); -// } -// this._show(); -// } -// ); -// } -// ); -// } - -// displayForSeachInput(value : string) : void { -// this._reset(); - -// BusinessFactory.buildTagBookmark( -// (business) => { -// business.search( -// value, -// (outcome) => { -// if (outcome.getLength() < 1) { -// this._setDefaultContent(); -// } else { -// this._removeDefaultContent(); -// outcome.forEach( -// (e) => { -// this._destList.append(this._buildDOMSearchResult(e)); -// } -// ); -// this._subscribeTriggers(); -// } -// this._show(); -// } -// ); -// } -// ); -// } - -// unfocus() : void { -// this._keyboardEventObj = null; -// } - -// //endregion Public Methods - -// //endregion Methods -// } diff --git a/testing/buildLauncher.py b/testing/buildLauncher.py old mode 100644 new mode 100755 index 2ba457e..29a047c --- a/testing/buildLauncher.py +++ b/testing/buildLauncher.py @@ -17,11 +17,14 @@ def __collect(self, path): for root, dirs, files in os.walk(path): for fileName in files: - with open(os.path.join(root, fileName), 'r') as f: - for line in f: - outcome = re.findall(pattern, line) - for e in outcome: - collected.append(e) + ext = os.path.splitext(fileName)[1] + + if ext == '.ts': + with open(os.path.join(root, fileName), 'r') as f: + for line in f: + outcome = re.findall(pattern, line) + for e in outcome: + collected.append(e) return collected diff --git a/testing/src/libs/oscar.1.0.2.min.ts b/testing/src/libs/oscar.1.0.4.min.ts similarity index 75% rename from testing/src/libs/oscar.1.0.2.min.ts rename to testing/src/libs/oscar.1.0.4.min.ts index 09096b0..bfd338a 100755 --- a/testing/src/libs/oscar.1.0.2.min.ts +++ b/testing/src/libs/oscar.1.0.4.min.ts @@ -1 +1 @@ -module Oscar { export interface IOscarObserverListener { onSuccess() : void; onFail(error? : Error) : void; } }module Oscar { export class OscarObserver implements IOscarObserver { private _isStopped : boolean; private _listener : Oscar.IOscarObserverListener; constructor(listener : Oscar.IOscarObserverListener) { this._listener = listener; this._isStopped = false; } success() : void { if (!this._isStopped) { setTimeout( () => { if (!this._isStopped) { this._isStopped = true; this._listener.onSuccess(); } }, 0 ); } } fail(error? : Error) : void { if (!this._isStopped) { setTimeout( () => { if (!this._isStopped) { this._isStopped = true; this._listener.onFail(error); } }, 0 ); } } stop() : void { this._isStopped = true; } } }module Oscar { export class TestClass { private _core : UnitTestClass; private _methods : Array; constructor(core : UnitTestClass) { this._core = core; this._methods = new Array(); } getName() : string { return ( this._core).constructor.name; } getCore() : UnitTestClass { return this._core; } addMethod(value : TestMethod) : TestClass { this._methods.push(value); return this; } getMethods() : Array { return this._methods; } } }module Oscar { export class TestMethod { private _name : string; private _core : () => void; private _isAsync : boolean; private _observer : Oscar.OscarObserver; private _success : boolean; private _error : Error; private _time : number; constructor(name : string, core : () => void, isAsync : boolean = false) { this._name = name; this._core = core; this._isAsync = isAsync; } getName() : string { return this._name; } getCore() : () => void { return this._core; } isAsync() : boolean { return this._isAsync; } getObserver() : Oscar.OscarObserver { return this._observer; } setObserver(observer : Oscar.OscarObserver) : void { this._observer = observer; } isSuccess() : boolean { return this._success; } setSuccess(value : boolean) : void { this._success = value; } getError() : Error { if (this._error !== null && this._error !== undefined) { return this._error; } return new Error('Unknown error'); } setError(value : Error) : void { this._error = value; } getTime() : number { return this._time; } setStart() : void { this._time = new Date().getTime(); } setEnd() : void { this._time = (new Date().getTime()) - this._time; } } }module Oscar { export class Utils { static shuffleArray(a : Array) : void { var n : number; var f : (min : number, max : number) => number; f = (min, max) => { return Math.round(Math.random() * max) + min; }; n = f(a.length, a.length * a.length); while (n >= 0) { var i : number, j : number; var tmp : T; i = f(0, a.length - 1); j = f(0, a.length - 1); tmp = a[i]; a[i] = a[j]; a[j] = tmp; n--; } } } }class Assert { static isTrue(value : boolean) : void { if (!value) { throw new Error('Expected value to be true'); } } static isFalse(value : boolean) : void { if (value) { throw new Error('Expected value to be false'); } } static isNull(value : T) : void { if (value !== null && value !== undefined) { throw new Error('Expected value to be null'); } } static isNotNull(value : T) : void { if (value === null || value === undefined) { throw new Error('Expected value to be not null'); } } static areEqual(expected : T, value : T) : void { if (value !== expected) { throw new Error('Expected ' + expected + ' instead of ' + value); } } static areNotEqual(unexpected : T, value : T) : void { if (value === unexpected) { throw new Error('Unexpected ' + unexpected + ' instead of ' + value); } } static throws(func : () => void) : void { var hasFailed : boolean; hasFailed = false; try { func(); } catch (e) { hasFailed = true; } finally { if (!hasFailed) { throw new Error('Expected function to throw an error'); } } } }interface IOscarObserver { success() : void; fail(error? : Error) : void; }class UnitTestClass { setUp() : void { } tearDown() : void { } }enum TestSuiteOutput { CONSOLE, HTML } declare var process : any; class TestSuite implements Oscar.IOscarObserverListener { private _collected : Array; private _totalTests : number; private _successfulTests : number; private _totalRuntime : number; private _output : TestSuiteOutput; private _maxRuntime : number; private _buildFailure : boolean; private _currentTestClass : Oscar.TestClass; private _currentTestClassIndex : number; private _currentTestMethodIndex : number; private _currentAsyncTest : Oscar.TestMethod; private _asyncTimer : any; constructor() { this._collected = new Array(); } private _moveToNextTest() : void { this._currentTestMethodIndex++; if (this._currentTestMethodIndex < this._currentTestClass.getMethods().length) { this._runSingleTest(this._currentTestClass.getMethods()[this._currentTestMethodIndex]); } else { this._handleClass(); } } private _runSingleTest(test : Oscar.TestMethod) : void { if (test.isAsync()) { var hasFailed : boolean; this._currentAsyncTest = test; test.setObserver(new Oscar.OscarObserver(this)); try { test.setStart(); this._currentTestClass.getCore().setUp(); test.getCore().call(this._currentTestClass.getCore(), test.getObserver()); hasFailed = false; } catch (e) { try { this._currentTestClass.getCore().tearDown(); } catch (e) { } test.setEnd(); test.setSuccess(false); test.setError(e); hasFailed = true; } finally { if (hasFailed) { test.getObserver().stop(); this._totalTests++; this._totalRuntime += test.getTime(); this._moveToNextTest(); } else { this._asyncTimer = setTimeout(() => { test.getObserver().stop(); this.onFail(new Error('Maximum runtime exceeded')); }, this._maxRuntime); } } } else { try { test.setStart(); this._currentTestClass.getCore().setUp(); test.getCore().call(this._currentTestClass.getCore()); this._currentTestClass.getCore().tearDown(); test.setEnd(); test.setSuccess(true); } catch (e) { try { this._currentTestClass.getCore().tearDown(); } catch (e) { } test.setEnd(); test.setSuccess(false); test.setError(e); } finally { if (test.isSuccess()) { this._successfulTests++; } this._totalTests++; this._totalRuntime += test.getTime(); this._moveToNextTest(); } } } private _handleClass() : void { var methods : Array; this._currentTestClassIndex++; if (this._currentTestClassIndex >= this._collected.length) { this._onRunOver(); return; } this._currentTestClass = this._collected[this._currentTestClassIndex]; methods = this._currentTestClass.getMethods(); if (methods.length < 1) { this._handleClass(); return; } Oscar.Utils.shuffleArray(methods); this._currentTestMethodIndex = 0; this._runSingleTest(methods[0]); } private _onRunOver() : void { var failedTests : number; var sortMethod : (a : Oscar.TestMethod, b : Oscar.TestMethod) => number; failedTests = this._totalTests - this._successfulTests; this._collected.sort( (a, b) => { if (a.getName() > b.getName()) { return 1; } else if (a.getName() < b.getName()) { return -1; } else { return 0; } } ); sortMethod = (a, b) => { if (a.getName() > b.getName()) { return 1; } else if (a.getName() < b.getName()) { return -1; } else { return 0; } }; for (var i = 0; i < this._collected.length; i++) { this._collected[i].getMethods().sort(sortMethod); } if (this._output === TestSuiteOutput.CONSOLE) { console.log('--- Unit testing sum up ---'); if (this._totalRuntime < 1) { console.log('Total: ' + this._totalTests + ' run in less than 1ms.'); } else { console.log('Total: ' + this._totalTests + ' run in ' + this._totalRuntime + 'ms.'); } console.log('Passed tests: ' + this._successfulTests); console.log('Failed tests: ' + failedTests + '\n'); for (var i = 0; i < this._collected.length; i++) { var testClass : Oscar.TestClass; testClass = this._collected[i]; console.log(testClass.getName() + ':'); for (var j = 0; j < testClass.getMethods().length; j++) { var testMethod : Oscar.TestMethod; testMethod = testClass.getMethods()[j]; if (testMethod.isSuccess()) { if (testMethod.getTime() < 1) { console.log('\t' + testMethod.getName() + ' - less than 1ms'); } else { console.log('\t' + testMethod.getName() + ' - ' + testMethod.getTime() + 'ms'); } } else { console.error('\t' + testMethod.getName() + ' FAILED'); console.error('\t\t' + testMethod.getError().toString()); } } } } else { var outcome : string; outcome = '

    Unit testing sum up

    '; outcome += '

    Total tests: ' + this._totalTests + '. '; outcome += 'Passed tests: ' + this._successfulTests + '. '; outcome += 'Failed tests: ' + failedTests + '.

    '; outcome += '

    Total: '; if (this._totalRuntime < 1) { outcome += 'less than 1'; } else { outcome += this._totalRuntime; } outcome += 'ms

    '; outcome += '
      '; for (var i = 0; i < this._collected.length; i++) { var testClass : Oscar.TestClass; testClass = this._collected[i]; outcome += '
    • ' + testClass.getName() + '
        '; for (var j = 0; j < testClass.getMethods().length; j++) { var testMethod : Oscar.TestMethod; testMethod = testClass.getMethods()[j]; outcome += '
      • ' + testMethod.getName() + ' - '; if (testMethod.getTime() < 1) { outcome += 'less than 1'; } else { outcome += testMethod.getTime(); } outcome += 'ms'; } else { outcome += 'fail">' + testMethod.getName() + ' FAILED'; outcome += '

        ' + testMethod.getError().toString() + '

        '; } outcome += '
      • '; } outcome += '
    • '; } outcome += '
    '; if (document.body !== null && document.body !== undefined) { document.body.innerHTML += outcome; } else { document.documentElement.innerHTML += '' + outcome + ''; } } if (failedTests > 0 && this._buildFailure) { if (process !== null && process !== undefined) { process.exit(1); } } } private _processFailure(error : Error) : void { this._currentAsyncTest.setEnd(); this._currentAsyncTest.setSuccess(false); this._currentAsyncTest.setError(error); this._totalRuntime += this._currentAsyncTest.getTime(); this._totalTests++; this._moveToNextTest(); } add(test : UnitTestClass) : TestSuite { var testClass : Oscar.TestClass; testClass = new Oscar.TestClass(test); for (var name in test) { var prop : any; var l : number; prop = test[name]; l = name.length; if (typeof(prop) === 'function') { if (l > 4) { var suffix : string; suffix = name.substring(l - 4, l).toLowerCase(); if (suffix === 'test') { var testMethod : Oscar.TestMethod; if (l > 9) { var extendedSuffix : string; extendedSuffix = name.substring(l - 9, l - 4).toLowerCase(); if (extendedSuffix === 'async') { testMethod = new Oscar.TestMethod(name, prop, true); } else { testMethod = new Oscar.TestMethod(name, prop, false); } } else { testMethod = new Oscar.TestMethod(name, prop, false); } testClass.addMethod(testMethod); } } } } this._collected.push(testClass); return this; } run(output? : TestSuiteOutput, maxRuntime? : number, buildFailure? : boolean) : void { if (output !== null && output !== undefined) { this._output = output; } else { this._output = TestSuiteOutput.CONSOLE; } if (maxRuntime !== null && maxRuntime !== undefined) { this._maxRuntime = maxRuntime; } else { this._maxRuntime = 30 * 1000; } if (buildFailure !== null && buildFailure !== undefined) { this._buildFailure = buildFailure; } else { this._buildFailure = true; } if (this._collected.length < 1) { throw new Error('No test collected'); } this._totalTests = 0; this._successfulTests = 0; this._totalRuntime = 0; Oscar.Utils.shuffleArray(this._collected); this._currentTestClassIndex = -1; this._handleClass(); } onSuccess() : void { var isTearDownOk : boolean; var error : Error; clearTimeout(this._asyncTimer); this._asyncTimer = null; try { this._currentTestClass.getCore().tearDown(); isTearDownOk = true; } catch (e) { error = e; isTearDownOk = false; } if (!isTearDownOk) { this._processFailure(error); return; } this._currentAsyncTest.setEnd(); this._currentAsyncTest.setSuccess(true); this._successfulTests++; this._totalTests++; this._totalRuntime += this._currentAsyncTest.getTime(); this._moveToNextTest(); } onFail(error? : Error) : void { clearTimeout(this._asyncTimer); this._asyncTimer = null; try { this._currentTestClass.getCore().tearDown(); } catch (e) { } this._processFailure(error); } } \ No newline at end of file +module Oscar { export interface IOscarObserverListener { onSuccess() : void; onFail(error? : Error) : void; } }module Oscar { export class OscarObserver implements IOscarObserver { private _isStopped : boolean; private _listener : Oscar.IOscarObserverListener; constructor(listener : Oscar.IOscarObserverListener) { this._listener = listener; this._isStopped = false; } success() : void { if (!this._isStopped) { setTimeout( () => { if (!this._isStopped) { this._isStopped = true; this._listener.onSuccess(); } }, 0 ); } } fail(error? : Error) : void { if (!this._isStopped) { setTimeout( () => { if (!this._isStopped) { this._isStopped = true; this._listener.onFail(error); } }, 0 ); } } stop() : void { this._isStopped = true; } } }module Oscar { export class TestClass { private _core : UnitTestClass; private _methods : Array; constructor(core : UnitTestClass) { this._core = core; this._methods = new Array(); } getName() : string { return ( this._core).constructor.name; } getCore() : UnitTestClass { return this._core; } addMethod(value : TestMethod) : TestClass { this._methods.push(value); return this; } getMethods() : Array { return this._methods; } } }module Oscar { export class TestMethod { private _name : string; private _core : () => void; private _isAsync : boolean; private _observer : Oscar.OscarObserver; private _success : boolean; private _error : Error; private _time : number; constructor(name : string, core : () => void, isAsync : boolean = false) { this._name = name; this._core = core; this._isAsync = isAsync; } getName() : string { return this._name; } getCore() : () => void { return this._core; } isAsync() : boolean { return this._isAsync; } getObserver() : Oscar.OscarObserver { return this._observer; } setObserver(observer : Oscar.OscarObserver) : void { this._observer = observer; } isSuccess() : boolean { return this._success; } setSuccess(value : boolean) : void { this._success = value; } getError() : Error { if (this._error !== null && this._error !== undefined) { return this._error; } return new Error('Unknown error'); } setError(value : Error) : void { this._error = value; } getTime() : number { return this._time; } setStart() : void { this._time = new Date().getTime(); } setEnd() : void { this._time = (new Date().getTime()) - this._time; } } }module Oscar { export class Utils { static shuffleArray(a : Array) : void { var n : number; var f : (min : number, max : number) => number; f = (min, max) => { return Math.round(Math.random() * max) + min; }; n = f(a.length, a.length * a.length); while (n >= 0) { var i : number, j : number; var tmp : T; i = f(0, a.length - 1); j = f(0, a.length - 1); tmp = a[i]; a[i] = a[j]; a[j] = tmp; n--; } } } }class Assert { static isTrue(value : boolean) : void { if (!value) { throw new Error('Expected value to be true'); } } static isFalse(value : boolean) : void { if (value) { throw new Error('Expected value to be false'); } } static isNull(value : T) : void { if (value !== null && value !== undefined) { throw new Error('Expected value to be null'); } } static isNotNull(value : T) : void { if (value === null || value === undefined) { throw new Error('Expected value to be not null'); } } static areEqual(expected : T, value : T) : void { if (value !== expected) { throw new Error('Expected ' + expected + ' instead of ' + value); } } static areNotEqual(unexpected : T, value : T) : void { if (value === unexpected) { throw new Error('Unexpected ' + unexpected + ' instead of ' + value); } } static throws(func : () => void) : void { var hasFailed : boolean; hasFailed = false; try { func(); } catch (e) { hasFailed = true; } finally { if (!hasFailed) { throw new Error('Expected function to throw an error'); } } } }interface IOscarObserver { success() : void; fail(error? : Error) : void; }class UnitTestClass { setUp() : void { } tearDown() : void { } }enum TestSuiteOutput { CONSOLE, HTML } declare var process : any; class TestSuite implements Oscar.IOscarObserverListener { private _collected : Array; private _totalTests : number; private _successfulTests : number; private _totalRuntime : number; private _output : TestSuiteOutput; private _maxRuntime : number; private _buildFailure : boolean; private _currentTestClass : Oscar.TestClass; private _currentTestClassIndex : number; private _currentTestMethodIndex : number; private _currentAsyncTest : Oscar.TestMethod; private _asyncTimer : any; constructor() { this._collected = new Array(); } private _moveToNextTest() : void { this._currentTestMethodIndex++; if (this._currentTestMethodIndex < this._currentTestClass.getMethods().length) { this._runSingleTest(this._currentTestClass.getMethods()[this._currentTestMethodIndex]); } else { this._handleClass(); } } private _runSingleTest(test : Oscar.TestMethod) : void { if (test.isAsync()) { var hasFailed : boolean; this._currentAsyncTest = test; test.setObserver(new Oscar.OscarObserver(this)); try { test.setStart(); this._currentTestClass.getCore().setUp(); test.getCore().call(this._currentTestClass.getCore(), test.getObserver()); hasFailed = false; } catch (e) { try { this._currentTestClass.getCore().tearDown(); } catch (e) { } test.setEnd(); test.setSuccess(false); test.setError(e); hasFailed = true; } finally { if (hasFailed) { test.getObserver().stop(); this._totalTests++; this._totalRuntime += test.getTime(); this._moveToNextTest(); } else { this._asyncTimer = setTimeout(() => { test.getObserver().stop(); this.onFail(new Error('Maximum runtime exceeded')); }, this._maxRuntime); } } } else { try { test.setStart(); this._currentTestClass.getCore().setUp(); test.getCore().call(this._currentTestClass.getCore()); this._currentTestClass.getCore().tearDown(); test.setEnd(); test.setSuccess(true); } catch (e) { try { this._currentTestClass.getCore().tearDown(); } catch (e) { } test.setEnd(); test.setSuccess(false); test.setError(e); } finally { if (test.isSuccess()) { this._successfulTests++; } this._totalTests++; this._totalRuntime += test.getTime(); this._moveToNextTest(); } } } private _handleClass() : void { var methods : Array; this._currentTestClassIndex++; if (this._currentTestClassIndex >= this._collected.length) { this._onRunOver(); return; } this._currentTestClass = this._collected[this._currentTestClassIndex]; methods = this._currentTestClass.getMethods(); if (methods.length < 1) { this._handleClass(); return; } Oscar.Utils.shuffleArray(methods); this._currentTestMethodIndex = 0; this._runSingleTest(methods[0]); } private _onRunOver() : void { var failedTests : number; var sortMethod : (a : Oscar.TestMethod, b : Oscar.TestMethod) => number; failedTests = this._totalTests - this._successfulTests; this._collected.sort( (a, b) => { if (a.getName() > b.getName()) { return 1; } else if (a.getName() < b.getName()) { return -1; } else { return 0; } } ); sortMethod = (a, b) => { if (a.getName() > b.getName()) { return 1; } else if (a.getName() < b.getName()) { return -1; } else { return 0; } }; for (var i = 0; i < this._collected.length; i++) { this._collected[i].getMethods().sort(sortMethod); } if (this._output === TestSuiteOutput.CONSOLE) { console.log('--- Unit testing sum up ---'); if (this._totalRuntime < 1) { console.log('Total: ' + this._totalTests + ' run in less than 1ms.'); } else { console.log('Total: ' + this._totalTests + ' run in ' + this._totalRuntime + 'ms.'); } console.log('Passed tests: ' + this._successfulTests); console.log('Failed tests: ' + failedTests + '\n'); for (var i = 0; i < this._collected.length; i++) { var testClass : Oscar.TestClass; testClass = this._collected[i]; console.log(testClass.getName() + ':'); for (var j = 0; j < testClass.getMethods().length; j++) { var testMethod : Oscar.TestMethod; testMethod = testClass.getMethods()[j]; if (testMethod.isSuccess()) { if (testMethod.getTime() < 1) { console.log('\t' + testMethod.getName() + ' - less than 1ms'); } else { console.log('\t' + testMethod.getName() + ' - ' + testMethod.getTime() + 'ms'); } } else { console.error('\t' + testMethod.getName() + ' FAILED'); console.error('\t\t' + testMethod.getError().toString()); } } } } else { var outcome : string; outcome = '

    Unit testing sum up

    '; outcome += '

    Total tests: ' + this._totalTests + '. '; outcome += 'Passed tests: ' + this._successfulTests + '. '; outcome += 'Failed tests: ' + failedTests + '.

    '; outcome += '

    Total: '; if (this._totalRuntime < 1) { outcome += 'less than 1'; } else { outcome += this._totalRuntime; } outcome += 'ms

    '; outcome += '
      '; for (var i = 0; i < this._collected.length; i++) { var testClass : Oscar.TestClass; testClass = this._collected[i]; outcome += '
    • ' + testClass.getName() + '
        '; for (var j = 0; j < testClass.getMethods().length; j++) { var testMethod : Oscar.TestMethod; testMethod = testClass.getMethods()[j]; outcome += '
      • ' + testMethod.getName() + ' - '; if (testMethod.getTime() < 1) { outcome += 'less than 1'; } else { outcome += testMethod.getTime(); } outcome += 'ms'; } else { outcome += 'fail">' + testMethod.getName() + ' FAILED'; outcome += '

        ' + testMethod.getError().toString() + '

        '; console.log( '%c' + testMethod.getName() + ' failed with error ' + testMethod.getError().message, 'color: red' ); console.log('%c' + (testMethod.getError()).stack, 'color : red'); } outcome += '
      • '; } outcome += '
    • '; } outcome += '
    '; if (document.body !== null && document.body !== undefined) { document.body.innerHTML += outcome; } else { document.documentElement.innerHTML += '' + outcome + ''; } } if (failedTests > 0 && this._buildFailure) { if (process !== null && process !== undefined) { process.exit(1); } } } private _processFailure(error : Error) : void { this._currentAsyncTest.setEnd(); this._currentAsyncTest.setSuccess(false); this._currentAsyncTest.setError(error); this._totalRuntime += this._currentAsyncTest.getTime(); this._totalTests++; this._moveToNextTest(); } add(test : UnitTestClass) : TestSuite { var testClass : Oscar.TestClass; testClass = new Oscar.TestClass(test); for (var name in test) { var prop : any; var l : number; prop = test[name]; l = name.length; if (typeof(prop) === 'function') { if (l > 4) { var suffix : string; suffix = name.substring(l - 4, l).toLowerCase(); if (suffix === 'test') { var testMethod : Oscar.TestMethod; if (l > 9) { var extendedSuffix : string; extendedSuffix = name.substring(l - 9, l - 4).toLowerCase(); if (extendedSuffix === 'async') { testMethod = new Oscar.TestMethod(name, prop, true); } else { testMethod = new Oscar.TestMethod(name, prop, false); } } else { testMethod = new Oscar.TestMethod(name, prop, false); } testClass.addMethod(testMethod); } } } } this._collected.push(testClass); return this; } run(output? : TestSuiteOutput, maxRuntime? : number, buildFailure? : boolean) : void { if (output !== null && output !== undefined) { this._output = output; } else { this._output = TestSuiteOutput.CONSOLE; } if (maxRuntime !== null && maxRuntime !== undefined) { this._maxRuntime = maxRuntime; } else { this._maxRuntime = 30 * 1000; } if (buildFailure !== null && buildFailure !== undefined) { this._buildFailure = buildFailure; } else { this._buildFailure = true; } if (this._collected.length < 1) { throw new Error('No test collected'); } this._totalTests = 0; this._successfulTests = 0; this._totalRuntime = 0; Oscar.Utils.shuffleArray(this._collected); this._currentTestClassIndex = -1; this._handleClass(); } onSuccess() : void { var isTearDownOk : boolean; var error : Error; clearTimeout(this._asyncTimer); this._asyncTimer = null; try { this._currentTestClass.getCore().tearDown(); isTearDownOk = true; } catch (e) { error = e; isTearDownOk = false; } if (!isTearDownOk) { this._processFailure(error); return; } this._currentAsyncTest.setEnd(); this._currentAsyncTest.setSuccess(true); this._successfulTests++; this._totalTests++; this._totalRuntime += this._currentAsyncTest.getTime(); this._moveToNextTest(); } onFail(error? : Error) : void { clearTimeout(this._asyncTimer); this._asyncTimer = null; try { this._currentTestClass.getCore().tearDown(); } catch (e) { } this._processFailure(error); } } \ No newline at end of file diff --git a/testing/src/references.ts b/testing/src/references.ts index cc98394..3bbc357 100644 --- a/testing/src/references.ts +++ b/testing/src/references.ts @@ -1,4 +1,4 @@ -/// +/// ///