Elm.Native.Signal = function(elm) { 'use strict'; elm.Native = elm.Native || {}; if (elm.Native.Signal) return elm.Native.Signal; var Utils = Elm.Native.Utils(elm); var Either = Elm.Either(elm); var foldl1 = Elm.List(elm).foldl1; function send(node, timestep, changed) { var kids = node.kids; for (var i = kids.length; i--; ) { kids[i].recv(timestep, changed, node.id); } } function Input(base) { this.id = Guid.guid(); this.value = base; this.kids = []; this.defaultNumberOfKids = 0; this.recv = function(timestep, eid, v) { var changed = eid === this.id; if (changed) { this.value = v; } send(this, timestep, changed); return changed; }; Dispatcher.inputs.push(this); } function LiftN(update, args) { this.id = Guid.guid(); this.value = update(); this.kids = []; var n = args.length; var count = 0; var isChanged = false; this.recv = function(timestep, changed, parentID) { ++count; if (changed) { isChanged = true; } if (count == n) { if (isChanged) { this.value = update() } send(this, timestep, isChanged); isChanged = false; count = 0; } }; for (var i = n; i--; ) { args[i].kids.push(this); } } function lift(func, a) { function update() { return func(a.value) } return new LiftN(update, [a]); } function lift2(func, a, b) { function update() { return A2( func, a.value, b.value ) } return new LiftN(update, [a,b]); } function lift3(func, a, b, c) { function update() { return A3( func, a.value, b.value, c.value ) } return new LiftN(update, [a,b,c]); } function lift4(func, a, b, c, d) { function update() { return A4( func, a.value, b.value, c.value, d.value ) } return new LiftN(update, [a,b,c,d]); } function lift5(func, a, b, c, d, e) { function update() { return A5( func, a.value, b.value, c.value, d.value, e.value ) } return new LiftN(update, [a,b,c,d,e]); } function lift6(func, a, b, c, d, e, f) { function update() { return A6( func, a.value, b.value, c.value, d.value, e.value, f.value ) } return new LiftN(update, [a,b,c,d,e,f]); } function lift7(func, a, b, c, d, e, f, g) { function update() { return A7( func, a.value, b.value, c.value, d.value, e.value, f.value, g.value ) } return new LiftN(update, [a,b,c,d,e,f,g]); } function lift8(func, a, b, c, d, e, f, g, h) { function update() { return A8( func, a.value, b.value, c.value, d.value, e.value, f.value, g.value, h.value ) } return new LiftN(update, [a,b,c,d,e,f,g,h]); } function foldp(func,state,input) { function update() { state = A2(func, input.value, state); return state } return new LiftN(update, [input]); } function dropIf(pred,base,input) { this.id = Guid.guid(); this.value = pred(input.value) ? base : input.value; this.kids = []; this.recv = function(timestep, changed, parentID) { var chng = changed && !pred(input.value); if (chng) { this.value = input.value; } send(this, timestep, chng); }; input.kids.push(this); } function dropRepeats(input) { this.id = Guid.guid(); this.value = input.value; this.kids = []; this.recv = function(timestep, changed, parentID) { var chng = changed && !Utils.eq(this.value,input.value); if (chng) { this.value = input.value; } send(this, timestep, chng); }; input.kids.push(this); } function dropWhen(s1,b,s2) { var pairs = lift2( F2(function(x,y){return {x:x,y:y}}), s1, s2 ); var dropped = new dropIf(function(p){return p.x},{x:true,y:b},pairs); return lift(function(p){return p.y}, dropped) } function timestamp(a) { function update() { return Utils.Tuple2(Date.now(), a.value) } return new LiftN(update, [a]); } function SampleOn(s1,s2) { this.id = Guid.guid(); this.value = s2.value; this.kids = []; var count = 0; var isChanged = false; this.recv = function(timestep, changed, parentID) { if (parentID === s1.id) isChanged = changed; ++count; if (count == 2) { if (isChanged) { this.value = s2.value; } send(this, timestep, isChanged); count = 0; isChanged = false; } }; s1.kids.push(this); s2.kids.push(this); } function sampleOn(s1,s2) { return new SampleOn(s1,s2) } function delay(t,s) { var delayed = new Input(s.value); var firstEvent = true; function update(v) { if (firstEvent) { firstEvent = false; return; } setTimeout(function() { Dispatcher.notify(delayed.id, v) }, t); } function first(a,b) { return a } return new SampleOn(delayed, lift2(F2(first), delayed, lift(update,s))); } function Merge(s1,s2) { this.id = Guid.guid(); this.value = s1.value; this.kids = []; var next = null; var count = 0; var isChanged = false; this.recv = function(timestep, changed, parentID) { ++count; if (changed) { isChanged = true; if (parentID == s2.id && next === null) { next = s2.value; } if (parentID == s1.id) { next = s1.value; } } if (count == 2) { if (isChanged) { this.value = next; next = null; } send(this, timestep, isChanged); isChanged = false; count = 0; } }; s1.kids.push(this); s2.kids.push(this); } function merge(s1,s2) { return new Merge(s1,s2) } function merges(ss) { return A2(foldl1, F2(merge), ss) } function mergeEither(s1,s2) {return new Merge(A2(lift, Either.Left , s1), A2(lift, Either.Right, s2))} function average(sampleSize, s) { var sample = new Array(sampleSize); var i = sampleSize; while (i--) { sample[i] = 0; } i = 0; var full = false; var total = 0; function f(n) { total += n - sample[i]; sample[i] = n; var avg = total / Math.max(1, full ? sampleSize : i); if (++i == sampleSize) { full = true; i = 0; } return avg; } return lift(f,s);pp } return elm.Native.Signal = { constant : function(v) { return new Input(v); }, lift : F2(lift ), lift2 : F3(lift2), lift3 : F4(lift3), lift4 : F5(lift4), lift5 : F6(lift5), lift6 : F7(lift6), lift7 : F8(lift7), lift8 : F9(lift8), foldp : F3(foldp), delay : delay, merge : F2(merge) merges : merges, mergeEither : F2(mergeEither), average : F2(average), count : function(s) { return foldp(F2(function(x,y) { return x+y }), 0, s) }, countIf : F2(function(pred,s) { return foldp(F2(function(x,c){return pred(x) ? c+1 : c}), 0, s)}), keepIf : F3(function(pred,base,sig) { return new dropIf(function(x) {return !pred(x)},base,sig) }), dropIf : F3(function(pred,base,sig) { return new dropIf(pred,base,sig) }), keepWhen : F3(function(s1,b,s2) { return dropWhen(lift(function(b){return !b;},s1), b, s2) }), dropWhen : F3(dropWhen), dropRepeats : function(s) { return new dropRepeats(s);}, sampleOn : F2(sampleOn), timestamp : timestamp }; };