git.iko.soy/purescript-stream
on master help sign in
42 files changed+2154−2409
since splitsnapshots
unifiedsplit
.eslintignore−1 .gitignore+1 CHANGELOG.md+28 README.md+28 bower.json+3−1 ffi/Control/Stream/LinkedList.js−47 ffi/Control/Stream/Stream.js−5 ffi/Control/Stream/combinators/combine.js−97 ffi/Control/Stream/combinators/concat.js−56 ffi/Control/Stream/combinators/drain.js−4 ffi/Control/Stream/combinators/index.js−6 ffi/Control/Stream/combinators/merge.js−74 ffi/Control/Stream/combinators/mergeConcurrently.js−126 ffi/Control/Stream/combinators/switch.js−99 ffi/Control/Stream/disposables/Disposable.js−13 ffi/Control/Stream/disposables/MemoizedDisposable.js−17 ffi/Control/Stream/disposables/SettableDisposable.js−29 ffi/Control/Stream/disposables/disposeSafely.js−3 ffi/Control/Stream/disposables/index.js−12 ffi/Control/Stream/index.js−4 ffi/Control/Stream/runEffects.js−30 ffi/Control/Stream/scheduler/ClockTimer.js−48 ffi/Control/Stream/scheduler/PropagateTask.js−30 ffi/Control/Stream/scheduler/ScheduledTask.js−19 ffi/Control/Stream/scheduler/Scheduler.js−101 ffi/Control/Stream/scheduler/Timeline.js−124 ffi/Control/Stream/scheduler/index.js−16 ffi/Control/Stream/sink/IndexSink.js−24 ffi/Control/Stream/sink/index.js−1 package.json+3−10 rollup.config.js−14 src/Control/Disposable/Disposable.js+32 src/Control/Disposable/Disposable.purs+10 src/Control/Scheduler/Scheduler.js+370 src/Control/Scheduler/Scheduler.purs+32 src/Control/Sink/Sink.purs+9 src/Control/Stream.js−1123 src/Control/Stream.purs+42−275 src/Control/Stream/Stream.js+1244 src/Control/Stream/Stream.purs+340 src/Control/Time.purs+3 test/Main.purs+9
.eslintignore−1
@@ -1,2 +1 @@
11output/
2−src/
.gitignore+1
@@ -6,3 +6,4 @@
66/.psc*
77/.psa*
88src/Main.purs
9+.npm-debug.log*
CHANGELOG.mdnew file+28
@@ -0,0 +1,28 @@
1+<a name="0.2.0"></a>
2+# [0.2.0](https://github.com/TylorS/purescript-stream/compare/v0.1.0...v0.2.0) (2017-03-21)
3+
4+
5+### Bug Fixes
6+
7+* **Stream:** add missing filter import ([d4e1c8e](https://github.com/TylorS/purescript-stream/commit/d4e1c8e))
8+
9+
10+
11+<a name="0.1.0"></a>
12+# [0.1.0](https://github.com/TylorS/purescript-stream/compare/6b75d2f...v0.1.0) (2017-03-16)
13+
14+
15+### Bug Fixes
16+
17+* **Stream:** add missing exports ([13c18b7](https://github.com/TylorS/purescript-stream/commit/13c18b7))
18+
19+
20+### Features
21+
22+* **stream:** implement more helpers and combinators ([8e8b516](https://github.com/TylorS/purescript-stream/commit/8e8b516))
23+* **stream:** more combinators ([a50a246](https://github.com/TylorS/purescript-stream/commit/a50a246))
24+* **stream:** reimplement ([0813a54](https://github.com/TylorS/purescript-stream/commit/0813a54))
25+* **stream:** start of a stream library ([6b75d2f](https://github.com/TylorS/purescript-stream/commit/6b75d2f))
26+
27+
28+
README.mdnew file+28
@@ -0,0 +1,28 @@
1+# Purescript Stream
2+
3+> An ultra-fast reactive stream library for purescript
4+
5+## Let me have it
6+```sh
7+bower install --save purescript-stream
8+```
9+
10+## Basic usage
11+```purescript
12+module Main where
13+
14+import Prelude
15+import Control.Monad.Eff (Eff)
16+import Control.Monad.Eff.Console (CONSOLE, logShow, log)
17+import Control.Stream (STREAM, periodic, constant, scan, tapEvent, tapEnd, drain)
18+import Data.Unit (Unit)
19+
20+main :: Eff (stream :: STREAM, console :: CONSOLE) Unit
21+main = do
22+ periodic 1000.0 -- Stream Unit
23+ # constant 1 -- Stream Int
24+ # scan (+) 0 -- Stream Int
25+ # tapEvent logShow -- Perform side-effects on events
26+ # tapEnd (log "done") -- Perform a side-effect on stream completion
27+ # drain -- activate your stream
28+```
bower.json+3−1
@@ -9,7 +9,9 @@
99 "dependencies": {
1010 "purescript-eff": "^2.0.0",
1111 "purescript-prelude": "^2.5.0",
12− "purescript-refs": "^2.0.0"
12+ "purescript-refs": "^2.0.0",
13+ "purescript-maybe": "^2.1.1",
14+ "purescript-partial": "^1.2.0"
1315 },
1416 "devDependencies": {
1517 "purescript-console": "^2.0.0",
ffi/Control/Stream/LinkedList.jsdeleted−47
@@ -1,47 +0,0 @@
1−export class LinkedList {
2− constructor () {
3− this.head = null
4− this.length = 0
5− }
6−
7− add (x) {
8− if (this.head !== null) {
9− this.head.prev = x
10− x.next = this.head
11− }
12− this.head = x
13− ++this.length
14− }
15−
16− remove (x) { // eslint-disable-line complexity
17− --this.length
18− if (x === this.head) {
19− this.head = this.head.next
20− }
21− if (x.next !== null) {
22− x.next.prev = x.prev
23− x.next = null
24− }
25− if (x.prev !== null) {
26− x.prev.next = x.next
27− x.prev = null
28− }
29− }
30−
31− isEmpty () {
32− return this.length === 0
33− }
34−
35− dispose () {
36− if (this.isEmpty()) return
37−
38− var x = this.head
39− this.head = null
40− this.length = 0
41−
42− while (x !== null) {
43− x.dispose()
44− x = x.next
45− }
46− }
47−}
ffi/Control/Stream/Stream.jsdeleted−5
@@ -1,5 +0,0 @@
1−export class Stream {
2− constructor (source) {
3− this.source = source
4− }
5−}
ffi/Control/Stream/combinators/combine.jsdeleted−97
@@ -1,97 +0,0 @@
1−/** @license MIT License (c) copyright 2010-2016 original author or authors */
2−/** @author Brian Cavalier */
3−/** @author John Hann */
4−
5−import { map, tail } from '@most/prelude'
6−
7−import { IndexSink } from '../sink/IndexSink'
8−import { Stream } from '../Stream'
9−import { disposeAll } from '../disposables'
10−
11−export const combine2 = f => s1 => s2 => combineArray(f, [s1, s2])
12−export const combine3 = f => s1 => s2 => s3 => combineArray(f, [s1, s2, s3])
13−export const combine4 = f => s1 => s2 => s3 => s4 => combineArray(f, [s1, s2, s3, s4])
14−export const combine5 = f => s1 => s2 => s3 => s4 => s5 => combineArray(f, [s1, s2, s3, s4, s5])
15−
16−function combineArray (f, streams) {
17− return new Stream(combineSources(f, streams))
18−}
19−
20−function combineSources (f, streams) {
21− return new Combine(f, map(getSource, streams))
22−}
23−
24−function getSource (stream) {
25− return stream.source
26−}
27−
28−function Combine (f, sources) {
29− this.f = f
30− this.sources = sources
31−}
32−
33−Combine.prototype.run = function (sink) {
34− return scheduler => {
35− var l = this.sources.length
36− var disposables = new Array(l)
37− var sinks = new Array(l)
38−
39− var mergeSink = new CombineSink(disposables, sinks, sink, this.f)
40−
41− for (var indexSink, i = 0; i < l; ++i) {
42− indexSink = sinks[i] = new IndexSink(i, mergeSink)
43− disposables[i] = this.sources[i].run(indexSink)(scheduler)
44− }
45−
46− return disposeAll(disposables)
47− }
48−}
49−
50−function CombineSink (disposables, sinks, sink, f) {
51− this.sink = sink
52− this.disposables = disposables
53− this.sinks = sinks
54− this.f = f
55−
56− var l = sinks.length
57− this.awaiting = l
58− this.values = new Array(l)
59− this.hasValue = new Array(l)
60−
61− for (var i = 0; i < l; ++i) {
62− this.hasValue[i] = false
63− }
64−
65− this.activeCount = sinks.length
66−}
67−
68−CombineSink.prototype.event = function (t) {
69− return indexedValue => {
70− var i = indexedValue.index
71− var awaiting = this._updateReady(i)
72−
73− this.values[i] = indexedValue.value
74− if (awaiting === 0) {
75− const value = tail(this.values).reduce((f, x) => f(x), this.f(this.values[0]))
76− this.sink.event(t)(value)
77− }
78− }
79−}
80−
81−CombineSink.prototype._updateReady = function (index) {
82− if (this.awaiting > 0) {
83− if (!this.hasValue[index]) {
84− this.hasValue[index] = true
85− this.awaiting -= 1
86− }
87− }
88− return this.awaiting
89−}
90−
91−CombineSink.prototype.end = function (t, indexedValue) {
92− this.disposables[indexedValue.index].dispose()
93−
94− if (--this.activeCount === 0) {
95− this.sink.end(t)
96− }
97−}
ffi/Control/Stream/combinators/concat.jsdeleted−56
@@ -1,56 +0,0 @@
1−import { MemoizedDisposable } from '../disposables/MemoizedDisposable'
2−import { Stream } from '../Stream'
3−
4−export const concat = s1 => s2 => continueWith(() => s2)(s1)
5−
6−export const continueWith = f => stream => new Stream(new ContinueWith(f, stream.source))
7−
8−function ContinueWith (f, source) {
9− this.f = f
10− this.source = source
11−}
12−
13−ContinueWith.prototype.run = function (sink) {
14− return scheduler => {
15− return new ContinueWithSink(this.f, this.source, sink, scheduler)
16− }
17−}
18−
19−function ContinueWithSink (f, source, sink, scheduler) {
20− this.f = f
21− this.sink = sink
22− this.scheduler = scheduler
23− this.active = true
24− this.disposable = new MemoizedDisposable(source.run(this)(scheduler))
25−}
26−
27−ContinueWithSink.prototype.event = function (t) {
28− return x => {
29− if (!this.active) {
30− return
31− }
32− this.sink.event(t)(x)
33− }
34−}
35−
36−ContinueWithSink.prototype.end = function (t, x) {
37− if (!this.active) {
38− return
39− }
40−
41− this.disposable.dispose()
42− this._startNext(t, x, this.sink)
43−}
44−
45−ContinueWithSink.prototype._startNext = function (t, x, sink) {
46− this._continue(this.f, x, sink)
47−}
48−
49−ContinueWithSink.prototype._continue = function (f, x, sink) {
50− return f(x).source.run(sink)(this.scheduler)
51−}
52−
53−ContinueWithSink.prototype.dispose = function () {
54− this.active = false
55− return this.disposable.dispose()
56−}
ffi/Control/Stream/combinators/drain.jsdeleted−4
@@ -1,4 +0,0 @@
1−import { defaultScheduler } from '../scheduler'
2−import { runEffects } from '../runEffects'
3−
4−export const drain = stream => () => runEffects(stream, defaultScheduler)
ffi/Control/Stream/combinators/index.jsdeleted−6
@@ -1,6 +0,0 @@
1−export * from './drain'
2−export * from './mergeConcurrently'
3−export * from './combine'
4−export * from './merge'
5−export * from './concat'
6−export * from './switch'
ffi/Control/Stream/combinators/merge.jsdeleted−74
@@ -1,74 +0,0 @@
1−/** @license MIT License (c) copyright 2010-2016 original author or authors */
2−/** @author Brian Cavalier */
3−/** @author John Hann */
4−
5−import { IndexSink } from '../sink/IndexSink'
6−import { Stream } from '../Stream'
7−import { disposeAll } from '../disposables'
8−import { reduce } from '@most/prelude'
9−
10−/**
11− * @param {Array} streams array of stream to merge
12− * @returns {Stream} stream containing events from all input observables
13− * in time order. If two events are simultaneous they will be merged in
14− * arbitrary order.
15− */
16−export function merge (streams) {
17− return new Stream(mergeSources(streams))
18−}
19−
20−/**
21− * This implements fusion/flattening for merge. It will
22− * fuse adjacent merge operations. For example:
23− * - a.merge(b).merge(c) effectively becomes merge(a, b, c)
24− * - merge(a, merge(b, c)) effectively becomes merge(a, b, c)
25− * It does this by concatenating the sources arrays of
26− * any nested Merge sources, in effect "flattening" nested
27− * merge operations into a single merge.
28− */
29−function mergeSources (streams) {
30− return new Merge(reduce(appendSources, [], streams))
31−}
32−
33−function appendSources (sources, stream) {
34− var source = stream.source
35− return source instanceof Merge
36− ? sources.concat(source.sources)
37− : sources.concat(source)
38−}
39−
40−function Merge (sources) {
41− this.sources = sources
42−}
43−
44−Merge.prototype.run = function (sink, scheduler) {
45− var l = this.sources.length
46− var disposables = new Array(l)
47− var sinks = new Array(l)
48−
49− var mergeSink = new MergeSink(disposables, sinks, sink)
50−
51− for (var indexSink, i = 0; i < l; ++i) {
52− indexSink = sinks[i] = new IndexSink(i, mergeSink)
53− disposables[i] = this.sources[i].run(indexSink, scheduler)
54− }
55−
56− return disposeAll(disposables)
57−}
58−
59−function MergeSink (disposables, sinks, sink) {
60− this.sink = sink
61− this.disposables = disposables
62− this.activeCount = sinks.length
63−}
64−
65−MergeSink.prototype.event = function (t, indexValue) {
66− this.sink.event(t, indexValue.value)
67−}
68−
69−MergeSink.prototype.end = function (t, indexedValue) {
70− dispose.tryDispose(t, this.disposables[indexedValue.index], this.sink)
71− if (--this.activeCount === 0) {
72− this.sink.end(t, indexedValue.value)
73− }
74−}
ffi/Control/Stream/combinators/mergeConcurrently.jsdeleted−126
@@ -1,126 +0,0 @@
1−/** @license MIT License (c) copyright 2010-2016 original author or authors */
2−/** @author Brian Cavalier */
3−/** @author John Hann */
4−
5−import { curry2, curry3, id as identity } from '@most/prelude'
6−
7−import { LinkedList } from '../LinkedList'
8−import { MemoizedDisposable } from '../disposables/MemoizedDisposable'
9−import { Stream } from '../Stream'
10−
11−export const flatMap =
12− curry2((stream, f) => mergeMapConcurrently(f, Infinity, stream))
13−
14−export const mergeConcurrently = curry2((concurrency, stream) =>
15− mergeMapConcurrently(identity, concurrency, stream))
16−
17−export const join =
18− mergeConcurrently(Infinity)
19−
20−export const mergeMapConcurrently = curry3((f, concurrency, stream) =>
21− new Stream(new MergeConcurrently(f, concurrency, stream.source)))
22−
23−class MergeConcurrently {
24− constructor (f, concurrency, source) {
25− this.f = f
26− this.concurrency = concurrency
27− this.source = source
28− }
29−
30− run (sink) {
31− return scheduler => new Outer(this.f, this.concurrency, this.source, sink, scheduler)
32− }
33−}
34−
35−class Outer {
36− constructor (f, concurrency, source, sink, scheduler) {
37− this.f = f
38− this.concurrency = concurrency
39− this.sink = sink
40− this.scheduler = scheduler
41− this.pending = []
42− this.current = new LinkedList()
43− this.disposable = new MemoizedDisposable(source.run(this)(scheduler))
44− this.active = true
45− }
46−
47− event (t) {
48− return x => this._addInner(t, x)
49− }
50−
51− _addInner (t, x) {
52− if (this.current.length < this.concurrency) {
53− this._startInner(t, x)
54− } else {
55− this.pending.push(x)
56− }
57− }
58−
59− _startInner (t, x) {
60− try {
61− this._initInner(t, x)
62− } catch (e) {
63− this.error(t, e)
64− }
65− }
66−
67− _initInner (t, x) {
68− const innerSink = new Inner(t, this, this.sink)
69− innerSink.disposable = mapAndRun(this.f, x, innerSink, this.scheduler)
70− this.current.add(innerSink)
71− }
72−
73− end (t) {
74− this.active = false
75− this.disposable.dispose()
76− this._checkEnd(t)
77− }
78−
79− dispose () {
80− this.active = false
81− this.pending.length = 0
82− this.disposable.dispose()
83− this.current.dispose()
84− }
85−
86− _endInner (t, inner) {
87− this.current.remove(inner)
88− inner.dispose()
89−
90− if (this.pending.length === 0) {
91− this._checkEnd(t)
92− } else {
93− this._startInner(t, this.pending.shift())
94− }
95− }
96−
97− _checkEnd (t) {
98− if (!this.active && this.current.isEmpty()) {
99− this.sink.end(t)
100− }
101− }
102−}
103−
104−const mapAndRun = (f, x, sink, scheduler) => f(x).source.run(sink)(scheduler)
105−
106−class Inner {
107− constructor (time, outer, sink) {
108− this.prev = this.next = null
109− this.time = time
110− this.outer = outer
111− this.sink = sink
112− this.disposable = void 0
113− }
114−
115− event (t) {
116− return x => this.sink.event(Math.max(t, this.time))(x)
117− }
118−
119− end (t) {
120− this.outer._endInner(Math.max(t, this.time), this)
121− }
122−
123− dispose () {
124− return this.disposable.dispose()
125− }
126−}
ffi/Control/Stream/combinators/switch.jsdeleted−99
@@ -1,99 +0,0 @@
1−import { disposeAll, emptyDisposable } from '../disposables'
2−
3−import { Stream } from '../Stream'
4−
5−/**
6− * Given a stream of streams, return a new stream that adopts the behavior
7− * of the most recent inner stream.
8− * @param {Stream} stream of streams on which to switch
9− * @returns {Stream} switching stream
10− */
11−function switchLatest (stream) {
12− return new Stream(new Switch(stream.source))
13−}
14−
15−export { switchLatest as switch }
16−
17−function Switch (source) {
18− this.source = source
19−}
20−
21−Switch.prototype.run = function (sink) {
22− return scheduler => {
23− const switchSink = new SwitchSink(sink, scheduler)
24− return disposeAll([switchSink, this.source.run(switchSink)(scheduler)])
25− }
26−}
27−
28−function SwitchSink (sink, scheduler) {
29− this.sink = sink
30− this.scheduler = scheduler
31− this.current = null
32− this.ended = false
33−}
34−
35−SwitchSink.prototype.event = function (t) {
36− return stream => {
37− this._disposeCurrent(t) // TODO: capture the result of this dispose
38− this.current = new Segment(t, Infinity, this, this.sink)
39− this.current.disposable = stream.source.run(this.current)(this.scheduler)
40− }
41−}
42−
43−SwitchSink.prototype.end = function (t, x) {
44− this.ended = true
45− this._checkEnd(t, x)
46−}
47−
48−SwitchSink.prototype.dispose = function () {
49− return this._disposeCurrent(this.scheduler.now())
50−}
51−
52−SwitchSink.prototype._disposeCurrent = function (t) {
53− if (this.current !== null) {
54− return this.current._dispose(t)
55− }
56−}
57−
58−SwitchSink.prototype._disposeInner = function (t, inner) {
59− inner._dispose(t) // TODO: capture the result of this dispose
60− if (inner === this.current) {
61− this.current = null
62− }
63−}
64−
65−SwitchSink.prototype._checkEnd = function (t, x) {
66− if (this.ended && this.current === null) {
67− this.sink.end(t, x)
68− }
69−}
70−
71−SwitchSink.prototype._endInner = function (t, x, inner) {
72− this._disposeInner(t, inner)
73− this._checkEnd(t, x)
74−}
75−
76−function Segment (min, max, outer, sink) {
77− this.min = min
78− this.max = max
79− this.outer = outer
80− this.sink = sink
81− this.disposable = emptyDisposable
82−}
83−
84−Segment.prototype.event = function (t) {
85− return x => {
86− if (t < this.max) {
87− this.sink.event(Math.max(t, this.min))(x)
88− }
89− }
90−}
91−
92−Segment.prototype.end = function (t, x) {
93− this.outer._endInner(Math.max(t, this.min), x, this)
94−}
95−
96−Segment.prototype._dispose = function (t) {
97− this.max = t
98− this.disposable.dispose()
99−}
ffi/Control/Stream/disposables/Disposable.jsdeleted−13
@@ -1,13 +0,0 @@
1−export class Disposable {
2− /**
3− * Create a new Disposable which will dispose its underlying resource.
4− * @param {function} dispose function
5− * @param {*?} data any data to be passed to disposer function
6− */
7− constructor (dispose, data) {
8− this._dispose = dispose
9− this._data = data
10−
11− this.dispose = () => dispose(data)
12− }
13−}
ffi/Control/Stream/disposables/MemoizedDisposable.jsdeleted−17
@@ -1,17 +0,0 @@
1−export class MemoizedDisposable {
2− constructor (disposable) {
3− this.disposed = false
4− this.value = undefined
5− this.disposable = disposable
6− }
7−
8− dispose () {
9− if (!this.disposed) {
10− this.disposed = true
11− this.value = this.disposable.dispose()
12− this.disposable = undefined
13− }
14−
15− return this.value
16− }
17−}
ffi/Control/Stream/disposables/SettableDisposable.jsdeleted−29
@@ -1,29 +0,0 @@
1−export class SettableDisposable {
2− constructor () {
3− this.disposable = void 0
4− this.disposed = false
5− this.result = void 0
6− }
7−
8− setDisposable (disposable) {
9− this.disposable = disposable
10−
11− if (this.disposed) {
12− this.result = disposable.dispose()
13− }
14− }
15−
16− dispose () {
17− if (this.disposed) {
18− return this.result
19− }
20−
21− this.disposed = true
22−
23− if (this.disposable !== void 0) {
24− this.result = this.disposable.dispose()
25− }
26−
27− return this.result
28− }
29−}
ffi/Control/Stream/disposables/disposeSafely.jsdeleted−3
@@ -1,3 +0,0 @@
1−export function disposeSafely (disposable) {
2− disposable.dispose()
3−}
ffi/Control/Stream/disposables/index.jsdeleted−12
@@ -1,12 +0,0 @@
1−import { curry2, id, map } from '@most/prelude'
2−
3−import { Disposable } from './Disposable'
4−import { MemoizedDisposable } from './MemoizedDisposable'
5−import { disposeSafely } from './disposeSafely'
6−
7−export const createDisposable = curry2((dispose, data) => new MemoizedDisposable(new Disposable(dispose, data)))
8−
9−export const emptyDisposable = new Disposable(id, undefined)
10−
11−export const disposeAll = disposables =>
12− createDisposable(curry2(map)(disposeSafely), disposables)
ffi/Control/Stream/index.jsdeleted−4
@@ -1,4 +0,0 @@
1−/* @flow */
2−export * from './disposables'
3−export * from './scheduler'
4−export * from './combinators'
ffi/Control/Stream/runEffects.jsdeleted−30
@@ -1,30 +0,0 @@
1−import { SettableDisposable } from './disposables/SettableDisposable'
2−
3−export function runEffects (stream, scheduler) {
4− return runSourceEffects(stream.source, scheduler)
5−}
6−
7−const runSourceEffects = (source, scheduler) => runSource(source, scheduler)
8−
9−function runSource (source, scheduler) {
10− const disposable = new SettableDisposable()
11− const observer = new RunEffectsSink(disposable)
12−
13− disposable.setDisposable(source.run(observer)(scheduler))
14−
15− return {}
16−}
17−
18−var RunEffectsSink = function RunEffectsSink (disposable) {
19− this._disposable = disposable
20− this.active = true
21−}
22−
23−RunEffectsSink.prototype.event = function event (t) {
24− return function (x) {}
25−}
26−
27−RunEffectsSink.prototype.end = function end (t) {
28− this.active = false
29− Promise.resolve(this._disposable).then(d => d.dispose())
30−}
ffi/Control/Stream/scheduler/ClockTimer.jsdeleted−48
@@ -1,48 +0,0 @@
1−/** @license MIT License (c) copyright 2010-2016 original author or authors */
2−/** @author Brian Cavalier */
3−/** @author John Hann */
4−
5−/*global setTimeout, clearTimeout*/
6−
7−export function defer (task) {
8− return Promise.resolve(task).then(runTask)
9−}
10−
11−export function runTask (task) {
12− return task.run()
13−}
14−
15−export class ClockTimer {
16− constructor () {
17− this.now = Date.now
18− }
19−
20− setTimer (f, dt) {
21− return dt <= 0 ? runAsap(f) : setTimeout(f, dt)
22− }
23−
24− clearTimer (t) {
25− return t instanceof Asap ? t.cancel() : clearTimeout(t)
26− }
27−}
28−
29−class Asap {
30− constructor (f) {
31− this.f = f
32− this.active = true
33− }
34−
35− run () {
36− return this.active && this.f()
37− }
38−
39− cancel () {
40− this.active = false
41− }
42−}
43−
44−function runAsap (f) {
45− const task = new Asap(f)
46− defer(task)
47− return task
48−}
ffi/Control/Stream/scheduler/PropagateTask.jsdeleted−30
@@ -1,30 +0,0 @@
1−import { curry2, curry3 } from '@most/prelude'
2−
3−const propagateTask =
4− curry3((run, value, sink) => new PropagateTask(run, value, sink))
5−
6−export const eventTask =
7− curry2((value, sink) => propagateTask(runEvent, value, sink))
8−
9−export const endTask = sink => propagateTask(runEnd, void 0, sink)
10−
11−class PropagateTask {
12− constructor (run, value, sink) {
13− let active = true
14−
15− this.dispose = () => { active = false }
16− this.run = t => {
17− if (!active) return
18−
19− run(t, value, sink)
20− }
21− }
22−}
23−
24−function runEvent (time, value, sink) {
25− sink.event(time)(value)
26−}
27−
28−function runEnd (time, value, sink) {
29− sink.end(time, value)
30−}
ffi/Control/Stream/scheduler/ScheduledTask.jsdeleted−19
@@ -1,19 +0,0 @@
1−/* @flow */
2−export class ScheduledTask {
3− constructor (delay, period, task, scheduler) {
4− this.time = delay
5− this.period = period
6− this.task = task
7− this.scheduler = scheduler
8− this.active = true
9− }
10−
11− run () {
12− this.task.run(this.time)
13− }
14−
15− dispose () {
16− this.scheduler.cancel(this)
17− this.task.dispose()
18− }
19−}
ffi/Control/Stream/scheduler/Scheduler.jsdeleted−101
@@ -1,101 +0,0 @@
1−/* @flow */
2−import { ScheduledTask } from './ScheduledTask'
3−
4−function runTask (task) {
5− try {
6− return task.run()
7− } catch (e) {
8− console.error(e)
9− }
10−}
11−
12−export class Scheduler {
13− constructor (timer, timeline) {
14− this.timer = timer
15− this.timeline = timeline
16−
17− this._timer = null
18− this._nextArrival = Infinity
19−
20− this._runReadyTasksBound = () => this._runReadyTasks(this.now())
21− }
22−
23− now () {
24− return this.timer.now()
25− }
26−
27− asap (task) {
28− return this.schedule(0)(-1)(task)
29− }
30−
31− delay (delay) {
32− return task => this.schedule(delay)(-1)(task)
33− }
34−
35− periodic (period) {
36− return task => this.schedule(0)(period)(task)
37− }
38−
39− schedule (delay) {
40− return period => task => {
41− const now = this.now()
42− const st = new ScheduledTask(now + Math.max(0, delay), period, task, this)
43−
44− this.timeline.add(st)
45− this._scheduleNextRun(now)
46− return st
47− }
48− }
49−
50− cancel (task) {
51− task.active = false
52− if (this.timeline.remove(task)) {
53− this._reschedule()
54− }
55− }
56−
57− cancelAll (f) {
58− this.timeline.removeAll(f)
59− this._reschedule()
60− }
61−
62− _reschedule () {
63− if (this.timeline.isEmpty()) {
64− this._unschedule()
65− } else {
66− this._scheduleNextRun(this.now())
67− }
68− }
69−
70− _unschedule () {
71− this.timer.clearTimer(this._timer)
72− this._timer = null
73− }
74−
75− _scheduleNextRun (now) { // eslint-disable-line complexity
76− if (this.timeline.isEmpty()) {
77− return
78− }
79−
80− const nextArrival = this.timeline.nextArrival()
81−
82− if (this._timer === null) {
83− this._scheduleNextArrival(nextArrival, now)
84− } else if (nextArrival < this._nextArrival) {
85− this._unschedule()
86− this._scheduleNextArrival(nextArrival, now)
87− }
88− }
89−
90− _scheduleNextArrival (nextArrival, now) {
91− this._nextArrival = nextArrival
92− const delay = Math.max(0, nextArrival - now)
93− this._timer = this.timer.setTimer(this._runReadyTasksBound, delay)
94− }
95−
96− _runReadyTasks (now) {
97− this._timer = null
98− this.timeline.runTasks(now, runTask)
99− this._scheduleNextRun(this.now())
100− }
101−}
ffi/Control/Stream/scheduler/Timeline.jsdeleted−124
@@ -1,124 +0,0 @@
1−/** @license MIT License (c) copyright 2010-2016 original author or authors */
2−/** @author Brian Cavalier */
3−/** @author John Hann */
4−
5−import * as base from '@most/prelude'
6−
7−export class Timeline {
8− constructor () {
9− this.tasks = []
10− }
11−
12− nextArrival () {
13− return this.isEmpty() ? Infinity : this.tasks[0].time
14− }
15−
16− isEmpty () {
17− return this.tasks.length === 0
18− }
19−
20− add (st) {
21− insertByTime(st, this.tasks)
22− }
23−
24− remove (st) {
25− const i = binarySearch(st.time, this.tasks)
26−
27− if (i >= 0 && i < this.tasks.length) {
28− const at = base.findIndex(st, this.tasks[i].events)
29− if (at >= 0) {
30− this.tasks[i].events.splice(at, 1)
31− return true
32− }
33− }
34−
35− return false
36− }
37−
38− removeAll (f) {
39− for (let i = 0; i < this.tasks.length; ++i) {
40− removeAllFrom(f, this.tasks[i])
41− }
42− }
43−
44− runTasks (t, runTask) {
45− const tasks = this.tasks
46− const l = tasks.length
47− let i = 0
48−
49− while (i < l && tasks[i].time <= t) {
50− ++i
51− }
52−
53− this.tasks = tasks.slice(i)
54−
55− // Run all ready tasks
56− for (let j = 0; j < i; ++j) {
57− this.tasks = runReadyTasks(runTask, tasks[j].events, this.tasks)
58− }
59− }
60−}
61−
62−function runReadyTasks (runTask, events, tasks) { // eslint-disable-line complexity
63− for (let i = 0; i < events.length; ++i) {
64− const task = events[i]
65−
66− if (task.active) {
67− runTask(task)
68−
69− // Reschedule periodic repeating tasks
70− // Check active again, since a task may have canceled itself
71− if (task.period >= 0 && task.active) {
72− task.time = task.time + task.period
73− insertByTime(task, tasks)
74− }
75− }
76− }
77−
78− return tasks
79−}
80−
81−function insertByTime (task, timeslots) { // eslint-disable-line complexity
82− const l = timeslots.length
83−
84− if (l === 0) {
85− timeslots.push(newTimeslot(task.time, [task]))
86− return
87− }
88−
89− const i = binarySearch(task.time, timeslots)
90−
91− if (i >= l) {
92− timeslots.push(newTimeslot(task.time, [task]))
93− } else if (task.time === timeslots[i].time) {
94− timeslots[i].events.push(task)
95− } else {
96− timeslots.splice(i, 0, newTimeslot(task.time, [task]))
97− }
98−}
99−
100−function removeAllFrom (f, timeslot) {
101− timeslot.events = base.removeAll(f, timeslot.events)
102−}
103−
104−function binarySearch (t, sortedArray) { // eslint-disable-line complexity
105− let lo = 0
106− let hi = sortedArray.length
107− let mid, y
108−
109− while (lo < hi) {
110− mid = Math.floor((lo + hi) / 2)
111− y = sortedArray[mid]
112−
113− if (t === y.time) {
114− return mid
115− } else if (t < y.time) {
116− hi = mid
117− } else {
118− lo = mid + 1
119− }
120− }
121− return hi
122−}
123−
124−const newTimeslot = (t, events) => ({ time: t, events: events })
ffi/Control/Stream/scheduler/index.jsdeleted−16
@@ -1,16 +0,0 @@
1−import { ClockTimer } from './ClockTimer'
2−import { Scheduler } from './Scheduler'
3−import { Timeline } from './Timeline'
4−import { curry2 } from '@most/prelude'
5−
6−export { endTask, eventTask } from './PropagateTask'
7−
8−export const defaultScheduler = new Scheduler(new ClockTimer(), new Timeline())
9−
10−export const scheduleTasks = curry2((tasks, scheduler) => {
11− const scheduledTasks = tasks.map(task => scheduler.asap(task))
12−
13− return {
14− dispose: () => scheduledTasks.forEach(task => task.dispose())
15− }
16−})
ffi/Control/Stream/sink/IndexSink.jsdeleted−24
@@ -1,24 +0,0 @@
1−export class IndexSink {
2− constructor (i, sink) {
3− this.sink = sink
4− this.index = i
5− this.active = true
6− this.value = void 0
7− }
8−
9− event (t) {
10− return x => {
11− if (!this.active) return
12−
13− this.value = x
14− this.sink.event(t)(this)
15− }
16− }
17−
18− end (t) {
19− if (!this.active) return
20−
21− this.active = false
22− this.sink.end(t, { index: this.index })
23− }
24−}
ffi/Control/Stream/sink/index.jsdeleted−1
@@ -1 +0,0 @@
1−export * from './IndexSink'
package.json+3−10
@@ -1,11 +1,11 @@
11{
2− "name": "purescript-tempest",
3− "version": "0.0.0",
2+ "name": "purescript-stream",
3+ "version": "0.2.0",
44 "description": "",
55 "main": "index.js",
66 "scripts": {
77 "start": "yarn build && pulp run",
8− "build": "rollup -c && pulp build",
8+ "build": "pulp build",
99 "changelog": "conventional-changelog -i CHANGELOG.md -s -r 0 -p angular",
1010 "clean": "rimraf lib lib.es2015",
1111 "commit": "git-cz",
@@ -32,14 +32,7 @@
3232 "husky": "^0.13.2",
3333 "pulp": "^10.0.4",
3434 "purescript": "^0.10.7",
35− "rollup": "^0.41.4",
36− "rollup-plugin-buble": "^0.15.0",
37− "rollup-plugin-flow": "^1.1.1",
38− "rollup-plugin-node-resolve": "^2.0.0",
3935 "uglify-js": "^2.8.11",
4036 "validate-commit-msg": "^2.11.2"
41− },
42− "dependencies": {
43− "@most/prelude": "^1.5.0"
4437 }
4538}
rollup.config.jsdeleted−14
@@ -1,14 +0,0 @@
1−import buble from 'rollup-plugin-buble'
2−import flow from 'rollup-plugin-flow'
3−import resolve from 'rollup-plugin-node-resolve'
4−
5−export default {
6− entry: 'ffi/Control/Stream/index.js',
7− dest: 'src/Control/Stream.js',
8− format: 'cjs',
9− plugins: [
10− flow(),
11− buble(),
12− resolve({ module: true, jsnext: true })
13− ]
14−}
src/Control/Disposable/Disposable.jsnew file+32
@@ -0,0 +1,32 @@
1+exports.emptyDisposable = { dispose: function () { return {} } }
2+
3+exports.disposeAll = function (disposables) {
4+ var disposed = false
5+
6+ function dispose () {
7+ if (disposed) return
8+
9+ disposables.forEach(function (disposable) {
10+ disposable.dispose()
11+ })
12+
13+ disposed = true
14+ }
15+
16+ return { dispose: dispose }
17+}
18+
19+exports.lazyDisposable = function (f) {
20+ var disposed = false
21+
22+ function dispose () {
23+ if (disposed) return
24+ var disposable = f()
25+
26+ disposable.dispose()
27+
28+ disposed = true
29+ }
30+
31+ return { dispose: dispose }
32+}
src/Control/Disposable/Disposable.pursnew file+10
@@ -0,0 +1,10 @@
1+module Control.Stream.Disposable where
2+
3+import Control.Monad.Eff (Pure)
4+import Data.Unit (Unit)
5+
6+type Disposable = { dispose :: Pure Unit }
7+
8+foreign import emptyDisposable :: Disposable
9+foreign import disposeAll :: Array Disposable -> Disposable
10+foreign import lazyDisposable :: (Unit -> Disposable) -> Disposable
src/Control/Scheduler/Scheduler.jsnew file+370
@@ -0,0 +1,370 @@
1+exports.scheduleTasks = function (f) {
2+ return function (tasks) {
3+ var scheduledTasks = tasks.map(f.bind(scheduler))
4+
5+ function dispose () {
6+ scheduledTasks.forEach(function (task) {
7+ task.dispose()
8+ })
9+ }
10+
11+ return { dispose: dispose }
12+ }
13+}
14+
15+exports.eventTask = function (sink) {
16+ return function (value) {
17+ return new PropagateTask(runEvent, value, sink)
18+ }
19+}
20+
21+exports.endTask = function (sink) {
22+ return new PropagateTask(runEnd, void 0, sink)
23+}
24+
25+function PropagateTask (run, value, sink) {
26+ this.active = true
27+ this._run = run
28+ this.value = value
29+ this.sink = sink
30+}
31+
32+PropagateTask.prototype.dispose = function () {
33+ this.active = false
34+}
35+
36+PropagateTask.prototype.run = function (time) {
37+ if (!this.active) return
38+
39+ this._run(time, this.value, this.sink)
40+}
41+
42+function runEvent (time, value, sink) {
43+ sink.event(time)(value)
44+}
45+
46+function runEnd (time, value, sink) {
47+ sink.end(time)
48+}
49+
50+function defer (task) {
51+ return Promise.resolve(task).then(runTask)
52+}
53+
54+function runTask (task) {
55+ return task.run()
56+}
57+
58+var ClockTimer = function ClockTimer () {
59+ this.now = Date.now
60+}
61+
62+ClockTimer.prototype.setTimer = function setTimer (f, dt) {
63+ return dt <= 0 ? runAsap(f) : setTimeout(f, dt)
64+}
65+
66+ClockTimer.prototype.clearTimer = function clearTimer (t) {
67+ return t instanceof Asap ? t.cancel() : clearTimeout(t)
68+}
69+
70+var Asap = function Asap (f) {
71+ this.f = f
72+ this.active = true
73+}
74+
75+Asap.prototype.run = function run () {
76+ return this.active && this.f()
77+}
78+
79+Asap.prototype.cancel = function cancel () {
80+ this.active = false
81+}
82+
83+function runAsap (f) {
84+ var task = new Asap(f)
85+ defer(task)
86+ return task
87+}
88+
89+var ScheduledTask = function ScheduledTask (delay, period, task, scheduler) {
90+ this.time = delay
91+ this.period = period
92+ this.task = task
93+ this.scheduler = scheduler
94+ this.active = true
95+}
96+
97+ScheduledTask.prototype.run = function run () {
98+ this.task.run(this.time)
99+}
100+
101+ScheduledTask.prototype.dispose = function dispose () {
102+ this.scheduler.cancel(this)
103+ this.task.dispose()
104+}
105+
106+function runTask$1 (task) {
107+ try {
108+ return task.run()
109+ } catch (e) {
110+ console.error(e)
111+ }
112+}
113+
114+var Scheduler = function Scheduler (timer, timeline) {
115+ var this$1 = this
116+
117+ this.timer = timer
118+ this.timeline = timeline
119+
120+ this._timer = null
121+ this._nextArrival = Infinity
122+
123+ this._runReadyTasksBound = function () { return this$1._runReadyTasks(this$1.now()) }
124+}
125+
126+Scheduler.prototype.now = function now () {
127+ return this.timer.now()
128+}
129+
130+Scheduler.prototype.asap = function asap (task) {
131+ return this.schedule(0)(-1)(task)
132+}
133+
134+Scheduler.prototype.delay = function delay (delay$1) {
135+ var this$1 = this
136+
137+ return function (task) { return this$1.schedule(delay$1)(-1)(task) }
138+}
139+
140+Scheduler.prototype.periodic = function periodic (period) {
141+ var this$1 = this
142+
143+ return function (task) { return this$1.schedule(0)(period)(task) }
144+}
145+
146+Scheduler.prototype.schedule = function schedule (delay) {
147+ var this$1 = this
148+
149+ return function (period) {
150+ return function (task) {
151+ var now = this$1.now()
152+ var st = new ScheduledTask(now + Math.max(0, delay), period, task, this$1)
153+
154+ st.run = st.run.bind(st)
155+ st.dispose = st.dispose.bind(st)
156+
157+ this$1.timeline.add(st)
158+ this$1._scheduleNextRun(now)
159+ return st
160+ }
161+ }
162+}
163+
164+Scheduler.prototype.cancel = function cancel (task) {
165+ task.active = false
166+ if (this.timeline.remove(task)) {
167+ this._reschedule()
168+ }
169+}
170+
171+Scheduler.prototype.cancelAll = function cancelAll (f) {
172+ this.timeline.removeAll(f)
173+ this._reschedule()
174+}
175+
176+Scheduler.prototype._reschedule = function _reschedule () {
177+ if (this.timeline.isEmpty()) {
178+ this._unschedule()
179+ } else {
180+ this._scheduleNextRun(this.now())
181+ }
182+}
183+
184+Scheduler.prototype._unschedule = function _unschedule () {
185+ this.timer.clearTimer(this._timer)
186+ this._timer = null
187+}
188+
189+Scheduler.prototype._scheduleNextRun = function _scheduleNextRun (now) { // eslint-disable-line complexity
190+ if (this.timeline.isEmpty()) {
191+ return
192+ }
193+
194+ var nextArrival = this.timeline.nextArrival()
195+
196+ if (this._timer === null) {
197+ this._scheduleNextArrival(nextArrival, now)
198+ } else if (nextArrival < this._nextArrival) {
199+ this._unschedule()
200+ this._scheduleNextArrival(nextArrival, now)
201+ }
202+}
203+
204+Scheduler.prototype._scheduleNextArrival = function _scheduleNextArrival (nextArrival, now) {
205+ this._nextArrival = nextArrival
206+ var delay = Math.max(0, nextArrival - now)
207+ this._timer = this.timer.setTimer(this._runReadyTasksBound, delay)
208+}
209+
210+Scheduler.prototype._runReadyTasks = function _runReadyTasks (now) {
211+ this._timer = null
212+ this.timeline.runTasks(now, runTask$1)
213+ this._scheduleNextRun(this.now())
214+}
215+
216+/** @license MIT License (c) copyright 2010-2016 original author or authors */
217+/** @author Brian Cavalier */
218+/** @author John Hann */
219+
220+var Timeline = function Timeline () {
221+ this.tasks = []
222+}
223+
224+Timeline.prototype.nextArrival = function nextArrival () {
225+ return this.isEmpty() ? Infinity : this.tasks[0].time
226+}
227+
228+Timeline.prototype.isEmpty = function isEmpty () {
229+ return this.tasks.length === 0
230+}
231+
232+Timeline.prototype.add = function add (st) {
233+ insertByTime(st, this.tasks)
234+}
235+
236+Timeline.prototype.remove = function remove$$1 (st) {
237+ var i = binarySearch(st.time, this.tasks)
238+
239+ if (i >= 0 && i < this.tasks.length) {
240+ var at = findIndex(st, this.tasks[i].events)
241+ if (at >= 0) {
242+ this.tasks[i].events.splice(at, 1)
243+ return true
244+ }
245+ }
246+
247+ return false
248+}
249+
250+Timeline.prototype.removeAll = function removeAll$$1 (f) {
251+ var this$1 = this
252+
253+ for (var i = 0; i < this.tasks.length; ++i) {
254+ removeAllFrom(f, this$1.tasks[i])
255+ }
256+}
257+
258+Timeline.prototype.runTasks = function runTasks (t, runTask) {
259+ var this$1 = this
260+
261+ var tasks = this.tasks
262+ var l = tasks.length
263+ var i = 0
264+
265+ while (i < l && tasks[i].time <= t) {
266+ ++i
267+ }
268+
269+ this.tasks = tasks.slice(i)
270+
271+ // Run all ready tasks
272+ for (var j = 0; j < i; ++j) {
273+ this$1.tasks = runReadyTasks(runTask, tasks[j].events, this$1.tasks)
274+ }
275+}
276+
277+function runReadyTasks (runTask, events, tasks) { // eslint-disable-line complexity
278+ for (var i = 0; i < events.length; ++i) {
279+ var task = events[i]
280+
281+ if (task.active) {
282+ runTask(task)
283+
284+ // Reschedule periodic repeating tasks
285+ // Check active again, since a task may have canceled itself
286+ if (task.period >= 0 && task.active) {
287+ task.time = task.time + task.period
288+ insertByTime(task, tasks)
289+ }
290+ }
291+ }
292+
293+ return tasks
294+}
295+
296+function insertByTime (task, timeslots) { // eslint-disable-line complexity
297+ var l = timeslots.length
298+
299+ if (l === 0) {
300+ timeslots.push(newTimeslot(task.time, [task]))
301+ return
302+ }
303+
304+ var i = binarySearch(task.time, timeslots)
305+
306+ if (i >= l) {
307+ timeslots.push(newTimeslot(task.time, [task]))
308+ } else if (task.time === timeslots[i].time) {
309+ timeslots[i].events.push(task)
310+ } else {
311+ timeslots.splice(i, 0, newTimeslot(task.time, [task]))
312+ }
313+}
314+
315+function removeAllFrom (f, timeslot) {
316+ timeslot.events = removeAll(f, timeslot.events)
317+}
318+
319+function binarySearch (t, sortedArray) { // eslint-disable-line complexity
320+ var lo = 0
321+ var hi = sortedArray.length
322+ var mid, y
323+
324+ while (lo < hi) {
325+ mid = Math.floor((lo + hi) / 2)
326+ y = sortedArray[mid]
327+
328+ if (t === y.time) {
329+ return mid
330+ } else if (t < y.time) {
331+ hi = mid
332+ } else {
333+ lo = mid + 1
334+ }
335+ }
336+ return hi
337+}
338+
339+var newTimeslot = function (t, events) { return ({ time: t, events: events }) }
340+
341+function removeAll (f, a) {
342+ var l = a.length
343+ var b = new Array(l)
344+ var j = 0
345+ for (var x = (void 0), i = 0; i < l; ++i) {
346+ x = a[i]
347+ if (!f(x)) {
348+ b[j] = x
349+ ++j
350+ }
351+ }
352+
353+ b.length = j
354+ return b
355+}
356+
357+// findIndex :: a -> [a] -> Int
358+// find index of x in a, from the left
359+function findIndex (x, a) {
360+ for (var i = 0, l = a.length; i < l; ++i) {
361+ if (x === a[i]) {
362+ return i
363+ }
364+ }
365+ return -1
366+}
367+
368+var scheduler = new Scheduler(new ClockTimer(), new Timeline())
369+
370+exports.scheduler = scheduler
src/Control/Scheduler/Scheduler.pursnew file+32
@@ -0,0 +1,32 @@
1+module Control.Stream.Scheduler where
2+
3+import Control.Monad.Eff (Pure)
4+import Control.Stream.Disposable (Disposable)
5+import Control.Stream.Sink (Sink)
6+import Control.Stream.Time (Time)
7+import Data.Unit (Unit)
8+
9+newtype Scheduler = Scheduler
10+ { now :: Pure Time
11+ , asap :: Task -> ScheduledTask
12+ , delay :: Number -> Task -> ScheduledTask
13+ , periodic :: Number -> Task -> ScheduledTask
14+ , schedule :: Number -> Number -> Task -> ScheduledTask
15+ , cancel :: ScheduledTask -> Unit
16+ , cancelAll :: (ScheduledTask -> Boolean) -> Unit
17+ }
18+
19+type Task =
20+ { run :: Time -> Unit
21+ , dispose :: Pure Unit
22+ }
23+
24+type ScheduledTask =
25+ { run :: Pure Unit
26+ , dispose :: Pure Unit
27+ }
28+
29+foreign import scheduler :: Scheduler
30+foreign import scheduleTasks :: (Task -> ScheduledTask) -> Array Task -> Disposable
31+foreign import eventTask :: forall a. Sink a -> a -> Task
32+foreign import endTask :: forall a. Sink a -> Task
src/Control/Sink/Sink.pursnew file+9
@@ -0,0 +1,9 @@
1+module Control.Stream.Sink (Sink(..)) where
2+
3+import Control.Stream.Time (Time)
4+import Data.Unit (Unit)
5+
6+newtype Sink a = Sink
7+ { event :: Time -> a -> Unit
8+ , end :: Time -> Unit
9+ }
src/Control/Stream.jsdeleted−1123
@@ -1,1123 +0,0 @@
1−'use strict';
2−
3−Object.defineProperty(exports, '__esModule', { value: true });
4−
5−/** @license MIT License (c) copyright 2010-2016 original author or authors */
6−
7−// Non-mutating array operations
8−
9−// cons :: a -> [a] -> [a]
10−// a with x prepended
11−
12−
13−// append :: a -> [a] -> [a]
14−// a with x appended
15−
16−
17−// drop :: Int -> [a] -> [a]
18−// drop first n elements
19−function drop (n, a) { // eslint-disable-line complexity
20− if (n < 0) {
21− throw new TypeError('n must be >= 0')
22− }
23−
24− var l = a.length;
25− if (n === 0 || l === 0) {
26− return a
27− }
28−
29− if (n >= l) {
30− return []
31− }
32−
33− return unsafeDrop(n, a, l - n)
34−}
35−
36−// unsafeDrop :: Int -> [a] -> Int -> [a]
37−// Internal helper for drop
38−function unsafeDrop (n, a, l) {
39− var b = new Array(l);
40− for (var i = 0; i < l; ++i) {
41− b[i] = a[n + i];
42− }
43− return b
44−}
45−
46−// tail :: [a] -> [a]
47−// drop head element
48−function tail (a) {
49− return drop(1, a)
50−}
51−
52−// copy :: [a] -> [a]
53−// duplicate a (shallow duplication)
54−
55−
56−// map :: (a -> b) -> [a] -> [b]
57−// transform each element with f
58−function map (f, a) {
59− var l = a.length;
60− var b = new Array(l);
61− for (var i = 0; i < l; ++i) {
62− b[i] = f(a[i]);
63− }
64− return b
65−}
66−
67−// reduce :: (a -> b -> a) -> a -> [b] -> a
68−// accumulate via left-fold
69−function reduce (f, z, a) {
70− var r = z;
71− for (var i = 0, l = a.length; i < l; ++i) {
72− r = f(r, a[i], i);
73− }
74− return r
75−}
76−
77−// replace :: a -> Int -> [a]
78−// replace element at index
79−
80−
81−// remove :: Int -> [a] -> [a]
82−// remove element at index
83−
84−
85−// removeAll :: (a -> boolean) -> [a] -> [a]
86−// remove all elements matching a predicate
87−function removeAll (f, a) {
88− var l = a.length;
89− var b = new Array(l);
90− var j = 0;
91− for (var x = (void 0), i = 0; i < l; ++i) {
92− x = a[i];
93− if (!f(x)) {
94− b[j] = x;
95− ++j;
96− }
97− }
98−
99− b.length = j;
100− return b
101−}
102−
103−// findIndex :: a -> [a] -> Int
104−// find index of x in a, from the left
105−function findIndex (x, a) {
106− for (var i = 0, l = a.length; i < l; ++i) {
107− if (x === a[i]) {
108− return i
109− }
110− }
111− return -1
112−}
113−
114−// isArrayLike :: * -> boolean
115−// Return true iff x is array-like
116−
117−/** @license MIT License (c) copyright 2010-2016 original author or authors */
118−
119−// id :: a -> a
120−var id = function (x) { return x; };
121−
122−// compose :: (b -> c) -> (a -> b) -> (a -> c)
123−
124−
125−// apply :: (a -> b) -> a -> b
126−
127−
128−// curry2 :: ((a, b) -> c) -> (a -> b -> c)
129−function curry2 (f) {
130− function curried (a, b) {
131− switch (arguments.length) {
132− case 0: return curried
133− case 1: return function (b) { return f(a, b); }
134− default: return f(a, b)
135− }
136− }
137− return curried
138−}
139−
140−// curry3 :: ((a, b, c) -> d) -> (a -> b -> c -> d)
141−function curry3 (f) {
142− function curried (a, b, c) { // eslint-disable-line complexity
143− switch (arguments.length) {
144− case 0: return curried
145− case 1: return curry2(function (b, c) { return f(a, b, c); })
146− case 2: return function (c) { return f(a, b, c); }
147− default:return f(a, b, c)
148− }
149− }
150− return curried
151−}
152−
153−// curry4 :: ((a, b, c, d) -> e) -> (a -> b -> c -> d -> e)
154−
155−/** @license MIT License (c) copyright 2016 original author or authors */
156−
157−var Disposable = function Disposable (dispose, data) {
158− this._dispose = dispose;
159− this._data = data;
160−
161− this.dispose = function () { return dispose(data); };
162−};
163−
164−var MemoizedDisposable = function MemoizedDisposable (disposable) {
165− this.disposed = false;
166− this.value = undefined;
167− this.disposable = disposable;
168−};
169−
170−MemoizedDisposable.prototype.dispose = function dispose () {
171− if (!this.disposed) {
172− this.disposed = true;
173− this.value = this.disposable.dispose();
174− this.disposable = undefined;
175− }
176−
177− return this.value
178−};
179−
180−function disposeSafely (disposable) {
181− disposable.dispose();
182−}
183−
184−var createDisposable = curry2(function (dispose, data) { return new MemoizedDisposable(new Disposable(dispose, data)); });
185−
186−var emptyDisposable = new Disposable(id, undefined);
187−
188−var disposeAll = function (disposables) { return createDisposable(curry2(map)(disposeSafely), disposables); };
189−
190−/** @license MIT License (c) copyright 2010-2016 original author or authors */
191−/** @author Brian Cavalier */
192−/** @author John Hann */
193−
194−/*global setTimeout, clearTimeout*/
195−
196−function defer (task) {
197− return Promise.resolve(task).then(runTask)
198−}
199−
200−function runTask (task) {
201− return task.run()
202−}
203−
204−var ClockTimer = function ClockTimer () {
205− this.now = Date.now;
206−};
207−
208−ClockTimer.prototype.setTimer = function setTimer (f, dt) {
209− return dt <= 0 ? runAsap(f) : setTimeout(f, dt)
210−};
211−
212−ClockTimer.prototype.clearTimer = function clearTimer (t) {
213− return t instanceof Asap ? t.cancel() : clearTimeout(t)
214−};
215−
216−var Asap = function Asap (f) {
217− this.f = f;
218− this.active = true;
219−};
220−
221−Asap.prototype.run = function run () {
222− return this.active && this.f()
223−};
224−
225−Asap.prototype.cancel = function cancel () {
226− this.active = false;
227−};
228−
229−function runAsap (f) {
230− var task = new Asap(f);
231− defer(task);
232− return task
233−}
234−
235−/* */
236−var ScheduledTask = function ScheduledTask (delay, period, task, scheduler) {
237− this.time = delay;
238− this.period = period;
239− this.task = task;
240− this.scheduler = scheduler;
241− this.active = true;
242−};
243−
244−ScheduledTask.prototype.run = function run () {
245− this.task.run(this.time);
246−};
247−
248−ScheduledTask.prototype.dispose = function dispose () {
249− this.scheduler.cancel(this);
250− this.task.dispose();
251−};
252−
253−/* */
254−function runTask$1 (task) {
255− try {
256− return task.run()
257− } catch (e) {
258− console.error(e);
259− }
260−}
261−
262−var Scheduler = function Scheduler (timer, timeline) {
263− var this$1 = this;
264−
265− this.timer = timer;
266− this.timeline = timeline;
267−
268− this._timer = null;
269− this._nextArrival = Infinity;
270−
271− this._runReadyTasksBound = function () { return this$1._runReadyTasks(this$1.now()); };
272−};
273−
274−Scheduler.prototype.now = function now () {
275− return this.timer.now()
276−};
277−
278−Scheduler.prototype.asap = function asap (task) {
279− return this.schedule(0)(-1)(task)
280−};
281−
282−Scheduler.prototype.delay = function delay (delay$1) {
283− var this$1 = this;
284−
285− return function (task) { return this$1.schedule(delay$1)(-1)(task); }
286−};
287−
288−Scheduler.prototype.periodic = function periodic (period) {
289− var this$1 = this;
290−
291− return function (task) { return this$1.schedule(0)(period)(task); }
292−};
293−
294−Scheduler.prototype.schedule = function schedule (delay) {
295− var this$1 = this;
296−
297− return function (period) { return function (task) {
298− var now = this$1.now();
299− var st = new ScheduledTask(now + Math.max(0, delay), period, task, this$1);
300−
301− this$1.timeline.add(st);
302− this$1._scheduleNextRun(now);
303− return st
304− }; }
305−};
306−
307−Scheduler.prototype.cancel = function cancel (task) {
308− task.active = false;
309− if (this.timeline.remove(task)) {
310− this._reschedule();
311− }
312−};
313−
314−Scheduler.prototype.cancelAll = function cancelAll (f) {
315− this.timeline.removeAll(f);
316− this._reschedule();
317−};
318−
319−Scheduler.prototype._reschedule = function _reschedule () {
320− if (this.timeline.isEmpty()) {
321− this._unschedule();
322− } else {
323− this._scheduleNextRun(this.now());
324− }
325−};
326−
327−Scheduler.prototype._unschedule = function _unschedule () {
328− this.timer.clearTimer(this._timer);
329− this._timer = null;
330−};
331−
332−Scheduler.prototype._scheduleNextRun = function _scheduleNextRun (now) { // eslint-disable-line complexity
333− if (this.timeline.isEmpty()) {
334− return
335− }
336−
337− var nextArrival = this.timeline.nextArrival();
338−
339− if (this._timer === null) {
340− this._scheduleNextArrival(nextArrival, now);
341− } else if (nextArrival < this._nextArrival) {
342− this._unschedule();
343− this._scheduleNextArrival(nextArrival, now);
344− }
345−};
346−
347−Scheduler.prototype._scheduleNextArrival = function _scheduleNextArrival (nextArrival, now) {
348− this._nextArrival = nextArrival;
349− var delay = Math.max(0, nextArrival - now);
350− this._timer = this.timer.setTimer(this._runReadyTasksBound, delay);
351−};
352−
353−Scheduler.prototype._runReadyTasks = function _runReadyTasks (now) {
354− this._timer = null;
355− this.timeline.runTasks(now, runTask$1);
356− this._scheduleNextRun(this.now());
357−};
358−
359−/** @license MIT License (c) copyright 2010-2016 original author or authors */
360−/** @author Brian Cavalier */
361−/** @author John Hann */
362−
363−var Timeline = function Timeline () {
364− this.tasks = [];
365−};
366−
367−Timeline.prototype.nextArrival = function nextArrival () {
368− return this.isEmpty() ? Infinity : this.tasks[0].time
369−};
370−
371−Timeline.prototype.isEmpty = function isEmpty () {
372− return this.tasks.length === 0
373−};
374−
375−Timeline.prototype.add = function add (st) {
376− insertByTime(st, this.tasks);
377−};
378−
379−Timeline.prototype.remove = function remove$$1 (st) {
380− var i = binarySearch(st.time, this.tasks);
381−
382− if (i >= 0 && i < this.tasks.length) {
383− var at = findIndex(st, this.tasks[i].events);
384− if (at >= 0) {
385− this.tasks[i].events.splice(at, 1);
386− return true
387− }
388− }
389−
390− return false
391−};
392−
393−Timeline.prototype.removeAll = function removeAll$$1 (f) {
394− var this$1 = this;
395−
396− for (var i = 0; i < this.tasks.length; ++i) {
397− removeAllFrom(f, this$1.tasks[i]);
398− }
399−};
400−
401−Timeline.prototype.runTasks = function runTasks (t, runTask) {
402− var this$1 = this;
403−
404− var tasks = this.tasks;
405− var l = tasks.length;
406− var i = 0;
407−
408− while (i < l && tasks[i].time <= t) {
409− ++i;
410− }
411−
412− this.tasks = tasks.slice(i);
413−
414− // Run all ready tasks
415− for (var j = 0; j < i; ++j) {
416− this$1.tasks = runReadyTasks(runTask, tasks[j].events, this$1.tasks);
417− }
418−};
419−
420−function runReadyTasks (runTask, events, tasks) { // eslint-disable-line complexity
421− for (var i = 0; i < events.length; ++i) {
422− var task = events[i];
423−
424− if (task.active) {
425− runTask(task);
426−
427− // Reschedule periodic repeating tasks
428− // Check active again, since a task may have canceled itself
429− if (task.period >= 0 && task.active) {
430− task.time = task.time + task.period;
431− insertByTime(task, tasks);
432− }
433− }
434− }
435−
436− return tasks
437−}
438−
439−function insertByTime (task, timeslots) { // eslint-disable-line complexity
440− var l = timeslots.length;
441−
442− if (l === 0) {
443− timeslots.push(newTimeslot(task.time, [task]));
444− return
445− }
446−
447− var i = binarySearch(task.time, timeslots);
448−
449− if (i >= l) {
450− timeslots.push(newTimeslot(task.time, [task]));
451− } else if (task.time === timeslots[i].time) {
452− timeslots[i].events.push(task);
453− } else {
454− timeslots.splice(i, 0, newTimeslot(task.time, [task]));
455− }
456−}
457−
458−function removeAllFrom (f, timeslot) {
459− timeslot.events = removeAll(f, timeslot.events);
460−}
461−
462−function binarySearch (t, sortedArray) { // eslint-disable-line complexity
463− var lo = 0;
464− var hi = sortedArray.length;
465− var mid, y;
466−
467− while (lo < hi) {
468− mid = Math.floor((lo + hi) / 2);
469− y = sortedArray[mid];
470−
471− if (t === y.time) {
472− return mid
473− } else if (t < y.time) {
474− hi = mid;
475− } else {
476− lo = mid + 1;
477− }
478− }
479− return hi
480−}
481−
482−var newTimeslot = function (t, events) { return ({ time: t, events: events }); };
483−
484−var propagateTask =
485− curry3(function (run, value, sink) { return new PropagateTask(run, value, sink); });
486−
487−var eventTask =
488− curry2(function (value, sink) { return propagateTask(runEvent, value, sink); });
489−
490−var endTask = function (sink) { return propagateTask(runEnd, void 0, sink); };
491−
492−var PropagateTask = function PropagateTask (run, value, sink) {
493− var active = true;
494−
495− this.dispose = function () { active = false; };
496− this.run = function (t) {
497− if (!active) { return }
498−
499− run(t, value, sink);
500− };
501−};
502−
503−function runEvent (time, value, sink) {
504− sink.event(time)(value);
505−}
506−
507−function runEnd (time, value, sink) {
508− sink.end(time, value);
509−}
510−
511−var defaultScheduler = new Scheduler(new ClockTimer(), new Timeline());
512−
513−var scheduleTasks = curry2(function (tasks, scheduler) {
514− var scheduledTasks = tasks.map(function (task) { return scheduler.asap(task); });
515−
516− return {
517− dispose: function () { return scheduledTasks.forEach(function (task) { return task.dispose(); }); }
518− }
519−});
520−
521−var SettableDisposable = function SettableDisposable () {
522− this.disposable = void 0;
523− this.disposed = false;
524− this.result = void 0;
525−};
526−
527−SettableDisposable.prototype.setDisposable = function setDisposable (disposable) {
528− this.disposable = disposable;
529−
530− if (this.disposed) {
531− this.result = disposable.dispose();
532− }
533−};
534−
535−SettableDisposable.prototype.dispose = function dispose () {
536− if (this.disposed) {
537− return this.result
538− }
539−
540− this.disposed = true;
541−
542− if (this.disposable !== void 0) {
543− this.result = this.disposable.dispose();
544− }
545−
546− return this.result
547−};
548−
549−function runEffects (stream, scheduler) {
550− return runSourceEffects(stream.source, scheduler)
551−}
552−
553−var runSourceEffects = function (source, scheduler) { return runSource(source, scheduler); };
554−
555−function runSource (source, scheduler) {
556− var disposable = new SettableDisposable();
557− var observer = new RunEffectsSink(disposable);
558−
559− disposable.setDisposable(source.run(observer)(scheduler));
560−
561− return {}
562−}
563−
564−var RunEffectsSink = function RunEffectsSink (disposable) {
565− this._disposable = disposable;
566− this.active = true;
567−};
568−
569−RunEffectsSink.prototype.event = function event (t) {
570− return function (x) {}
571−};
572−
573−RunEffectsSink.prototype.end = function end (t) {
574− this.active = false;
575− Promise.resolve(this._disposable).then(function (d) { return d.dispose(); });
576−};
577−
578−var drain = function (stream) { return function () { return runEffects(stream, defaultScheduler); }; };
579−
580−var LinkedList = function LinkedList () {
581− this.head = null;
582− this.length = 0;
583−};
584−
585−LinkedList.prototype.add = function add (x) {
586− if (this.head !== null) {
587− this.head.prev = x;
588− x.next = this.head;
589− }
590− this.head = x;
591− ++this.length;
592−};
593−
594−LinkedList.prototype.remove = function remove (x) { // eslint-disable-linecomplexity
595− --this.length;
596− if (x === this.head) {
597− this.head = this.head.next;
598− }
599− if (x.next !== null) {
600− x.next.prev = x.prev;
601− x.next = null;
602− }
603− if (x.prev !== null) {
604− x.prev.next = x.next;
605− x.prev = null;
606− }
607−};
608−
609−LinkedList.prototype.isEmpty = function isEmpty () {
610− return this.length === 0
611−};
612−
613−LinkedList.prototype.dispose = function dispose () {
614− if (this.isEmpty()) { return }
615−
616− var x = this.head;
617− this.head = null;
618− this.length = 0;
619−
620− while (x !== null) {
621− x.dispose();
622− x = x.next;
623− }
624−};
625−
626−var Stream = function Stream (source) {
627− this.source = source;
628−};
629−
630−/** @license MIT License (c) copyright 2010-2016 original author or authors */
631−/** @author Brian Cavalier */
632−/** @author John Hann */
633−
634−var flatMap =
635− curry2(function (stream, f) { return mergeMapConcurrently(f, Infinity, stream); });
636−
637−var mergeConcurrently = curry2(function (concurrency, stream) { return mergeMapConcurrently(id, concurrency, stream); });
638−
639−var join =
640− mergeConcurrently(Infinity);
641−
642−var mergeMapConcurrently = curry3(function (f, concurrency, stream) { return new Stream(new MergeConcurrently(f, concurrency, stream.source)); });
643−
644−var MergeConcurrently = function MergeConcurrently (f, concurrency, source) {
645− this.f = f;
646− this.concurrency = concurrency;
647− this.source = source;
648−};
649−
650−MergeConcurrently.prototype.run = function run (sink) {
651− var this$1 = this;
652−
653− return function (scheduler) { return new Outer(this$1.f, this$1.concurrency, this$1.source, sink, scheduler); }
654−};
655−
656−var Outer = function Outer (f, concurrency, source, sink, scheduler) {
657− this.f = f;
658− this.concurrency = concurrency;
659− this.sink = sink;
660− this.scheduler = scheduler;
661− this.pending = [];
662− this.current = new LinkedList();
663− this.disposable = new MemoizedDisposable(source.run(this)(scheduler));
664− this.active = true;
665−};
666−
667−Outer.prototype.event = function event (t) {
668− var this$1 = this;
669−
670− return function (x) { return this$1._addInner(t, x); }
671−};
672−
673−Outer.prototype._addInner = function _addInner (t, x) {
674− if (this.current.length < this.concurrency) {
675− this._startInner(t, x);
676− } else {
677− this.pending.push(x);
678− }
679−};
680−
681−Outer.prototype._startInner = function _startInner (t, x) {
682− try {
683− this._initInner(t, x);
684− } catch (e) {
685− this.error(t, e);
686− }
687−};
688−
689−Outer.prototype._initInner = function _initInner (t, x) {
690− var innerSink = new Inner(t, this, this.sink);
691− innerSink.disposable = mapAndRun(this.f, x, innerSink, this.scheduler);
692− this.current.add(innerSink);
693−};
694−
695−Outer.prototype.end = function end (t) {
696− this.active = false;
697− this.disposable.dispose();
698− this._checkEnd(t);
699−};
700−
701−Outer.prototype.dispose = function dispose () {
702− this.active = false;
703− this.pending.length = 0;
704− this.disposable.dispose();
705− this.current.dispose();
706−};
707−
708−Outer.prototype._endInner = function _endInner (t, inner) {
709− this.current.remove(inner);
710− inner.dispose();
711−
712− if (this.pending.length === 0) {
713− this._checkEnd(t);
714− } else {
715− this._startInner(t, this.pending.shift());
716− }
717−};
718−
719−Outer.prototype._checkEnd = function _checkEnd (t) {
720− if (!this.active && this.current.isEmpty()) {
721− this.sink.end(t);
722− }
723−};
724−
725−var mapAndRun = function (f, x, sink, scheduler) { return f(x).source.run(sink)(scheduler); };
726−
727−var Inner = function Inner (time, outer, sink) {
728− this.prev = this.next = null;
729− this.time = time;
730− this.outer = outer;
731− this.sink = sink;
732− this.disposable = void 0;
733−};
734−
735−Inner.prototype.event = function event (t) {
736− var this$1 = this;
737−
738− return function (x) { return this$1.sink.event(Math.max(t, this$1.time))(x); }
739−};
740−
741−Inner.prototype.end = function end (t) {
742− this.outer._endInner(Math.max(t, this.time), this);
743−};
744−
745−Inner.prototype.dispose = function dispose () {
746− return this.disposable.dispose()
747−};
748−
749−var IndexSink = function IndexSink (i, sink) {
750− this.sink = sink;
751− this.index = i;
752− this.active = true;
753− this.value = void 0;
754−};
755−
756−IndexSink.prototype.event = function event (t) {
757− var this$1 = this;
758−
759− return function (x) {
760− if (!this$1.active) { return }
761−
762− this$1.value = x;
763− this$1.sink.event(t)(this$1);
764− }
765−};
766−
767−IndexSink.prototype.end = function end (t) {
768− if (!this.active) { return }
769−
770− this.active = false;
771− this.sink.end(t, { index: this.index });
772−};
773−
774−/** @license MIT License (c) copyright 2010-2016 original author or authors */
775−/** @author Brian Cavalier */
776−/** @author John Hann */
777−
778−var combine2 = function (f) { return function (s1) { return function (s2) { return combineArray(f, [s1, s2]); }; }; };
779−var combine3 = function (f) { return function (s1) { return function (s2) { return function (s3) { return combineArray(f, [s1, s2, s3]); }; }; }; };
780−var combine4 = function (f) { return function (s1) { return function (s2) { return function (s3) { return function (s4) { return combineArray(f, [s1, s2, s3, s4]); }; }; }; }; };
781−var combine5 = function (f) { return function (s1) { return function (s2) { return function (s3) { return function (s4) { return function (s5) { return combineArray(f, [s1, s2, s3, s4, s5]); }; }; }; }; }; };
782−
783−function combineArray (f, streams) {
784− return new Stream(combineSources(f, streams))
785−}
786−
787−function combineSources (f, streams) {
788− return new Combine(f, map(getSource, streams))
789−}
790−
791−function getSource (stream) {
792− return stream.source
793−}
794−
795−function Combine (f, sources) {
796− this.f = f;
797− this.sources = sources;
798−}
799−
800−Combine.prototype.run = function (sink) {
801− var this$1 = this;
802−
803− return function (scheduler) {
804− var l = this$1.sources.length;
805− var disposables = new Array(l);
806− var sinks = new Array(l);
807−
808− var mergeSink = new CombineSink(disposables, sinks, sink, this$1.f);
809−
810− for (var indexSink, i = 0; i < l; ++i) {
811− indexSink = sinks[i] = new IndexSink(i, mergeSink);
812− disposables[i] = this$1.sources[i].run(indexSink)(scheduler);
813− }
814−
815− return disposeAll(disposables)
816− }
817−};
818−
819−function CombineSink (disposables, sinks, sink, f) {
820− var this$1 = this;
821−
822− this.sink = sink;
823− this.disposables = disposables;
824− this.sinks = sinks;
825− this.f = f;
826−
827− var l = sinks.length;
828− this.awaiting = l;
829− this.values = new Array(l);
830− this.hasValue = new Array(l);
831−
832− for (var i = 0; i < l; ++i) {
833− this$1.hasValue[i] = false;
834− }
835−
836− this.activeCount = sinks.length;
837−}
838−
839−CombineSink.prototype.event = function (t) {
840− var this$1 = this;
841−
842− return function (indexedValue) {
843− var i = indexedValue.index;
844− var awaiting = this$1._updateReady(i);
845−
846− this$1.values[i] = indexedValue.value;
847− if (awaiting === 0) {
848− var value = tail(this$1.values).reduce(function (f, x) { return f(x); }, this$1.f(this$1.values[0]));
849− this$1.sink.event(t)(value);
850− }
851− }
852−};
853−
854−CombineSink.prototype._updateReady = function (index) {
855− if (this.awaiting > 0) {
856− if (!this.hasValue[index]) {
857− this.hasValue[index] = true;
858− this.awaiting -= 1;
859− }
860− }
861− return this.awaiting
862−};
863−
864−CombineSink.prototype.end = function (t, indexedValue) {
865− this.disposables[indexedValue.index].dispose();
866−
867− if (--this.activeCount === 0) {
868− this.sink.end(t);
869− }
870−};
871−
872−/** @license MIT License (c) copyright 2010-2016 original author or authors */
873−/** @author Brian Cavalier */
874−/** @author John Hann */
875−
876−/**
877− * @param {Array} streams array of stream to merge
878− * @returns {Stream} stream containing events from all input observables
879− * in time order. If two events are simultaneous they will be merged in
880− * arbitrary order.
881− */
882−function merge (streams) {
883− return new Stream(mergeSources(streams))
884−}
885−
886−/**
887− * This implements fusion/flattening for merge. It will
888− * fuse adjacent merge operations. For example:
889− * - a.merge(b).merge(c) effectively becomes merge(a, b, c)
890− * - merge(a, merge(b, c)) effectively becomes merge(a, b, c)
891− * It does this by concatenating the sources arrays of
892− * any nested Merge sources, in effect "flattening" nested
893− * merge operations into a single merge.
894− */
895−function mergeSources (streams) {
896− return new Merge(reduce(appendSources, [], streams))
897−}
898−
899−function appendSources (sources, stream) {
900− var source = stream.source;
901− return source instanceof Merge
902− ? sources.concat(source.sources)
903− : sources.concat(source)
904−}
905−
906−function Merge (sources) {
907− this.sources = sources;
908−}
909−
910−Merge.prototype.run = function (sink, scheduler) {
911− var this$1 = this;
912−
913− var l = this.sources.length;
914− var disposables = new Array(l);
915− var sinks = new Array(l);
916−
917− var mergeSink = new MergeSink(disposables, sinks, sink);
918−
919− for (var indexSink, i = 0; i < l; ++i) {
920− indexSink = sinks[i] = new IndexSink(i, mergeSink);
921− disposables[i] = this$1.sources[i].run(indexSink, scheduler);
922− }
923−
924− return disposeAll(disposables)
925−};
926−
927−function MergeSink (disposables, sinks, sink) {
928− this.sink = sink;
929− this.disposables = disposables;
930− this.activeCount = sinks.length;
931−}
932−
933−MergeSink.prototype.event = function (t, indexValue) {
934− this.sink.event(t, indexValue.value);
935−};
936−
937−MergeSink.prototype.end = function (t, indexedValue) {
938− dispose.tryDispose(t, this.disposables[indexedValue.index], this.sink);
939− if (--this.activeCount === 0) {
940− this.sink.end(t, indexedValue.value);
941− }
942−};
943−
944−var concat = function (s1) { return function (s2) { return continueWith(function () { return s2; })(s1); }; };
945−
946−var continueWith = function (f) { return function (stream) { return new Stream(new ContinueWith(f, stream.source)); }; };
947−
948−function ContinueWith (f, source) {
949− this.f = f;
950− this.source = source;
951−}
952−
953−ContinueWith.prototype.run = function (sink) {
954− var this$1 = this;
955−
956− return function (scheduler) {
957− return new ContinueWithSink(this$1.f, this$1.source, sink, scheduler)
958− }
959−};
960−
961−function ContinueWithSink (f, source, sink, scheduler) {
962− this.f = f;
963− this.sink = sink;
964− this.scheduler = scheduler;
965− this.active = true;
966− this.disposable = new MemoizedDisposable(source.run(this)(scheduler));
967−}
968−
969−ContinueWithSink.prototype.event = function (t) {
970− var this$1 = this;
971−
972− return function (x) {
973− if (!this$1.active) {
974− return
975− }
976− this$1.sink.event(t)(x);
977− }
978−};
979−
980−ContinueWithSink.prototype.end = function (t, x) {
981− if (!this.active) {
982− return
983− }
984−
985− this.disposable.dispose();
986− this._startNext(t, x, this.sink);
987−};
988−
989−ContinueWithSink.prototype._startNext = function (t, x, sink) {
990− this._continue(this.f, x, sink);
991−};
992−
993−ContinueWithSink.prototype._continue = function (f, x, sink) {
994− return f(x).source.run(sink)(this.scheduler)
995−};
996−
997−ContinueWithSink.prototype.dispose = function () {
998− this.active = false;
999− return this.disposable.dispose()
1000−};
1001−
1002−/**
1003− * Given a stream of streams, return a new stream that adopts the behavior
1004− * of the most recent inner stream.
1005− * @param {Stream} stream of streams on which to switch
1006− * @returns {Stream} switching stream
1007− */
1008−function switchLatest (stream) {
1009− return new Stream(new Switch(stream.source))
1010−}
1011−
1012−function Switch (source) {
1013− this.source = source;
1014−}
1015−
1016−Switch.prototype.run = function (sink) {
1017− var this$1 = this;
1018−
1019− return function (scheduler) {
1020− var switchSink = new SwitchSink(sink, scheduler);
1021− return disposeAll([switchSink, this$1.source.run(switchSink)(scheduler)])
1022− }
1023−};
1024−
1025−function SwitchSink (sink, scheduler) {
1026− this.sink = sink;
1027− this.scheduler = scheduler;
1028− this.current = null;
1029− this.ended = false;
1030−}
1031−
1032−SwitchSink.prototype.event = function (t) {
1033− var this$1 = this;
1034−
1035− return function (stream) {
1036− this$1._disposeCurrent(t); // TODO: capture the result of this dispose
1037− this$1.current = new Segment(t, Infinity, this$1, this$1.sink);
1038− this$1.current.disposable = stream.source.run(this$1.current)(this$1.scheduler);
1039− }
1040−};
1041−
1042−SwitchSink.prototype.end = function (t, x) {
1043− this.ended = true;
1044− this._checkEnd(t, x);
1045−};
1046−
1047−SwitchSink.prototype.dispose = function () {
1048− return this._disposeCurrent(this.scheduler.now())
1049−};
1050−
1051−SwitchSink.prototype._disposeCurrent = function (t) {
1052− if (this.current !== null) {
1053− return this.current._dispose(t)
1054− }
1055−};
1056−
1057−SwitchSink.prototype._disposeInner = function (t, inner) {
1058− inner._dispose(t); // TODO: capture the result of this dispose
1059− if (inner === this.current) {
1060− this.current = null;
1061− }
1062−};
1063−
1064−SwitchSink.prototype._checkEnd = function (t, x) {
1065− if (this.ended && this.current === null) {
1066− this.sink.end(t, x);
1067− }
1068−};
1069−
1070−SwitchSink.prototype._endInner = function (t, x, inner) {
1071− this._disposeInner(t, inner);
1072− this._checkEnd(t, x);
1073−};
1074−
1075−function Segment (min, max, outer, sink) {
1076− this.min = min;
1077− this.max = max;
1078− this.outer = outer;
1079− this.sink = sink;
1080− this.disposable = emptyDisposable;
1081−}
1082−
1083−Segment.prototype.event = function (t) {
1084− var this$1 = this;
1085−
1086− return function (x) {
1087− if (t < this$1.max) {
1088− this$1.sink.event(Math.max(t, this$1.min))(x);
1089− }
1090− }
1091−};
1092−
1093−Segment.prototype.end = function (t, x) {
1094− this.outer._endInner(Math.max(t, this.min), x, this);
1095−};
1096−
1097−Segment.prototype._dispose = function (t) {
1098− this.max = t;
1099− this.disposable.dispose();
1100−};
1101−
1102−/* */
1103−
1104−exports.createDisposable = createDisposable;
1105−exports.emptyDisposable = emptyDisposable;
1106−exports.disposeAll = disposeAll;
1107−exports.defaultScheduler = defaultScheduler;
1108−exports.scheduleTasks = scheduleTasks;
1109−exports.endTask = endTask;
1110−exports.eventTask = eventTask;
1111−exports.drain = drain;
1112−exports.flatMap = flatMap;
1113−exports.mergeConcurrently = mergeConcurrently;
1114−exports.join = join;
1115−exports.mergeMapConcurrently = mergeMapConcurrently;
1116−exports.combine2 = combine2;
1117−exports.combine3 = combine3;
1118−exports.combine4 = combine4;
1119−exports.combine5 = combine5;
1120−exports.merge = merge;
1121−exports.concat = concat;
1122−exports.continueWith = continueWith;
1123−exports.switch = switchLatest;
src/Control/Stream.purs+42−275
@@ -1,292 +1,59 @@
11module Control.Stream
2− ( STREAM
2+ ( module Control.Stream.Stream
3+ , module Control.Stream.Disposable
4+ , module Control.Stream.Scheduler
5+ , module Control.Stream.Sink
6+ , module Control.Stream.Time
7+ ) where
8+
9+import Control.Stream.Stream
10+ (STREAM
311 , EffStream
4− , Stream
5− , Source
6− , Sink
7− , Scheduler
8− , Task
9− , ScheduledTask
10− , Disposable
11− , Time
12− , EventFn
13− , EndFn
14− -- Scheduler-related functions and values
15− , defaultScheduler
16− , eventTask
17− , endTask
18− , createDisposable
19− , emptyDisposable
20− , disposeAll
21− , scheduleTasks
22− -- Stream-related helpers
23− , createStream
24− , createSink
12+ , Stream(..)
13+ , just
14+ , empty
15+ , never
16+ , periodic
2517 , createCombinator
2618 , createEventCombinator
2719 , createEndCombinator
28− , getSource
29− , runSource
30− -- Combinators
3120 , drain
3221 , tapEvent
3322 , tapEnd
23+ , fromArray
3424 , filter
25+ , take
26+ , skip
27+ , constant
28+ , continueWith
29+ , concat
30+ , startWith
31+ , scan
32+ , loop
33+ , chain
3534 , mergeConcurrently
36− , mergeMapConcurrently
3735 , join
36+ , mergeMapConcurrently
37+ , concatMap
38+ , switch
3839 , combine2
3940 , combine3
4041 , combine4
4142 , combine5
42− , continueWith
43− , concat
43+ , combineArray
4444 , merge
45− , switch
46− , constant
47− , scan
48− , startWith
49− -- Stream factories
50− , just
51− , fromArray
52− , empty
53− , periodic
45+ , skipRepeatsWith
46+ , skipRepeats
47+ , until
48+ , since
49+ , during
50+ , sample
51+ , debounce
52+ , throttle
53+ , delay
54+ , multicast
5455 )
55− where
56−
57−import Control.Applicative (class Applicative)
58−import Control.Apply (class Apply)
59−import Control.Bind (class Bind)
60−import Control.Category (id)
61−import Control.Monad (class Monad)
62−import Control.Monad.Eff (Eff, Pure)
63−import Control.Monad.Eff.Ref (Ref, modifyRef', newRef, readRef)
64−import Control.Monad.Eff.Unsafe (unsafeCoerceEff, unsafePerformEff)
65−import Control.MonadPlus (class Alt, class Plus)
66−import Data.Array (snoc)
67−import Data.Function (flip, ($))
68−import Data.Functor (class Functor, map)
69−import Data.Monoid (class Monoid)
70−import Data.Semigroup (class Semigroup)
71−import Data.Unit (Unit, unit)
72−
73−newtype Time = Time Int
74−
75−foreign import data STREAM :: !
76−
77−type EffStream e a = Eff (stream :: STREAM | e) a
78−
79−newtype Stream a = Stream { source :: Source a }
80−
81−type Source a = { run :: Sink a -> Scheduler -> Disposable }
82−
83−type Sink a =
84− { event :: Time -> a -> Unit
85− , end :: Time -> Unit
86− }
87−
88−newtype Scheduler = Scheduler
89− { now :: Pure Time
90− , asap :: Task -> ScheduledTask
91− , delay :: Number -> Task -> ScheduledTask
92− , periodic :: Number -> Task -> ScheduledTask
93− , schedule :: Number -> Number -> Task -> ScheduledTask
94− , cancel :: ScheduledTask -> Unit
95− , cancelAll :: (ScheduledTask -> Boolean) -> Unit
96− }
97−
98−type Task =
99− { run :: Time -> Unit
100− , dispose :: Pure Unit
101− }
102−
103−type ScheduledTask =
104− { run :: Pure Unit
105− , dispose :: Pure Unit
106− }
107−
108−type Disposable = { dispose :: Pure Unit }
109−
110−type EventFn a b = (Sink b -> Scheduler -> Time -> a -> Unit)
111−type EndFn a = (Sink a -> Scheduler -> Time -> Unit)
112−
113−instance functorStream :: Functor Stream where
114− map = _map
115−
116−instance applyStream :: Apply Stream where
117− apply = combine2 id
118−
119−instance applicativeStream :: Applicative Stream where
120− pure = just
121−
122−instance bindStream :: Bind Stream where
123− bind = flatMap
124−
125−instance monadStream :: Monad Stream
126−
127−instance semigroupStream :: Semigroup (Stream a) where
128− append = concat
129−
130−instance altStream :: Alt Stream where
131− alt = \s1 s2 -> merge [s1, s2]
132−
133−instance monoidStream :: Monoid (Stream a) where
134− mempty = empty
135−
136−instance plusStream :: Plus Stream where
137− empty = empty
138−
139−-- Stream-related helpers
140−createStream :: forall a. (Sink a -> Scheduler -> Disposable) -> Stream a
141−createStream run = Stream { source: { run } }
142−
143−getSource :: forall a. Stream a -> Source a
144−getSource stream = case stream of Stream a -> a.source
145−
146−runSource :: forall a. Stream a -> Sink a -> Scheduler -> Disposable
147−runSource stream sink scheduler = (getSource stream).run sink scheduler
148−
149−createSink :: forall a. (Time -> a -> Unit) -> (Time -> Unit) -> Sink a
150−createSink event end = { event, end }
151−
152−createCombinator :: forall a b. EventFn a b -> EndFn b -> Stream a -> Stream b
153−createCombinator event end stream = createStream runCombinator
154− where
155− runCombinator :: Sink b -> Scheduler -> Disposable
156− runCombinator sink scheduler =
157− runSource stream (createSink (event sink scheduler) (end sink scheduler)) scheduler
158−
159−createEventCombinator :: forall a b. EventFn a b -> Stream a -> Stream b
160−createEventCombinator event stream = createCombinator event end stream
161− where
162− end :: EndFn b
163− end sink scheduler time =
164− sink.end time
165−
166−createEndCombinator :: forall a. EndFn a -> Stream a -> Stream a
167−createEndCombinator end stream = createCombinator event end stream
168− where
169− event :: EventFn a a
170− event sink scheduler time value = sink.event time value
171−
172−-- Stream factories
173−just :: forall a. a -> Stream a
174−just a = createStream (runJust a)
175−
176−runJust :: forall a. a -> Sink a -> Scheduler -> Disposable
177−runJust a sink scheduler =
178− scheduleTasks [ eventTask a sink, endTask sink ] scheduler
179−
180−empty :: forall a. Stream a
181−empty = createStream \sink scheduler -> scheduleTasks [endTask sink] scheduler
182−
183−never :: forall a. Stream a
184−never = createStream \sink scheduler -> emptyDisposable
185−
186−-- TODO: remove fromArray because it's not a real event stream
187−-- replace with a fromArray combinator
188−fromArray :: forall a. Array a -> Stream a
189−fromArray arr = createStream (runFromArray arr)
190−
191−runFromArray :: forall a. Array a -> Sink a -> Scheduler -> Disposable
192−runFromArray arr sink scheduler = scheduleTasks tasks scheduler
193− where
194− tasks :: Array Task
195− tasks = snoc eventTasks (endTask sink)
196−
197− eventTasks :: Array Task
198− eventTasks = map (flip eventTask sink) arr
199−
200−periodic :: Number -> Stream Unit
201−periodic period = createStream (runPeriodic period)
202−
203−runPeriodic :: Number -> Sink Unit -> Scheduler -> Disposable
204−runPeriodic period sink scheduler = { dispose: scheduledTask.dispose }
205− where
206− p = case scheduler of Scheduler a -> a.periodic
207− scheduledTask = p period (eventTask unit sink)
208−
209−-- combinators
210−_map :: forall a b. (a -> b) -> Stream a -> Stream b
211−_map f stream = createEventCombinator mapEvent stream
212− where
213− mapEvent :: EventFn a b
214− mapEvent sink scheduler time value = sink.event time (f value)
215−
216−filter :: forall a. (a -> Boolean) -> Stream a -> Stream a
217−filter predicate stream = createEventCombinator event stream
218− where
219− event :: EventFn a a
220− event sink scheduler time value = if predicate value
221− then sink.event time value
222− else unit
223−
224−tapEvent :: forall e a. (a -> EffStream e Unit) -> Stream a -> Stream a
225−tapEvent f stream = createEventCombinator event stream
226− where
227− event :: EventFn a a
228− event sink scheduler time value = sink.event time value
229− where -- find a better way to perform these side effects
230− x = unsafePerformEff (f value)
231−
232−tapEnd :: forall e a. EffStream e Unit -> Stream a -> Stream a
233−tapEnd f stream = createEndCombinator end stream
234− where
235− end :: EndFn a
236− end sink scheduler time = sink.end time
237− where -- find a better way to perform these side effects
238− x = unsafePerformEff f
239−
240−startWith :: forall a. a -> Stream a -> Stream a
241−startWith value stream = concat (just value) stream
242−
243−constant :: forall a b. b -> Stream a -> Stream b
244−constant value stream = createEventCombinator constantEvent stream
245− where
246− constantEvent sink scheduler time x = sink.event time value
247−
248−scan :: forall a b. (b -> a -> b) -> b -> Stream a -> Stream b
249−scan f seed stream = startWith seed $ createEventCombinator scanEvent stream
250− where
251− state = createState seed
252−
253− scanEvent :: Sink b -> Scheduler -> Time -> a -> Unit
254− scanEvent sink scheduler time value = sink.event time (state.set \acc -> f acc value)
255−
256−-- find a better way to perform these side effects
257−createState :: forall a. a -> { get :: Pure a, set :: (a -> a) -> a }
258−createState seed = { set, get }
259− where
260− ref :: Ref a
261− ref = unsafePerformEff $ unsafeCoerceEff $ newRef seed
262−
263− set :: (a -> a) -> a
264− set f = unsafePerformEff $ unsafeCoerceEff $
265− modifyRef' ref \x -> { state: (f x), value: (f x) }
266−
267− get :: Pure a
268− get = unsafeCoerceEff $ readRef ref
269−
270−-- Foreign imports
271−-- Scheduler-related
272−foreign import defaultScheduler :: Scheduler
273−foreign import eventTask :: forall a. a -> Sink a -> Task
274−foreign import endTask :: forall a. Sink a -> Task
275−foreign import createDisposable :: forall a. (a -> Unit) -> a -> Disposable
276−foreign import emptyDisposable :: Disposable
277−foreign import disposeAll :: Array Disposable -> Disposable
278−foreign import scheduleTasks :: Array Task -> Scheduler -> Disposable
279−-- combinators
280−foreign import drain :: forall e a. Stream a -> EffStream e Unit
281−foreign import mergeConcurrently :: forall a. Int -> Stream (Stream a) -> Stream a
282−foreign import mergeMapConcurrently :: forall a b. (a -> Stream b) -> Stream a -> Stream b
283−foreign import combine2 :: forall a b c. (a -> b -> c) -> Stream a -> Stream b -> Stream c
284−foreign import combine3 :: forall a b c d. (a -> b -> c -> d) -> Stream a -> Stream b -> Stream c -> Stream d
285−foreign import combine4 :: forall a b c d e. (a -> b -> c -> d -> e) -> Stream a -> Stream b -> Stream c -> Stream d -> Stream e
286−foreign import combine5 :: forall a b c d e f. (a -> b -> c -> d -> e -> f) -> Stream a -> Stream b -> Stream c -> Stream d -> Stream e -> Stream f
287−foreign import join :: forall a. Stream (Stream a) -> Stream a
288−foreign import flatMap :: forall a b. Stream a -> (a -> Stream b) -> Stream b
289−foreign import continueWith :: forall a. (Unit -> Stream a) -> Stream a -> Stream a
290−foreign import concat :: forall a. Stream a -> Stream a -> Stream a
291−foreign import merge :: forall a. Array (Stream a) -> Stream a
292−foreign import switch :: forall a. Stream (Stream a) -> Stream a
56+import Control.Stream.Disposable (Disposable, emptyDisposable)
57+import Control.Stream.Scheduler (Scheduler(..), Task, ScheduledTask, scheduler, scheduleTasks, eventTask, endTask)
58+import Control.Stream.Sink (Sink(..))
59+import Control.Stream.Time (Time)
src/Control/Stream/Stream.jsnew file+1244
@@ -0,0 +1,1244 @@
1+var ControlStreamScheduler = require('../Control.Stream.Scheduler')
2+var ControlStreamStream = require('../Control.Stream.Stream')
3+
4+exports.drain = function (stream) { return function () { return runSource(stream, ControlStreamScheduler.scheduler) } }
5+
6+exports.subscribe = function (event) {
7+ return function (end) {
8+ return function (stream) {
9+ return function () {
10+ var disposable = new SettableDisposable()
11+
12+ var observer = { event: event, end: end }
13+
14+ var d = stream.run(observer)(ControlStreamScheduler.scheduler)
15+
16+ disposable.setDisposable(d)
17+
18+ return {}
19+ }
20+ }
21+ }
22+}
23+
24+function runSource (source, scheduler) {
25+ var disposable = new SettableDisposable()
26+
27+ function event (t) {
28+ return function (x) {
29+ return {}
30+ }
31+ }
32+
33+ function end (t) {
34+ disposable.dispose()
35+ return {}
36+ }
37+
38+ var observer = { event: event, end: end }
39+
40+ var d = source.run(observer)(scheduler)
41+
42+ disposable.setDisposable(d)
43+
44+ return {}
45+}
46+
47+var SettableDisposable = function SettableDisposable () {
48+ this.disposable = void 0
49+ this.disposed = false
50+ this.result = void 0
51+}
52+
53+SettableDisposable.prototype.setDisposable = function setDisposable (disposable) {
54+ this.disposable = disposable
55+
56+ if (this.disposed) {
57+ this.result = disposable.dispose()
58+ }
59+}
60+
61+SettableDisposable.prototype.dispose = function dispose () {
62+ if (this.disposed) {
63+ return this.result
64+ }
65+
66+ this.disposed = true
67+
68+ if (this.disposable !== void 0) {
69+ this.result = this.disposable.dispose()
70+ }
71+
72+ return this.result
73+}
74+
75+exports.fromArray = function (array) {
76+ return function (stream) {
77+ return new FromArray(array, stream)
78+ }
79+}
80+
81+function FromArray (array, stream) {
82+ this.array = array
83+ this.stream = stream
84+}
85+
86+FromArray.prototype.run = function (sink) {
87+ var that = this
88+
89+ return function (scheduler) {
90+ return that.stream.run(new FromArraySink(sink, that.array))(scheduler)
91+ }
92+}
93+
94+function FromArraySink (sink, array) {
95+ this.sink = sink
96+ this.array = array
97+}
98+
99+FromArraySink.prototype.event = function (time) {
100+ var array = this.array
101+ var sink = this.sink
102+ return function (x) {
103+ var value = array.shift()
104+
105+ if (value) {
106+ sink.event(time)(value)
107+ } else {
108+ sink.end(time)
109+ }
110+ }
111+}
112+
113+FromArraySink.prototype.end = function (time) {
114+ this.sink.end(time)
115+}
116+
117+var LinkedList = function LinkedList () {
118+ this.head = null
119+ this.length = 0
120+}
121+
122+LinkedList.prototype.add = function add (x) {
123+ if (this.head !== null) {
124+ this.head.prev = x
125+ x.next = this.head
126+ }
127+ this.head = x
128+ ++this.length
129+}
130+
131+LinkedList.prototype.remove = function remove (x) { // eslint-disable-line complexity
132+ --this.length
133+ if (x === this.head) {
134+ this.head = this.head.next
135+ }
136+ if (x.next !== null) {
137+ x.next.prev = x.prev
138+ x.next = null
139+ }
140+ if (x.prev !== null) {
141+ x.prev.next = x.next
142+ x.prev = null
143+ }
144+}
145+
146+LinkedList.prototype.isEmpty = function isEmpty () {
147+ return this.length === 0
148+}
149+
150+LinkedList.prototype.dispose = function dispose () {
151+ if (this.isEmpty()) { return }
152+
153+ var x = this.head
154+ this.head = null
155+ this.length = 0
156+
157+ while (x !== null) {
158+ x.dispose()
159+ x = x.next
160+ }
161+}
162+
163+exports.chain = function (f) {
164+ return function (stream) {
165+ return mergeMapConcurrently(f)(Infinity)(stream)
166+ }
167+}
168+
169+exports.mergeConcurrently = mergeConcurrently
170+
171+function mergeConcurrently (concurrency) {
172+ return function (stream) {
173+ return mergeMapConcurrently(function (x) { return x })(concurrency)(stream)
174+ }
175+}
176+
177+exports.join = mergeConcurrently(Infinity)
178+
179+exports.mergeMapConcurrently = mergeMapConcurrently
180+
181+function mergeMapConcurrently (f) {
182+ return function (concurrency) {
183+ return function (stream) {
184+ var mstream = new MergeConcurrently(f, concurrency, stream)
185+
186+ mstream.run.bind(mstream)
187+
188+ return mstream
189+ }
190+ }
191+}
192+
193+function MergeConcurrently (f, concurrency, source) {
194+ this.f = f
195+ this.concurrency = concurrency
196+ this.source = source
197+}
198+
199+MergeConcurrently.prototype.run = function run (sink) {
200+ var this$1 = this
201+
202+ return function (scheduler) { return new Outer(this$1.f, this$1.concurrency, this$1.source, sink, scheduler) }
203+}
204+
205+var Outer = function Outer (f, concurrency, source, sink, scheduler) {
206+ this.f = f
207+ this.concurrency = concurrency
208+ this.sink = sink
209+ this.scheduler = scheduler
210+ this.pending = []
211+ this.current = new LinkedList()
212+
213+ var disposed = false
214+ var disposable = source.run(this)(scheduler)
215+
216+ this.disposable = {
217+ dispose: function () {
218+ if (disposed) return
219+
220+ disposed = true
221+ disposable.dispose()
222+ }
223+ }
224+
225+ this.active = true
226+}
227+
228+Outer.prototype.event = function event (t) {
229+ var this$1 = this
230+
231+ return function (x) { return this$1._addInner(t, x) }
232+}
233+
234+Outer.prototype._addInner = function _addInner (t, x) {
235+ if (this.current.length < this.concurrency) {
236+ this._startInner(t, x)
237+ } else {
238+ this.pending.push(x)
239+ }
240+}
241+
242+Outer.prototype._startInner = function _startInner (t, x) {
243+ this._initInner(t, x)
244+}
245+
246+Outer.prototype._initInner = function _initInner (t, x) {
247+ var innerSink = new Inner(t, this, this.sink)
248+ innerSink.disposable = mapAndRun(this.f, x, innerSink, this.scheduler)
249+ this.current.add(innerSink)
250+}
251+
252+Outer.prototype.end = function end (t) {
253+ this.active = false
254+ this.disposable.dispose()
255+ this._checkEnd(t)
256+}
257+
258+Outer.prototype.dispose = function dispose () {
259+ this.active = false
260+ this.pending.length = 0
261+ this.disposable.dispose()
262+ this.current.dispose()
263+}
264+
265+Outer.prototype._endInner = function _endInner (t, inner) {
266+ this.current.remove(inner)
267+ inner.dispose()
268+
269+ if (this.pending.length === 0) {
270+ this._checkEnd(t)
271+ } else {
272+ this._startInner(t, this.pending.shift())
273+ }
274+}
275+
276+Outer.prototype._checkEnd = function _checkEnd (t) {
277+ if (!this.active && this.current.isEmpty()) {
278+ this.sink.end(t)
279+ }
280+}
281+
282+var mapAndRun = function (f, x, sink, scheduler) { return f(x).run(sink)(scheduler) }
283+
284+var Inner = function Inner (time, outer, sink) {
285+ this.prev = this.next = null
286+ this.time = time
287+ this.outer = outer
288+ this.sink = sink
289+ this.disposable = void 0
290+}
291+
292+Inner.prototype.event = function event (t) {
293+ var this$1 = this
294+
295+ return function (x) { return this$1.sink.event(Math.max(t, this$1.time))(x) }
296+}
297+
298+Inner.prototype.end = function end (t) {
299+ this.outer._endInner(Math.max(t, this.time), this)
300+}
301+
302+Inner.prototype.dispose = function dispose () {
303+ return this.disposable.dispose()
304+}
305+
306+exports.switch = function switchLatest (stream) {
307+ return new Switch(stream)
308+}
309+
310+function Switch (source) {
311+ this.source = source
312+}
313+
314+Switch.prototype.run = function (sink) {
315+ var this$1 = this
316+
317+ return function (scheduler) {
318+ var switchSink = new SwitchSink(sink, scheduler)
319+ var disposable = this$1.source.run(switchSink)(scheduler)
320+
321+ return {
322+ dispose: function () {
323+ switchSink.dispose()
324+ disposable.dispose()
325+ }
326+ }
327+ }
328+}
329+
330+function SwitchSink (sink, scheduler) {
331+ this.sink = sink
332+ this.scheduler = scheduler
333+ this.current = null
334+ this.ended = false
335+}
336+
337+SwitchSink.prototype.event = function (t) {
338+ var this$1 = this
339+
340+ return function (stream) {
341+ this$1._disposeCurrent(t) // TODO: capture the result of this dispose
342+ this$1.current = new Segment(t, Infinity, this$1, this$1.sink)
343+ this$1.current.disposable = stream.run(this$1.current)(this$1.scheduler)
344+ }
345+}
346+
347+SwitchSink.prototype.end = function (t, x) {
348+ this.ended = true
349+ this._checkEnd(t, x)
350+}
351+
352+SwitchSink.prototype.dispose = function () {
353+ return this._disposeCurrent(this.scheduler.now())
354+}
355+
356+SwitchSink.prototype._disposeCurrent = function (t) {
357+ if (this.current !== null) {
358+ return this.current._dispose(t)
359+ }
360+}
361+
362+SwitchSink.prototype._disposeInner = function (t, inner) {
363+ inner._dispose(t) // TODO: capture the result of this dispose
364+ if (inner === this.current) {
365+ this.current = null
366+ }
367+}
368+
369+SwitchSink.prototype._checkEnd = function (t, x) {
370+ if (this.ended && this.current === null) {
371+ this.sink.end(t, x)
372+ }
373+}
374+
375+SwitchSink.prototype._endInner = function (t, x, inner) {
376+ this._disposeInner(t, inner)
377+ this._checkEnd(t, x)
378+}
379+
380+function Segment (min, max, outer, sink) {
381+ this.min = min
382+ this.max = max
383+ this.outer = outer
384+ this.sink = sink
385+ this.disposable = { dispose: Function.prototype }
386+}
387+
388+Segment.prototype.event = function (t) {
389+ var this$1 = this
390+
391+ return function (x) {
392+ if (t < this$1.max) {
393+ this$1.sink.event(Math.max(t, this$1.min))(x)
394+ }
395+ }
396+}
397+
398+Segment.prototype.end = function (t, x) {
399+ this.outer._endInner(Math.max(t, this.min), x, this)
400+}
401+
402+Segment.prototype._dispose = function (t) {
403+ this.max = t
404+ this.disposable.dispose()
405+}
406+
407+exports.continueWith = function continueWith (f) {
408+ return function (stream) {
409+ return new ContinueWith(f, stream)
410+ }
411+}
412+
413+function ContinueWith (f, source) {
414+ this.f = f
415+ this.source = source
416+}
417+
418+ContinueWith.prototype.run = function (sink) {
419+ var that = this
420+ return function (scheduler) {
421+ return new ContinueWithSink(that.f, that.source, sink, scheduler)
422+ }
423+}
424+
425+function ContinueWithSink (f, source, sink, scheduler) {
426+ this.f = f
427+ this.sink = sink
428+ this.scheduler = scheduler
429+ this.active = true
430+ this.disposable = source.run(this)(scheduler)
431+}
432+
433+ContinueWithSink.prototype.event = function (t) {
434+ var that = this
435+
436+ return function (x) {
437+ if (!that.active) {
438+ return
439+ }
440+ that.sink.event(t)(x)
441+ }
442+}
443+
444+ContinueWithSink.prototype.end = function (t, x) {
445+ if (!this.active) {
446+ return
447+ }
448+
449+ this.disposable.dispose()
450+
451+ this._startNext(t, x, this.sink)
452+}
453+
454+ContinueWithSink.prototype._startNext = function (t, x, sink) {
455+ try {
456+ this.disposable = this._continue(this.f, x, sink)
457+ } catch (e) {
458+ sink.error(t, e)
459+ }
460+}
461+
462+ContinueWithSink.prototype._continue = function (f, x, sink) {
463+ return f(x).run(sink)(this.scheduler)
464+}
465+
466+ContinueWithSink.prototype.dispose = function () {
467+ this.active = false
468+ return this.disposable.dispose()
469+}
470+
471+exports.combine2 = function (f) { return function (s1) { return function (s2) { return combineArray(f, [s1, s2]) } } }
472+exports.combine3 = function (f) { return function (s1) { return function (s2) { return function (s3) { return combineArray(f, [s1, s2, s3]) } } } }
473+exports.combine4 = function (f) { return function (s1) { return function (s2) { return function (s3) { return function (s4) { return combineArray(f, [s1, s2, s3, s4]) } } } } }
474+exports.combine5 = function (f) { return function (s1) { return function (s2) { return function (s3) { return function (s4) { return function (s5) { return combineArray(f, [s1, s2, s3, s4, s5]) } } } } } }
475+
476+exports.combineArray = function (streams) {
477+ return combineArray(Array, streams)
478+}
479+
480+function combineArray (f, streams) {
481+ return new Combine(f, streams)
482+}
483+
484+function Combine (f, sources) {
485+ this.f = f
486+ this.sources = sources
487+}
488+
489+Combine.prototype.run = function (sink) {
490+ var this$1 = this
491+
492+ return function (scheduler) {
493+ var l = this$1.sources.length
494+ var disposables = new Array(l)
495+ var sinks = new Array(l)
496+
497+ var mergeSink = new CombineSink(disposables, sinks, sink, this$1.f)
498+
499+ for (var indexSink, i = 0; i < l; ++i) {
500+ indexSink = sinks[i] = new IndexSink(i, mergeSink)
501+ disposables[i] = this$1.sources[i].run(indexSink)(scheduler)
502+ }
503+
504+ return {
505+ dispose: function () {
506+ disposables.forEach(function (d) {
507+ d.dispose()
508+ })
509+ }
510+ }
511+ }
512+}
513+
514+function CombineSink (disposables, sinks, sink, f) {
515+ var this$1 = this
516+
517+ this.sink = sink
518+ this.disposables = disposables
519+ this.sinks = sinks
520+ this.f = f
521+
522+ var l = sinks.length
523+ this.awaiting = l
524+ this.values = new Array(l)
525+ this.hasValue = new Array(l)
526+
527+ for (var i = 0; i < l; ++i) {
528+ this$1.hasValue[i] = false
529+ }
530+
531+ this.activeCount = sinks.length
532+}
533+
534+CombineSink.prototype.event = function (t) {
535+ var this$1 = this
536+
537+ return function (indexedValue) {
538+ var i = indexedValue.index
539+ var awaiting = this$1._updateReady(i)
540+
541+ this$1.values[i] = indexedValue.value
542+ if (awaiting === 0) {
543+ var value = tail(this$1.values).reduce(function (f, x) { return f(x) }, this$1.f(this$1.values[0]))
544+ this$1.sink.event(t)(value)
545+ }
546+ }
547+}
548+
549+CombineSink.prototype._updateReady = function (index) {
550+ if (this.awaiting > 0) {
551+ if (!this.hasValue[index]) {
552+ this.hasValue[index] = true
553+ this.awaiting -= 1
554+ }
555+ }
556+ return this.awaiting
557+}
558+
559+CombineSink.prototype.end = function (t, indexedValue) {
560+ this.disposables[indexedValue.index].dispose()
561+
562+ if (--this.activeCount === 0) {
563+ this.sink.end(t)
564+ }
565+}
566+
567+var IndexSink = function IndexSink (i, sink) {
568+ this.sink = sink
569+ this.index = i
570+ this.active = true
571+ this.value = void 0
572+}
573+
574+IndexSink.prototype.event = function event (t) {
575+ var this$1 = this
576+
577+ return function (x) {
578+ if (!this$1.active) { return }
579+
580+ this$1.value = x
581+ this$1.sink.event(t)(this$1)
582+ }
583+}
584+
585+IndexSink.prototype.end = function end (t) {
586+ if (!this.active) { return }
587+
588+ this.active = false
589+ this.sink.end(t, { index: this.index })
590+}
591+
592+function drop (n, a) { // eslint-disable-line complexity
593+ if (n < 0) {
594+ throw new TypeError('n must be >= 0')
595+ }
596+
597+ var l = a.length
598+ if (n === 0 || l === 0) {
599+ return a
600+ }
601+
602+ if (n >= l) {
603+ return []
604+ }
605+
606+ return unsafeDrop(n, a, l - n)
607+}
608+
609+// unsafeDrop :: Int -> [a] -> Int -> [a]
610+// Internal helper for drop
611+function unsafeDrop (n, a, l) {
612+ var b = new Array(l)
613+ for (var i = 0; i < l; ++i) {
614+ b[i] = a[n + i]
615+ }
616+ return b
617+}
618+
619+// tail :: [a] -> [a]
620+// drop head element
621+function tail (a) {
622+ return drop(1, a)
623+}
624+
625+exports.merge = function merge (streams) {
626+ return mergeSources(streams)
627+}
628+
629+/**
630+ * This implements fusion/flattening for merge. It will
631+ * fuse adjacent merge operations. For example:
632+ * - a.merge(b).merge(c) effectively becomes merge(a, b, c)
633+ * - merge(a, merge(b, c)) effectively becomes merge(a, b, c)
634+ * It does this by concatenating the sources arrays of
635+ * any nested Merge sources, in effect "flattening" nested
636+ * merge operations into a single merge.
637+ */
638+function mergeSources (streams) {
639+ return new Merge(reduce(appendSources, [], streams))
640+}
641+
642+function appendSources (sources, stream) {
643+ return stream instanceof Merge
644+ ? sources.concat(stream.sources)
645+ : sources.concat(stream)
646+}
647+
648+function Merge (sources) {
649+ this.sources = sources
650+}
651+
652+Merge.prototype.run = function (sink) {
653+ var this$1 = this
654+
655+ return function (scheduler) {
656+ var l = this.sources.length
657+ var disposables = new Array(l)
658+ var sinks = new Array(l)
659+
660+ var mergeSink = new MergeSink(disposables, sinks, sink)
661+
662+ for (var indexSink, i = 0; i < l; ++i) {
663+ indexSink = sinks[i] = new IndexSink(i, mergeSink)
664+ disposables[i] = this$1.sources[i].run(indexSink, scheduler)
665+ }
666+
667+ return all(disposables)
668+ }
669+}
670+
671+function all (disposables) {
672+ return {
673+ dispose: function () {
674+ disposables.forEach(function (d) {
675+ d.dispose()
676+ })
677+ }
678+ }
679+}
680+
681+function MergeSink (disposables, sinks, sink) {
682+ this.sink = sink
683+ this.disposables = disposables
684+ this.activeCount = sinks.length
685+}
686+
687+MergeSink.prototype.event = function (t) {
688+ var that = this
689+ return function (indexValue) {
690+ that.sink.event(t)(indexValue.value)
691+ }
692+}
693+
694+MergeSink.prototype.end = function (t, indexedValue) {
695+ this.disposables[indexedValue.index].dispose()
696+ if (--this.activeCount === 0) {
697+ this.sink.end(t, indexedValue.value)
698+ }
699+}
700+
701+function reduce (f, z, a) {
702+ var r = z
703+ for (var i = 0, l = a.length; i < l; ++i) {
704+ r = f(r, a[i], i)
705+ }
706+ return r
707+}
708+
709+exports.until = function takeUntil (signal) {
710+ return function (stream) {
711+ return new Until(signal, stream)
712+ }
713+}
714+
715+exports.since = function skipUntil (signal) {
716+ return function (stream) {
717+ return new Since(signal, stream)
718+ }
719+}
720+
721+function Until (maxSignal, source) {
722+ this.maxSignal = maxSignal
723+ this.source = source
724+}
725+
726+Until.prototype.run = function (sink) {
727+ var that = this
728+ return function (scheduler) {
729+ var min = new Bound(-Infinity, sink)
730+ var max = new UpperBound(that.maxSignal, sink, scheduler)
731+ var disposable = that.source.run(new TimeWindowSink(min, max, sink), scheduler)
732+
733+ return all([min, max, disposable])
734+ }
735+}
736+
737+function Since (minSignal, source) {
738+ this.minSignal = minSignal
739+ this.source = source
740+}
741+
742+Since.prototype.run = function (sink) {
743+ var that = this
744+ return function (scheduler) {
745+ var min = new LowerBound(that.minSignal, sink, scheduler)
746+ var max = new Bound(Infinity, sink)
747+ var disposable = that.source.run(new TimeWindowSink(min, max, sink))(scheduler)
748+
749+ return all([min, max, disposable])
750+ }
751+}
752+
753+function Bound (value, sink) {
754+ this.value = value
755+ this.sink = sink
756+}
757+
758+Bound.prototype.event = noop
759+Bound.prototype.end = noop
760+Bound.prototype.dispose = noop
761+
762+function TimeWindowSink (min, max, sink) {
763+ this.min = min
764+ this.max = max
765+ this.sink = sink
766+}
767+
768+TimeWindowSink.prototype.event = function (t, x) {
769+ var that = this
770+ return function (x) {
771+ if (t >= that.min.value && t < that.max.value) {
772+ that.sink.event(t)(x)
773+ }
774+ }
775+}
776+
777+TimeWindowSink.prototype.end = function (time) {
778+ this.sink.end(time)
779+}
780+
781+function LowerBound (signal, sink, scheduler) {
782+ this.value = Infinity
783+ this.sink = sink
784+ this.disposable = signal.run(this)(scheduler)
785+}
786+
787+LowerBound.prototype.event = function (t /*, x */) {
788+ return function () {
789+ if (t < this.value) {
790+ this.value = t
791+ }
792+ }
793+}
794+
795+LowerBound.prototype.end = noop
796+
797+LowerBound.prototype.dispose = function () {
798+ return this.disposable.dispose()
799+}
800+
801+function UpperBound (signal, sink, scheduler) {
802+ this.value = Infinity
803+ this.sink = sink
804+ this.disposable = signal.run(this)(scheduler)
805+}
806+
807+UpperBound.prototype.event = function (t) {
808+ var that = this
809+
810+ return function (x) {
811+ if (t < this.value) {
812+ that.value = t
813+ that.sink.end(t)
814+ }
815+ }
816+}
817+
818+UpperBound.prototype.end = noop
819+
820+UpperBound.prototype.dispose = function () {
821+ return this.disposable.dispose()
822+}
823+
824+function noop () { }
825+
826+exports.throttle = function throttle (period) {
827+ return function (stream) {
828+ return throttleSource(period, stream)
829+ }
830+}
831+
832+function throttleSource (period, source) {
833+ return source instanceof Throttle
834+ ? fuseThrottle(period, source)
835+ : new Throttle(period, source)
836+}
837+
838+function fuseThrottle (period, source) {
839+ return new Throttle(Math.max(period, source.period), source.source)
840+}
841+
842+function Throttle (period, source) {
843+ this.period = period
844+ this.source = source
845+}
846+
847+Throttle.prototype.run = function (sink) {
848+ var that = this
849+ return function (scheduler) {
850+ return that.source.run(new ThrottleSink(that.period, sink), scheduler)
851+ }
852+}
853+
854+function ThrottleSink (period, sink) {
855+ this.time = 0
856+ this.period = period
857+ this.sink = sink
858+}
859+
860+ThrottleSink.prototype.event = function (t) {
861+ var that = this
862+ return function (x) {
863+ if (t >= this.time) {
864+ that.time = t + this.period
865+ that.sink.event(t)(x)
866+ }
867+ }
868+}
869+
870+ThrottleSink.prototype.end = function (t) { this.sink.end(t) }
871+
872+exports.debounce = function debounce (period) {
873+ return function (stream) {
874+ return new Debounce(period, stream)
875+ }
876+}
877+
878+function Debounce (dt, source) {
879+ this.dt = dt
880+ this.source = source
881+}
882+
883+Debounce.prototype.run = function (sink) {
884+ var that = this
885+ return function (scheduler) {
886+ return new DebounceSink(that.dt, that.source, sink, scheduler)
887+ }
888+}
889+
890+function DebounceSink (dt, source, sink, scheduler) {
891+ this.dt = dt
892+ this.sink = sink
893+ this.scheduler = scheduler
894+ this.value = void 0
895+ this.timer = null
896+
897+ var sourceDisposable = source.run(this)(scheduler)
898+ this.disposable = all([this, sourceDisposable])
899+}
900+
901+DebounceSink.prototype.event = function (t) {
902+ var that = this
903+ return function (x) {
904+ that._clearTimer()
905+ that.value = x
906+ var task = ControlStreamScheduler.eventTask(that.sink)(x)
907+ that.timer = this.scheduler.delay(this.dt, task)
908+ }
909+}
910+
911+DebounceSink.prototype.end = function (t, x) {
912+ if (this._clearTimer()) {
913+ this.sink.event(t, this.value)
914+ this.value = void 0
915+ }
916+ this.sink.end(t, x)
917+}
918+
919+DebounceSink.prototype.dispose = function () {
920+ this._clearTimer()
921+}
922+
923+DebounceSink.prototype._clearTimer = function () {
924+ if (this.timer === null) {
925+ return false
926+ }
927+ this.timer.dispose()
928+ this.timer = null
929+ return true
930+}
931+
932+exports.delay = function delay (delayTime) {
933+ return function (stream) {
934+ return delayTime <= 0 ? stream : new Delay(delayTime, stream)
935+ }
936+}
937+
938+function Delay (dt, source) {
939+ this.dt = dt
940+ this.source = source
941+}
942+
943+Delay.prototype.run = function (sink) {
944+ var that = this
945+
946+ return function (scheduler) {
947+ var delaySink = new DelaySink(that.dt, sink, scheduler)
948+ return all([delaySink, that.source.run(delaySink)(scheduler)])
949+ }
950+}
951+
952+function DelaySink (dt, sink, scheduler) {
953+ this.dt = dt
954+ this.sink = sink
955+ this.scheduler = scheduler
956+}
957+
958+DelaySink.prototype.dispose = function () {
959+ var self = this
960+ this.scheduler.cancelAll(function (task) {
961+ return task.sink === self.sink
962+ })
963+}
964+
965+DelaySink.prototype.event = function (t) {
966+ var that = this
967+ return function (x) {
968+ that.scheduler.delay(that.dt)(ControlStreamScheduler.eventTask(that.sink)(x))
969+ }
970+}
971+
972+DelaySink.prototype.end = function (t, x) {
973+ this.scheduler.delay(this.dt)(ControlStreamScheduler.endTask(this.sink))
974+}
975+
976+var MulticastDisposable = function MulticastDisposable (source, sink) {
977+ this.source = source
978+ this.sink = sink
979+ this.disposed = false
980+}
981+
982+MulticastDisposable.prototype.dispose = function dispose () {
983+ if (this.disposed) {
984+ return
985+ }
986+ this.disposed = true
987+ var remaining = this.source.remove(this.sink)
988+ return remaining === 0 && this.source._dispose()
989+}
990+
991+var dispose = function (disposable) { return disposable.dispose() }
992+
993+var emptyDisposable = {
994+ dispose: function dispose$1 () { }
995+}
996+
997+function MulticastSource (source) {
998+ this.source = source
999+ this.sinks = []
1000+ this._disposable = emptyDisposable
1001+}
1002+
1003+MulticastSource.prototype.run = function run (sink) {
1004+ var that = this
1005+ return function (scheduler) {
1006+ var n = that.add(sink)
1007+ if (n === 1) {
1008+ that._disposable = that.source.run(that)(scheduler)
1009+ }
1010+ return new MulticastDisposable(that, sink)
1011+ }
1012+}
1013+
1014+MulticastSource.prototype._dispose = function _dispose () {
1015+ var disposable = this._disposable
1016+ this._disposable = emptyDisposable
1017+ return Promise.resolve(disposable).then(dispose)
1018+}
1019+
1020+MulticastSource.prototype.add = function add (sink) {
1021+ this.sinks = append(sink, this.sinks)
1022+ return this.sinks.length
1023+}
1024+
1025+function append (x, a) {
1026+ var l = a.length
1027+ var b = new Array(l + 1)
1028+ for (var i = 0; i < l; ++i) {
1029+ b[i] = a[i]
1030+ }
1031+
1032+ b[l] = x
1033+ return b
1034+}
1035+
1036+MulticastSource.prototype.remove = function remove$1 (sink) {
1037+ var i = findIndex(sink, this.sinks)
1038+ // istanbul ignore next
1039+ if (i >= 0) {
1040+ this.sinks = remove(i, this.sinks)
1041+ }
1042+
1043+ return this.sinks.length
1044+}
1045+
1046+function findIndex (x, a) {
1047+ for (var i = 0, l = a.length; i < l; ++i) {
1048+ if (x === a[i]) {
1049+ return i
1050+ }
1051+ }
1052+ return -1
1053+}
1054+
1055+function remove (i, a) { // eslint-disable-line complexity
1056+ if (i < 0) {
1057+ throw new TypeError('i must be >= 0')
1058+ }
1059+
1060+ var l = a.length
1061+ if (l === 0 || i >= l) { // exit early if index beyond end of array
1062+ return a
1063+ }
1064+
1065+ if (l === 1) { // exit early if index in bounds and length === 1
1066+ return []
1067+ }
1068+
1069+ return unsafeRemove(i, a, l - 1)
1070+}
1071+
1072+// unsafeRemove :: Int -> [a] -> Int -> [a]
1073+// Internal helper to remove element at index
1074+function unsafeRemove (i, a, l) {
1075+ var b = new Array(l)
1076+ var j
1077+ for (j = 0; j < i; ++j) {
1078+ b[j] = a[j]
1079+ }
1080+ for (j = i; j < l; ++j) {
1081+ b[j] = a[j + 1]
1082+ }
1083+
1084+ return b
1085+}
1086+
1087+MulticastSource.prototype.event = function event (time) {
1088+ var that = this
1089+ return function (value) {
1090+ var s = that.sinks
1091+ if (s.length === 1) {
1092+ return s[0].event(time)(value)
1093+ }
1094+ for (var i = 0; i < s.length; ++i) {
1095+ s[i].event(time)(value)
1096+ }
1097+ }
1098+}
1099+
1100+MulticastSource.prototype.end = function end (time) {
1101+ var s = this.sinks
1102+ for (var i = 0; i < s.length; ++i) {
1103+ s[i].end(time)
1104+ }
1105+}
1106+
1107+MulticastSource.prototype.until = function (signal) {
1108+ return exports.until(signal)(this)
1109+}
1110+
1111+exports.multicast = function multicast (stream) {
1112+ return new MulticastSource(stream)
1113+}
1114+
1115+function __extends (d, b) { // eslint-disable-line complexity
1116+ for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]
1117+ function __ () { this.constructor = d }
1118+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __())
1119+}
1120+
1121+var HoldSubjectSource = (function (_super) {
1122+ __extends(HoldSubjectSource, _super)
1123+ function HoldSubjectSource (source, bufferSize) {
1124+ var _this = _super.call(this, source) || this
1125+ _this.has = false
1126+ _this.buffer = []
1127+ _this.bufferSize = bufferSize
1128+ return _this
1129+ }
1130+ HoldSubjectSource.prototype.add = function (sink) {
1131+ if (this.has) {
1132+ pushEvents(this.buffer, sink)
1133+ }
1134+ return _super.prototype.add.call(this, sink)
1135+ }
1136+ HoldSubjectSource.prototype.event = function (time) {
1137+ var that = this
1138+ return function (value) {
1139+ that.has = true
1140+ that.buffer = dropAndAppend(value, that.buffer, that.bufferSize)
1141+ return _super.prototype.event.call(that, time)(value)
1142+ }
1143+ }
1144+ return HoldSubjectSource
1145+}(MulticastSource))
1146+
1147+function pushEvents (buffer, sink) {
1148+ var length = buffer.length
1149+ for (var i = 0; i < length; ++i) {
1150+ sink.event(ControlStreamScheduler.scheduler.now(), buffer[i])
1151+ }
1152+}
1153+
1154+function dropAndAppend (value, buffer, bufferSize) {
1155+ if (buffer.length === bufferSize) {
1156+ return append(value, drop(1, buffer))
1157+ }
1158+ return append(value, buffer)
1159+}
1160+
1161+exports.hold = function hold (bufferSize) {
1162+ return function (stream) {
1163+ return new HoldSubjectSource(stream, bufferSize)
1164+ }
1165+}
1166+
1167+exports.toSubject = function (stream) {
1168+ return exports.multicast(stream)
1169+}
1170+
1171+exports.toHoldSubject = exports.hold
1172+
1173+exports.fromSubject = function (subject) {
1174+ return subject
1175+}
1176+
1177+exports.subjectEvent = function (value) {
1178+ return function (subject) {
1179+ ControlStreamScheduler.eventTask(subject)(value)
1180+ return subject
1181+ }
1182+}
1183+
1184+exports.subjectEnd = function (value) {
1185+ return function (subject) {
1186+ subject.end(Date.now())
1187+ return subject
1188+ }
1189+}
1190+
1191+exports.proxy = function (value) {
1192+ var stream = new ProxyStream(value)
1193+
1194+ function attach (original) {
1195+ stream.attach(original)
1196+ return original
1197+ }
1198+
1199+ return { attach: attach, stream: stream }
1200+}
1201+
1202+var ProxyStream = (function (_super) {
1203+ __extends(ProxyStream, _super)
1204+ function ProxyStream (value) {
1205+ var _this = _super.call(this, ControlStreamStream.never, 1) || this
1206+ _this.attached = false
1207+ _this.running = false
1208+ _this.buffer.push(value)
1209+ return _this
1210+ }
1211+ ProxyStream.prototype.run = function (sink) {
1212+ var that = this
1213+
1214+ that.add(sink)
1215+
1216+ return function (scheduler) {
1217+ if (that.attached && !that.running) {
1218+ that.running = true
1219+ that._disposable = that.source.run(that)(scheduler)
1220+ return that._disposable
1221+ }
1222+
1223+ return new MulticastDisposable(that, sink)
1224+ }
1225+ }
1226+
1227+ ProxyStream.prototype.attach = function (source) {
1228+ if (this.attached) throw new Error('Can only proxy 1 stream')
1229+ this.attached = true
1230+
1231+ this.source = source
1232+
1233+ if (this.sinks.length) { this._disposable = source.run(this)(ControlStreamScheduler.scheduler) }
1234+ }
1235+
1236+ ProxyStream.prototype.end = function end (time) {
1237+ this.attached = false
1238+ this.running = false
1239+
1240+ return _super.prototype.end.call(this, time)
1241+ }
1242+
1243+ return ProxyStream
1244+}(HoldSubjectSource))
src/Control/Stream/Stream.pursnew file+340
@@ -0,0 +1,340 @@
1+module Control.Stream.Stream
2+ ( STREAM
3+ , EffStream
4+ , Stream(..)
5+ , just
6+ , empty
7+ , never
8+ , periodic
9+ , createCombinator
10+ , createEventCombinator
11+ , createEndCombinator
12+ , drain
13+ , tapEvent
14+ , tapEnd
15+ , fromArray
16+ , filter
17+ , take
18+ , skip
19+ , constant
20+ , continueWith
21+ , concat
22+ , startWith
23+ , scan
24+ , loop
25+ , chain
26+ , mergeConcurrently
27+ , join
28+ , mergeMapConcurrently
29+ , concatMap
30+ , switch
31+ , combine2
32+ , combine3
33+ , combine4
34+ , combine5
35+ , combineArray
36+ , merge
37+ , skipRepeatsWith
38+ , skipRepeats
39+ , until
40+ , since
41+ , during
42+ , sample
43+ , debounce
44+ , throttle
45+ , delay
46+ , multicast
47+ , hold
48+ , Subject
49+ , toSubject
50+ , toHoldSubject
51+ , fromSubject
52+ , subjectEvent
53+ , subjectEnd
54+ , subscribe
55+ ) where
56+
57+import Control.Alternative (class Apply)
58+import Control.Bind (class Bind)
59+import Control.Category (id)
60+import Control.Monad.Eff (Eff, Pure, runPure)
61+import Control.Monad.Eff.Ref (Ref, modifyRef', newRef, readRef)
62+import Control.Monad.Eff.Unsafe (unsafeCoerceEff, unsafePerformEff)
63+import Control.MonadPlus (class Alt, class Alternative, class MonadPlus, class Plus)
64+import Control.MonadZero (class Applicative, class MonadZero)
65+import Control.Stream.Disposable (Disposable, emptyDisposable, disposeAll)
66+import Control.Stream.Scheduler (Scheduler(..), endTask, eventTask, scheduleTasks)
67+import Control.Stream.Sink (Sink(..))
68+import Control.Stream.Stream (Stream(..), EffStream, empty, just)
69+import Control.Stream.Time (Time)
70+import Data.Eq ((==))
71+import Data.EuclideanRing ((-))
72+import Data.Functor (class Functor)
73+import Data.Maybe (Maybe(..), fromJust, isNothing)
74+import Data.Monoid (class Monoid)
75+import Data.Unit (Unit, unit)
76+import Partial.Unsafe (unsafePartial)
77+import Prelude (class Eq, class Monad, class Semigroup, eq)
78+
79+foreign import data STREAM :: !
80+
81+type EffStream e a = Eff (stream :: STREAM | e) a
82+
83+foreign import data Subject :: * -> *
84+
85+newtype Stream a = Stream { run :: Sink a -> Scheduler -> Disposable }
86+
87+instance functorStream :: Functor Stream where
88+ map = mapStream
89+
90+instance applyStream :: Apply Stream where
91+ apply = combine2 id
92+
93+instance applicativeStream :: Applicative Stream where
94+ pure = just
95+
96+instance bindStream :: Bind Stream where
97+ bind = chain
98+
99+instance monadStream :: Monad Stream
100+
101+instance semigroupStream :: Semigroup (Stream a) where
102+ append = concat
103+
104+instance altStream :: Alt Stream where
105+ alt = \s1 s2 -> merge [s1, s2]
106+
107+instance monoidStream :: Monoid (Stream a) where
108+ mempty = empty
109+
110+instance plusStream :: Plus Stream where
111+ empty = empty
112+
113+instance alternativeStream :: Alternative Stream
114+
115+instance monadZeroStream :: MonadZero Stream
116+
117+instance monadPlusStream :: MonadPlus Stream
118+
119+just :: forall a. a -> Stream a
120+just a = Stream { run } where
121+ run :: Sink a -> Scheduler -> Disposable
122+ run sink (Scheduler scheduler) =
123+ scheduleTasks scheduler.asap [ (eventTask sink a), (endTask sink) ]
124+
125+empty :: forall a. Stream a
126+empty = Stream { run } where
127+ run :: Sink a -> Scheduler -> Disposable
128+ run sink (Scheduler scheduler) = scheduleTasks scheduler.asap [ endTask sink ]
129+
130+never :: forall a. Stream a
131+never = Stream { run: \sink scheduler -> emptyDisposable }
132+
133+periodic :: Number -> Stream Unit
134+periodic period = Stream { run } where
135+ run :: Sink Unit -> Scheduler -> Disposable
136+ run sink (Scheduler scheduler) = do
137+ let task = eventTask sink unit
138+ let scheduledTask = scheduler.periodic period task
139+ { dispose : scheduledTask.dispose }
140+
141+createCombinator :: forall a b. (Sink b -> Time -> a -> Unit) -> (Sink b -> Time -> Unit) -> Stream a -> Stream b
142+createCombinator event end (Stream stream) = Stream { run } where
143+ run :: Sink b -> Scheduler -> Disposable
144+ run sink scheduler = stream.run (Sink { event: (event sink), end: (end sink) }) scheduler
145+
146+createEventCombinator :: forall a b. (Sink b -> Time -> a -> Unit) -> Stream a -> Stream b
147+createEventCombinator event stream = createCombinator event end stream where
148+ end (Sink sink) time = sink.end time
149+
150+createEndCombinator :: forall a. (Sink a -> Time -> Unit) -> Stream a -> Stream a
151+createEndCombinator end stream = createCombinator event end stream where
152+ event (Sink sink) time value = sink.event time value
153+
154+tapEvent :: forall e a. (a -> Eff e Unit) -> Stream a -> Stream a
155+tapEvent f stream = createEventCombinator event stream where
156+ event :: Sink a -> Time -> a -> Unit
157+ event (Sink sink) time value = sink.event time (always value (unsafePerformEff (f value)))
158+
159+tapEnd :: forall e a. Eff e Unit -> Stream a -> Stream a
160+tapEnd f stream = createEndCombinator end stream where
161+ end :: Sink a -> Time -> Unit
162+ end (Sink sink) time = sink.end (always time (unsafePerformEff f))
163+
164+take :: forall a. Int -> Stream a -> Stream a
165+take 0 stream = empty
166+take amount (Stream stream) = Stream { run } where
167+ run (Sink sink) scheduler = disposable where
168+ disposable = stream.run (Sink { event, end }) scheduler where
169+ state :: State Int
170+ state = createState amount
171+
172+ event ::Time -> a -> Unit
173+ event time value = do
174+ let amountLeft = (getState state)
175+ if amountLeft == 0
176+ then unit
177+ else do
178+ let newAmountLeft = state.set \x -> x - 1
179+ let x = sink.event time value
180+ if newAmountLeft == 0
181+ then sink.end (always time (runPure disposable.dispose))
182+ else unit
183+
184+ end time = sink.end time
185+
186+skip :: forall a. Int -> Stream a -> Stream a
187+skip 0 stream = stream
188+skip amount stream = createEventCombinator event stream where
189+ state :: State Int
190+ state = createState amount
191+
192+ event :: Sink a -> Time -> a -> Unit
193+ event (Sink sink) time value = do
194+ let amountLeft = runPure state.get
195+ if (amountLeft == 0)
196+ then sink.event time value
197+ else always unit (state.set \x -> x - 1)
198+
199+mapStream :: forall a b. (a -> b) -> Stream a -> Stream b
200+mapStream f stream = createEventCombinator event stream where
201+ event :: Sink b -> Time -> a -> Unit
202+ event (Sink sink) time value = sink.event time (f value)
203+
204+filter :: forall a. (a -> Boolean) -> Stream a -> Stream a
205+filter predicate stream = createEventCombinator event stream where
206+ event (Sink sink) time value = if predicate value
207+ then sink.event time value
208+ else unit
209+
210+skipRepeatsWith :: forall a. (a -> a -> Boolean) -> Stream a -> Stream a
211+skipRepeatsWith compare stream = createEventCombinator event stream where
212+ state :: State (Maybe a)
213+ state = createState Nothing
214+
215+ event (Sink sink) time value = do
216+ let currentState = (getState state)
217+ if (isNothing currentState)
218+ then sink.event time value
219+ else do
220+ let currentValue = unsafePartial (fromJust currentState)
221+ if (compare currentValue value)
222+ then unit
223+ else sink.event time value
224+
225+skipRepeats :: forall a. (Eq a) => Stream a -> Stream a
226+skipRepeats = skipRepeatsWith (eq)
227+
228+constant :: forall a b. b -> Stream a -> Stream b
229+constant b stream = createEventCombinator event stream where
230+ event :: Sink b -> Time -> a -> Unit
231+ event (Sink sink) time value = sink.event time b
232+
233+concat :: forall a. Stream a -> Stream a -> Stream a
234+concat s1 s2 = continueWith(\_ -> s2) s1
235+
236+startWith :: forall a. a -> Stream a -> Stream a
237+startWith seed stream = concat (just seed) stream
238+
239+scan :: forall a b. (b -> a -> b) -> b -> Stream a -> Stream b
240+scan f initial stream = startWith initial (createEventCombinator event stream) where
241+ seed :: State b
242+ seed = createState initial
243+
244+ event :: Sink b -> Time -> a -> Unit
245+ event (Sink sink) time value = sink.event time (seed.set \x -> f x value)
246+
247+loop :: forall a b c. (b -> a -> { seed :: b, value :: c }) -> b -> Stream a -> Stream c
248+loop f initial stream = createEventCombinator event stream where
249+ seed :: State b
250+ seed = createState initial
251+
252+ event :: Sink c -> Time -> a -> Unit
253+ event (Sink sink) time x = do
254+ let seedValue = f (getState seed) x
255+ sink.event time (always seedValue.value (seed.set \_ -> seedValue.seed))
256+
257+concatMap :: forall a b. (a -> Stream b) -> Stream a -> Stream b
258+concatMap f stream = mergeMapConcurrently f 1 stream
259+
260+ap :: forall a b. (Stream (a -> b)) -> Stream a -> Stream b
261+ap fs xs = combine2 (\f x -> f x) fs xs
262+
263+during :: forall a b. Stream (Stream b) -> Stream a -> Stream a
264+during timeWindow stream = until (join timeWindow) (since timeWindow stream)
265+
266+sample :: forall a b c. (a -> b -> c) -> Stream a -> Stream b -> Stream c
267+sample f (Stream sampler) (Stream stream) = Stream { run: runSample (createState Nothing) } where
268+ runSample :: State (Maybe b) -> Sink c -> Scheduler -> Disposable
269+ runSample state sink scheduler = disposeAll
270+ [ stream.run (createHoldSink state) scheduler
271+ , sampler.run (createSampleSink state sink f) scheduler
272+ ]
273+
274+createHoldSink :: forall a. State (Maybe a) -> Sink a
275+createHoldSink state = Sink { event, end } where
276+ event time value = always unit (state.set \_ -> Just value)
277+ end time = unit
278+
279+createSampleSink :: forall a b c. State (Maybe b) -> Sink c -> (a -> b -> c) -> Sink a
280+createSampleSink state (Sink sink) f = Sink { event, end } where
281+ end time = sink.end time
282+ event time value =
283+ if isNothing (runPure state.get)
284+ then unit
285+ else sink.event time (f value (unsafePartial (fromJust (runPure state.get))))
286+
287+sampleWith :: forall a b. Stream b -> Stream a -> Stream a
288+sampleWith signal stream = sample (\_ y -> y) signal stream
289+
290+-- find a better way to perform these side effects
291+always :: forall a b. a -> b -> a
292+always a b = a
293+
294+type State a = { get:: Pure a, set :: (a -> a) -> a }
295+
296+getState :: forall a. State a -> a
297+getState state = runPure state.get
298+
299+createState :: forall a. a -> State a
300+createState seed = { set, get }
301+ where
302+ ref :: Ref a
303+ ref = unsafePerformEff (unsafeCoerceEff (newRef seed))
304+
305+ set :: (a -> a) -> a
306+ set f = unsafePerformEff (unsafeCoerceEff (modifyRef' ref \x -> { state: (f x), value: (f x) }))
307+
308+ get :: Pure a
309+ get = unsafeCoerceEff (readRef ref)
310+
311+foreign import drain :: forall e a. Stream a -> EffStream e Unit
312+foreign import subscribe :: forall e a. (a -> Eff e Unit) -> (Unit -> Eff e Unit) -> Stream a -> EffStream e Unit
313+foreign import fromArray :: forall a b. Array a -> Stream b -> Stream a
314+foreign import chain :: forall a b. Stream a -> (a -> Stream b) -> Stream b
315+foreign import mergeConcurrently :: forall a. Int -> Stream (Stream a) -> Stream a
316+foreign import join :: forall a. Stream (Stream a) -> Stream a
317+foreign import mergeMapConcurrently :: forall a b. (a -> Stream b) -> Int -> Stream a -> Stream b
318+foreign import switch :: forall a. Stream (Stream a) -> Stream a
319+foreign import continueWith :: forall a. (Unit -> Stream a) -> Stream a -> Stream a
320+foreign import combine2 :: forall a b c. (a -> b -> c) -> Stream a -> Stream b -> Stream c
321+foreign import combine3 :: forall a b c d. (a -> b -> c -> d) -> Stream a -> Stream b -> Stream c -> Stream d
322+foreign import combine4 :: forall a b c d e. (a -> b -> c -> d -> e) -> Stream a -> Stream b -> Stream c -> Stream d -> Stream e
323+foreign import combine5 :: forall a b c d e f. (a -> b -> c -> d -> e -> f) -> Stream a -> Stream b -> Stream c -> Stream d -> Stream e -> Stream f
324+foreign import combineArray :: forall a. Array (Stream a) -> Stream (Array a)
325+foreign import merge :: forall a. Array (Stream a) -> Stream a
326+foreign import until :: forall a b. Stream b -> Stream a -> Stream a
327+foreign import since :: forall a b. Stream b -> Stream a -> Stream a
328+foreign import debounce :: forall a. Number -> Stream a -> Stream a
329+foreign import throttle :: forall a. Number -> Stream a -> Stream a
330+foreign import delay :: forall a. Number -> Stream a -> Stream a
331+foreign import multicast :: forall a. Stream a -> Stream a
332+foreign import hold :: forall a. Stream a -> Stream a
333+foreign import proxy :: forall a. a -> { attach :: (Stream a -> Stream a), stream :: Stream a }
334+
335+-- Sad subject types :/
336+foreign import toSubject :: forall a. Stream a -> Subject a
337+foreign import toHoldSubject :: forall a. Int -> Stream a -> Subject a
338+foreign import fromSubject :: forall a. Subject a -> Stream a
339+foreign import subjectEvent :: forall a. a -> Subject a -> Subject a
340+foreign import subjectEnd :: forall a. a -> Subject a -> Subject a
src/Control/Time.pursnew file+3
@@ -0,0 +1,3 @@
1+module Control.Stream.Time where
2+
3+newtype Time = Time Int
test/Main.pursnew file+9
@@ -0,0 +1,9 @@
1+module Test.Main where
2+
3+import Control.Monad.Eff (Eff)
4+import Control.Monad.Eff.Console (CONSOLE, logShow)
5+import Data.Unit (Unit)
6+
7+main :: Eff (console :: CONSOLE) Unit
8+main = do
9+ logShow "Write tests. You're a bad developer!"