diff --git a/README.md b/README.md index 7032545..794570d 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,115 @@ Base repository for the [promises-applied](https://github.com/GuildCrafts/web-de ## Description Complete the exercises in the folder `promise-it-wont-hurt-solutions` & `pg-promise-exercises`. Look at the `README.md` file in each folder for instructions. + +# Promises Applied + +## Challenge Rating + +This goal will likely be within your ZPD if you... + +- Are familiar with SQL (the core-sql [goal](https://github.com/GuildCrafts/web-development-js/issues/178) is highly recommended) +- Are familiar with object oriented programming in JavaScript +- Are interested in learning about JavaScript Promises +- Are interested in creating functions which use Promises +- Are interested in learning how to use the `pg-promise` library + +## Description + +A theoritical and practical approach to understanding JavaScript Promises. + +This goal makes heavy use of external resources: the [Promises Course][promises-course] course on [Udacity](https://www.udacity.com/). + +For the first two days you will be working on existing courses and completing tutorials. Then you'll use your skills to complete a set of exercises, and submit your solutions as your artifacts. + +Fork the repo [promises-exercises][promises-exercises] which contains the exercises you need to complete, and make it your artifact. + + +## Context + +JavaScript is an asynchronous programming language, and if you want want to avoid [callback hell](http://callbackhell.com/) you will have to learn to use Promises. + +Promises provide a simpler alternative for executing, composing, and managing asynchronous operations when compared to traditional callback-based approaches. They also allow you to handle asynchronous errors using approaches that are similar to synchronous `try/catch`. + +## Specifications + +Start by forking the [promises-exercises][promises-exercises] repo. Save your work to this repo. + +### Day 1 & 2 + +Complete these sections (including the exercises) of the [Rethinking Asynchronous JavaScript][fem-async-js] on Frontend Masters: +- Parallel vs. Async +- Callback +- Thunks +- Promises + +Complete the [Understanding Promises in JavaScript][treehouse-workshop-promises] workshop (22m). + +Read [this](https://coligo.io/javascript-promises-plain-simple/) blog post and [this](https://scotch.io/tutorials/understanding-javascript-promises-pt-i-background-basics) blog post. + +Make sure to save the exercises from the Frontend Masters course: + +- [x] Callback exercise 1 is completed and saved to a file in your repo. +- [x] Thunks exercise 2 is completed and saved to a file in your repo. +- [x] Promises exercises 3-6 are completed and saved to a file in your repo. + +If you complete the above with time to spare, fill any gaps in your understanding by skimming through the [Promises Course][promises-course] on Udacity. + +### Day 3 & 4 + +Complete exercises 1-13 in the [promise-it-wont-hurt-solutions][promise-it-wont-hurt-solutions]. + +- [x] `src/01-warmup.js` is complete and written to the appropriate file. +- [x] `src/02-fullfill-a-promise.js` is complete and written to the appropriate file. +- [x] `src/03-reject-a-promise.js` is complete and written to the appropriate file. +- [x] `src/04-to-reject-or-not-to-reject.js` is complete and written to the appropriate file. +- [x] `src/05-always-asynchronous.js` is complete and written to the appropriate file. +- [x] `src/06-shortcuts.js` is complete and written to the appropriate file. +- [x] `src/07-promise-after-promise.js` is complete and written to the appropriate file. +- [x] `src/08-values-and-promises.js` is complete and written to the appropriate file. +- [x] `src/09-throw-an-error.js` is complete and written to the appropriate file. _\*see note below_ +- [x] `src/10-an-important-file.js` is complete and written to the appropriate file. _\*see note below_ +- [x] `src/11-multiple-promises.js` is complete and written to the appropriate file. +- [x] `src/12-fetch-json.js` is complete and written to the appropriate file. +- [x] `src/13-do-some-work.js` is complete and written to the appropriate file. + +\*Note: `promise-it-wont-hurt` has a bug which checks the full path of the files, instead of the relative paths. This causes exercise 9 & 10's verify command to fail even though the solution is correct. If the file path is the only error that you are seeing, it means that your code is correct. + +### Day 5 + +Look at the [documentation](https://github.com/vitaly-t/pg-promise/wiki/Learn-by-Example) of the `pg-promise` repository. + +Complete exercises 1-7 in the [pg promise exercises][pg-promise-exercises]. + +- [ ] Exercise 1 is complete. +- [ ] Exercise 2 is complete. +- [ ] Exercise 3 is complete. +- [ ] Exercise 4 is complete. +- [ ] Exercise 5 is complete. +- [ ] Exercise 6 is complete. +- [ ] Exercise 7 is complete. + +### General +- [ ] All package dependencies are properly declared in `package.json`. +- [ ] All major features are added via pull requests with a clear description and concise commit messages. +- [ ] Code uses a linter and there are no linting errors. +- [ ] Variables, functions, files, etc. have appropriate and meaningful names. +- [ ] Functions are small and serve a single purpose. + +### Stretch +- [ ] Read Google's [Introduction](https://developers.google.com/web/fundamentals/getting-started/primers/promises) to Promises + +## Resources +- https://developers.google.com/web/fundamentals/getting-started/primers/promises +- https://coligo.io/javascript-promises-plain-simple/ +- https://scotch.io/tutorials/javascript-promises-for-dummies +- https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html +- https://blog.domenic.me/youre-missing-the-point-of-promises/ +- https://github.com/vitaly-t/pg-promise/wiki/Learn-by-Example + +[promise-it-wont-hurt-solutions]: https://github.com/GuildCrafts/promises-exercises/tree/master/promise-it-wont-hurt-solutions +[promises-course]: https://www.udacity.com/course/javascript-promises--ud898 +[pg-promise-exercises]: https://github.com/GuildCrafts/promises-exercises/tree/master/pg-promise-exercises +[promises-exercises]: https://github.com/GuildCrafts/promises-exercises +[treehouse-workshop-promises]: https://teamtreehouse.com/library/understanding-promises-in-javascript +[fem-async-js]: https://frontendmasters.com/courses/rethinking-async-js/ diff --git a/frontend-masters-exercises/exercises/ex1/README.md b/frontend-masters-exercises/exercises/ex1/README.md new file mode 100755 index 0000000..1208cfc --- /dev/null +++ b/frontend-masters-exercises/exercises/ex1/README.md @@ -0,0 +1,9 @@ +# Instructions + +1. This exercise calls for you to write some async flow-control code. To start off with, you'll use callbacks only. + +2. Expected behavior: + - Request all 3 files at the same time (in "parallel"). + - Render them ASAP (don't just blindly wait for all to finish loading) + - BUT, render them in proper (obvious) order: "file1", "file2", "file3". + - After all 3 are done, output "Complete!". diff --git a/frontend-masters-exercises/exercises/ex1/ex1-fixed.html b/frontend-masters-exercises/exercises/ex1/ex1-fixed.html new file mode 100755 index 0000000..c71f974 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex1/ex1-fixed.html @@ -0,0 +1,13 @@ + + + + +Exercise 1 - Fixed + + +

Exercise 1 - Fixed

+ + + + + diff --git a/frontend-masters-exercises/exercises/ex1/ex1-fixed.js b/frontend-masters-exercises/exercises/ex1/ex1-fixed.js new file mode 100755 index 0000000..99a9065 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex1/ex1-fixed.js @@ -0,0 +1,63 @@ +function fakeAjax(url,cb) { + var fake_responses = { + "file1": "The first text", + "file2": "The middle text", + "file3": "The last text" + }; + var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000; + + console.log("Requesting: " + url); + + setTimeout(function(){ + cb(fake_responses[url]); + },randomDelay); +} + +function output(text) { + console.log(text); +} + +// ************************************** +// The old-n-busted callback way + +function getFile(file) { + fakeAjax(file,function(text){ + fileReceived(file,text); + }); +} + +function fileReceived(file,text) { + // haven't received this text yet? + if (!responses[file]) { + responses[file] = text; + } + + var files = ["file1","file2","file3"]; + + // loop through responses in order for rendering + for (var i=0; i + + + +Exercise 1 + + +

Exercise 1

+ + + + + diff --git a/frontend-masters-exercises/exercises/ex1/ex1.js b/frontend-masters-exercises/exercises/ex1/ex1.js new file mode 100755 index 0000000..3592c41 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex1/ex1.js @@ -0,0 +1,82 @@ +function fakeAjax(url,cb) { + var fake_responses = { + "file1": "The first text", + "file2": "The middle text", + "file3": "The last text" + }; + + var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000; + + console.log("Requesting: " + url); + + setTimeout(function(){ + cb(fake_responses[url]); + },randomDelay); +} + +function output(text) { + console.log(text); +} + +// ************************************** +// The old-n-busted callback way +let first = null +let secondStatus = 0 +let second = null +letthirdStatus = 0 +let third = null + +function getFile(file) { + fakeAjax(file,function(text){ + // what do we do here? + if(file === "file1") { + first = "done" + output(text) + if(secondStatus === 1) { + output(second) + second = "done" + } + if(second === "done" && thirdStatus === 1) { + output(third) + third = "done" + } + } + + if(first !== "done" && file === "file2") { + secondStatus = 1 + second = text + } + + if(first === "done" && file === "file2") { + second = "done" + output(text) + if(thirdStatus === 1) { + output(third) + third = "done" + } + } + + if(second !== "done" && file === "file3") { + thirdStatus = 1 + third = text + } + + if(second === "done" && file === "file3" ) { + third = "done" + output(text) + } + + if(first === "done" && second === "done" && third === "done") { + console.log("Complete!") + } + + }); +} + +// request all files at once in "parallel" +console.log("FILE 1") +getFile("file1"); +console.log("FILE 2") +getFile("file2"); +console.log("FILE 3") +getFile("file3"); diff --git a/frontend-masters-exercises/exercises/ex10/README.md b/frontend-masters-exercises/exercises/ex10/README.md new file mode 100755 index 0000000..c208d37 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex10/README.md @@ -0,0 +1,13 @@ +# Instructions + +1. In this exercise, we're going to practice what we've learned about various async patterns so far, using the challenging "A Tale Of Three Lists" demos. + +2. Study the similarities/differences of the `ui.js` and `feeds.js` files on the repo (https://github.com/getify/a-tale-of-three-lists#compared-patterns), between these versions: "Plain Callbacks", "Thunks", "Promises", and "Promises+Generators". + + Then look at the version of the `ui.js` and `feeds.js` files as included in this exercise, which correspond to the "asynquence Flavored" demo version on the repo. + +3. Pick either reactive sequences or CSP -- whichever you feel most comfortable with or want most practice with -- and modify the `ui.js` and `feeds.js` files to use the appropriate concepts. For reactive sequences, you'll be creating sequences for each type of event and subscribing to them. For CSP, you'll be creating channels for the same. + + If you have time and want a real challenge, try both versions! + +4. Compare your approach to the "Reactive Sequences" and/or "CSP" demo versions on the repo (https://github.com/getify/a-tale-of-three-lists#compared-patterns). diff --git a/frontend-masters-exercises/exercises/ex10/asq.bundle.js b/frontend-masters-exercises/exercises/ex10/asq.bundle.js new file mode 100755 index 0000000..93c9ada --- /dev/null +++ b/frontend-masters-exercises/exercises/ex10/asq.bundle.js @@ -0,0 +1,2333 @@ +/*! asynquence + v0.8.2 (c) Kyle Simpson + MIT License: http://getify.mit-license.org +*/ +!function UMD(e,n,t){"function"==typeof define&&define.amd?define(t):"undefined"!=typeof module&&module.exports?module.exports=t():n[e]=t(e,n)}("ASQ",this,function DEF(e,n){"use strict";function Queue(){function Item(e){this.fn=e,this.next=void 0}var e,n,r;return{add:function $$add(t){r=new Item(t),n?n.next=r:e=r,n=r,r=void 0},drain:function $$drain(){var r=e;for(e=n=t=null;r;)r.fn(),r=r.next}}}function schedule(e){r.add(e),t||(t=u(r.drain))}function tapSequence(e){function trigger(){e.seq=createSequence.apply(h,arguments).defer()}trigger.fail=function $$trigger$fail(){var n=f.call(arguments);e.seq=createSequence(function $$create$sequence(e){e.fail.apply(h,n)}).defer()},e.seq.val(function $$val(){return trigger.apply(h,arguments),c.apply(h,arguments)}).or(function $$or(){trigger.fail.apply(h,arguments)}),e.seq=createSequence(function $$create$sequence(e){trigger=e}).defer()}function createSequence(){function scheduleSequenceTick(){r?sequenceTick():e||(e=schedule(sequenceTick))}function throwSequenceErrors(){throw 1===$.length?$[0]:$}function sequenceTick(){var a,c;if(e=null,delete d.unpause,r)clearTimeout(e),e=null,s.length=p.length=g.length=$.length=0;else if(n)for(0!==p.length||t||(t=!0,throwSequenceErrors());p.length;){t=!0,a=p.shift();try{a.apply(h,$)}catch(i){l(i)?$=$.concat(i):($.push(i),i.stack&&$.push(i.stack)),0===p.length&&throwSequenceErrors()}}else if(u&&s.length>0){u=!1,a=s.shift(),c=g.slice(),g.length=0,c.unshift(createStepCompletion());try{a.apply(h,c)}catch(i){l(i)?$=$.concat(i):$.push(i),n=!0,scheduleSequenceTick()}}}function createStepCompletion(){function done(){n||r||u||(u=!0,g.push.apply(g,arguments),$.length=0,scheduleSequenceTick())}return done.fail=function $$step$fail(){n||r||u||(n=!0,g.length=0,$.push.apply($,arguments),scheduleSequenceTick())},done.abort=function $$step$abort(){n||r||(u=!1,r=!0,g.length=$.length=0,scheduleSequenceTick())},done.errfcb=function $$step$errfcb(e){e?done.fail(e):done.apply(h,f.call(arguments,1))},done}function createGate(e,t,u){function resetGate(){clearTimeout(s),s=d=m=o=null}function scheduleGateTick(){return g?gateTick():void(s||(s=schedule(gateTick)))}function gateTick(){if(!(n||r||$)){var t=[];s=null,p?(e.fail.apply(h,o),resetGate()):g?(e.abort(),resetGate()):checkGate()&&($=!0,d.forEach(function $$each(e,n){t.push(m["s"+n])}),e.apply(h,t),resetGate())}}function checkGate(){if(0!==d.length){var e=!0;return d.some(function $$some(n){return null===n?(e=!1,!0):void 0}),e}}function createSegmentCompletion(){function done(){if(!(n||r||p||g||$||d[e])){var t=c.apply(h,arguments);m["s"+e]=t.length>1?t:t[0],d[e]=!0,scheduleGateTick()}}var e=d.length;return done.fail=function $$segment$fail(){n||r||p||g||$||d[e]||(p=!0,o=f.call(arguments),scheduleGateTick())},done.abort=function $$segment$abort(){n||r||p||g||$||(g=!0,gateTick())},done.errfcb=function $$segment$errfcb(e){e?done.fail(e):done.apply(h,f.call(arguments,1))},d[e]=null,done}var a,i,o,s,p=!1,g=!1,$=!1,d=[],m={};t.some(function $$some(e){if(p||g)return!0;a=u.slice(),a.unshift(createSegmentCompletion());try{e.apply(h,a)}catch(n){return i=n,p=!0,!0}}),i&&(l(i)?e.fail.apply(h,i):e.fail(i))}function then(){return n||r||0===arguments.length?d:(wrapArgs(arguments,thenWrapper).forEach(function $$each(e){i(e)?seq(e):s.push(e)}),scheduleSequenceTick(),d)}function or(){return r||0===arguments.length?d:(p.push.apply(p,arguments),scheduleSequenceTick(),d)}function gate(){if(n||r||0===arguments.length)return d;var e=f.call(arguments).map(function $$map(e){var n;return i(e)?(n={seq:e},tapSequence(n),function $$segment(e){n.seq.pipe(e)}):e});return then(function $$then(n){var t=f.call(arguments,1);createGate(n,e,t)}),d}function pipe(){return r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){then(function $$then(n){e.apply(h,f.call(arguments,1)),n()}).or(e.fail)}),d)}function seq(){return n||r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){var n={seq:e};i(e)&&tapSequence(n),then(function $$then(e){var t=n.seq;i(t)||(t=n.seq.apply(h,f.call(arguments,1))),t.pipe(e)})}),d)}function val(){return n||r||0===arguments.length?d:(f.call(wrapArgs(arguments,valWrapper)).forEach(function $$each(e){then(function $$then(n){var t=e.apply(h,f.call(arguments,1));l(t)||(t=c(t)),n.apply(h,t)})}),d)}function promise(){function wrap(e){return function $$fn(){e.apply(h,l(arguments[0])?arguments[0]:arguments)}}return n||r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){then(function $$then(n){var t=e;"function"==typeof e&&"function"!=typeof e.then&&(t=e.apply(h,f.call(arguments,1))),t.then(wrap(n),wrap(n.fail))})}),d)}function fork(){var e;return val(function $$val(){return e?e.apply(h,arguments):e=createSequence.apply(h,arguments).defer(),c.apply(h,arguments)}),or(function $$or(){if(e)e.fail.apply(h,arguments);else{var n=f.call(arguments);e=createSequence().then(function $$then(e){e.fail.apply(h,n)}).defer()}}),createSequence().then(function $$then(n){e?e.pipe(n):e=n}).defer()}function abort(){return n?d:(r=!0,sequenceTick(),d)}function duplicate(){var e;return a={then_queue:s.slice(),or_queue:p.slice()},e=createSequence(),a=null,e}function unpause(){g.push.apply(g,arguments),e===!0&&(e=null),scheduleSequenceTick()}function defer(){return p.push(function ignored(){}),d}function internals(e,t){var a=arguments.length>1;switch(e){case"seq_error":if(!a)return n;n=t;break;case"seq_aborted":if(!a)return r;r=t;break;case"then_ready":if(!a)return u;u=t;break;case"then_queue":return s;case"or_queue":return p;case"sequence_messages":return g;case"sequence_errors":return $}}function includeExtensions(){Object.keys(o).forEach(function $$each(e){d[e]=o[e](d,internals)})}var e,n=!1,t=!1,r=!1,u=!0,s=[],p=[],g=[],$=[],d=brandIt({then:then,or:or,onerror:or,gate:gate,all:gate,pipe:pipe,seq:seq,val:val,promise:promise,fork:fork,abort:abort,duplicate:duplicate,defer:defer});return includeExtensions(),a&&(s=a.then_queue.slice(),p=a.or_queue.slice(),d.unpause=unpause,e=!0),d.then.apply(h,arguments),d}function brandIt(e){return Object.defineProperty(e,p,{enumerable:!1,value:!0})}function checkBranding(e){return!(null==e||"object"!=typeof e||!e[p])}function valWrapper(e){return c.apply(h,f.call(arguments).slice(1,e+1))}function thenWrapper(e){arguments[e+1].apply(h,f.call(arguments).slice(1,e+1))}function wrapArgs(e,n){var t,r;for(e=f.call(e),t=0;t 1 ? + ARRAY_SLICE.call(arguments,1) : + void 0 + ; + num = +num || 0; + + api.then(function $$then(done){ + var args = orig_args || ARRAY_SLICE.call(arguments,1); + + setTimeout(function $$set$timeout(){ + done.apply(ø,args); + },num); + }); + + return api; + }; +}); + +ASQ.after = function $$after() { + return ASQ().after.apply(ø,arguments); +}; +// "any" +ASQ.extend("any",function $$extend(api,internals){ + return function $$any() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages.length = 0; + } + + function complete(trigger) { + if (success_messages.length > 0) { + // any successful segment's message(s) sent + // to main sequence to proceed as success + success_messages.length = fns.length; + trigger.apply(ø,success_messages); + } + else { + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + success_messages = [], + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "errfcb" +ASQ.extend("errfcb",function $$extend(api,internals){ + return function $$errfcb() { + // create a fake sequence to extract the callbacks + var sq = { + val: function $$then(cb){ sq.val_cb = cb; return sq; }, + or: function $$or(cb){ sq.or_cb = cb; return sq; } + }; + + // trick `seq(..)`s checks for a sequence + sq[brand] = true; + + // immediately register our fake sequence on the + // main sequence + api.seq(sq); + + // provide the "error-first" callback + return function $$errorfirst$callback(err) { + if (err) { + sq.or_cb(err); + } + else { + sq.val_cb.apply(ø,ARRAY_SLICE.call(arguments,1)); + } + }; + }; +}); +// "failAfter" +ASQ.extend("failAfter",function $$extend(api,internals){ + return function $$failAfter(num) { + var args = arguments.length > 1 ? + ARRAY_SLICE.call(arguments,1) : + void 0 + ; + num = +num || 0; + + api.then(function $$then(done){ + setTimeout(function $$set$timeout(){ + done.fail.apply(ø,args); + },num); + }); + + return api; + }; +}); + +ASQ.failAfter = function $$fail$after() { + return ASQ().failAfter.apply(ø,arguments); +}; +// "first" +ASQ.extend("first",function $$extend(api,internals){ + return function $$first() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + error_messages.length = 0; + } + + function success(trigger,idx,args) { + if (!finished) { + finished = true; + + // first successful segment triggers + // main sequence to proceed as success + trigger( + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ); + + reset(); + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete without success? + if (completed === fns.length) { + finished = true; + + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + + reset(); + } + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "go-style CSP" +(function IIFE(){ + + // filter out already-resolved queue entries + function filterResolved(queue) { + return queue.filter(function $$filter(entry){ + return !entry.resolved; + }); + } + + function closeQueue(queue,finalValue) { + queue.forEach(function $$each(iter){ + if (!iter.resolved) { + iter.next(); + iter.next(finalValue); + } + }); + queue.length = 0; + } + + function channel(bufSize) { + var ch = { + close: function $$close(){ + ch.closed = true; + closeQueue(ch.put_queue,false); + closeQueue(ch.take_queue,ASQ.csp.CLOSED); + }, + closed: false, + messages: [], + put_queue: [], + take_queue: [], + buffer_size: +bufSize || 0 + }; + return ch; + } + + function unblock(iter) { + if (iter && !iter.resolved) { + iter.next(iter.next().value); + } + } + + function put(channel,value) { + var ret; + + if (channel.closed) { + return false; + } + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + // immediate put? + if (channel.messages.length < channel.buffer_size) { + channel.messages.push(value); + unblock(channel.take_queue.shift()); + return true; + } + // queued put + else { + channel.put_queue.push( + // make a notifiable iterable for 'put' blocking + ASQ.iterable() + .then(function $$then(){ + if (!channel.closed) { + channel.messages.push(value); + return true; + } + else { + return false; + } + }) + ); + + // wrap a sequence/promise around the iterable + ret = ASQ( + channel.put_queue[channel.put_queue.length - 1] + ); + + // take waiting on this queued put? + if (channel.take_queue.length > 0) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + + return ret; + } + } + + function putAsync(channel,value,cb) { + var ret = ASQ(put(channel,value)); + + if (cb && typeof cb == "function") { + ret.val(cb); + } + else { + return ret; + } + } + + function take(channel) { + var ret; + + try { + ret = takem(channel); + } + catch (err) { + ret = err; + } + + if (ASQ.isSequence(ret)) { + ret.pCatch(function $$pcatch(err){ + return err; + }); + } + + return ret; + } + + function takeAsync(channel,cb) { + var ret = ASQ(take(channel)); + + if (cb && typeof cb == "function") { + ret.val(cb); + } + else { + return ret; + } + } + + function takem(channel) { + var msg; + + if (channel.closed) { + return ASQ.csp.CLOSED; + } + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + // immediate take? + if (channel.messages.length > 0) { + msg = channel.messages.shift(); + unblock(channel.put_queue.shift()); + if (msg instanceof Error) { + throw msg; + } + return msg; + } + // queued take + else { + channel.take_queue.push( + // make a notifiable iterable for 'take' blocking + ASQ.iterable() + .then(function $$then(){ + if (!channel.closed) { + var v = channel.messages.shift(); + if (v instanceof Error) { + throw v; + } + return v; + } + else { + return ASQ.csp.CLOSED; + } + }) + ); + + // wrap a sequence/promise around the iterable + msg = ASQ( + channel.take_queue[channel.take_queue.length - 1] + ); + + // put waiting on this take? + if (channel.put_queue.length > 0) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + + return msg; + } + } + + function takemAsync(channel,cb) { + var ret = ASQ(takem(channel)); + + if (cb && typeof cb == "function") { + ret.pThen(cb,cb); + } + else { + return ret.val(function $$val(v){ + if (v instanceof Error) { + throw v; + } + return v; + }); + } + } + + function alts(actions) { + var closed, open, handlers, i, isq, ret, resolved = false; + + // used `alts(..)` incorrectly? + if (!Array.isArray(actions) || actions.length == 0) { + throw Error("Invalid usage"); + } + + closed = []; + open = []; + handlers = []; + + // separate actions by open/closed channel status + actions.forEach(function $$each(action){ + var channel = Array.isArray(action) ? action[0] : action; + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + if (channel.closed) { + closed.push(channel); + } + else { + open.push(action); + } + }); + + // if no channels are still open, we're done + if (open.length == 0) { + return { value: ASQ.csp.CLOSED, channel: closed }; + } + + // can any channel action be executed immediately? + for (i=0; i 0) { + return { value: take(open[i]), channel: open[i] }; + } + } + + isq = ASQ.iterable(); + var ret = ASQ(isq); + + // setup channel action handlers + for (i=0; i 0) { + schedule(function handleUnblocking(){ + if (!resolved) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + },0); + } + } + // take action? + else { + channel = action; + + // define take handler + handlers.push( + ASQ.iterable() + .then(function $$then(){ + resolved = true; + + // mark all handlers across this `alts(..)` as resolved now + handlers = handlers.filter(function $$filter(handler){ + return !(handler.resolved = true); + }); + + // channel still open? + if (!channel.closed) { + isq.next({ value: channel.messages.shift(), channel: channel }); + } + // channel already closed? + else { + isq.next({ value: ASQ.csp.CLOSED, channel: channel }); + } + }) + ); + + // queue up take handler + channel.take_queue.push(handlers[handlers.length-1]); + + // put waiting on this queued take? + if (channel.put_queue.length > 0) { + schedule(function handleUnblocking(){ + if (!resolved) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + }); + } + } + })(open[i]); + } + + return ret; + } + + function altsAsync(chans,cb) { + var ret = ASQ(alts(chans)); + + if (cb && typeof cb == "function") { + ret.pThen(cb,cb); + } + else { + return ret; + } + } + + function timeout(delay) { + var ch = channel(); + setTimeout(ch.close,delay); + return ch; + } + + function go(gen,args) { + // goroutine arguments passed? + if (arguments.length > 1) { + if (!args || !Array.isArray(args)) { + args = [args]; + } + } + else { + args = []; + } + + return function *$$go(token) { + + // unblock the overall goroutine handling + function unblock() { + token.unblock_count++; + + if (token.block && !token.block.marked) { + token.block.marked = true; + token.block.next(); + } + } + + var ret, msg, err, type, done = false, it; + + // keep track of how many requests for unblocking + // have occurred + token.unblock_count = (token.unblock_count || 0); + + // keep track of how many goroutines are running + // so we can infer when we're done go'ing + token.go_count = (token.go_count || 0) + 1; + + // need to initialize a set of goroutines? + if (token.go_count === 1) { + // create a default channel for these goroutines + token.channel = channel(); + token.channel.messages = token.messages; + token.channel.go = function $$go(){ + // unblock the goroutine handling for this + // new goroutine + unblock(); + // add the goroutine (called with any args) to + // the handling queue + token.add( go.apply(ø,arguments) ); + }; + // starting out with initial channel messages? + if (token.channel.messages.length > 0) { + // fake back-pressure blocking for each + token.channel.put_queue = token.channel.messages.map(function $$map(){ + // make a notifiable iterable for 'put' blocking + return ASQ.iterable() + .then(function $$then(){ + unblock(token.channel.take_queue.shift()); + return !token.channel.closed; + }); + }); + } + } + + // initialize the generator + it = gen.apply(ø,[token.channel].concat(args)); + + (function iterate(){ + + function next() { + // keep going with next step in goroutine? + if (!done) { + iterate(); + } + // unblock overall goroutine handling to + // continue with other goroutines + else { + unblock(); + } + } + + // has a resumption value been achieved yet? + if (!ret) { + // try to resume the goroutine + try { + // resume with injected exception? + if (err) { + ret = it.throw(err); + err = null; + } + // resume normally + else { + ret = it.next(msg); + } + } + // resumption failed, so bail + catch (e) { + done = true; + err = e; + msg = null; + unblock(); + return; + } + + // keep track of the result of the resumption + done = ret.done; + ret = ret.value; + type = typeof ret; + + // if this goroutine is complete, unblock the + // overall goroutine handling + if (done) { + unblock(); + } + + // received a thenable/promise back? + if (isPromise(ret)) { + ret = ASQ().promise(ret); + } + + // wait for the value? + if (ASQ.isSequence(ret)) { + ret.val(function $$val(){ + ret = null; + msg = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + next(); + }) + .or(function $$or(){ + ret = null; + msg = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + if (msg instanceof Error) { + err = msg; + msg = null; + } + next(); + }); + } + // immediate value, prepare it to go right back in + else { + msg = ret; + ret = null; + next(); + } + } + })(); + + // keep this goroutine alive until completion + while (!done) { + // transfer control to another goroutine + yield token; + + // need to block overall goroutine handling + // while idle? + if (!done && !token.block && token.unblock_count === 0) { + // wait here while idle + yield (token.block = ASQ.iterable()); + + token.block = false; + } + + if (token.unblock_count > 0) token.unblock_count--; + } + + // this goroutine is done now + token.go_count--; + + // all goroutines done? + if (token.go_count === 0) { + // any lingering blocking need to be cleaned up? + unblock(); + + // capture any untaken messages + msg = ASQ.messages.apply(ø,token.messages); + + // need to implicitly force-close channel? + if (token.channel && !token.channel.closed) { + token.channel.closed = true; + token.channel.put_queue.length = token.channel.take_queue.length = 0; + token.channel.close = token.channel.go = token.channel.messages = null; + } + token.channel = null; + } + + // make sure leftover error or message are + // passed along + if (err) { + throw err; + } + else if (token.go_count === 0) { + return msg; + } + else { + return token; + } + }; + } + + ASQ.csp = { + chan: channel, + put: put, + putAsync: putAsync, + take: take, + takeAsync: takeAsync, + takem: takem, + takemAsync: takemAsync, + alts: alts, + altsAsync: altsAsync, + timeout: timeout, + go: go, + CLOSED: {} + }; + +})(); +// "ASQ.iterable()" +(function IIFE(){ + var template; + + ASQ.iterable = function $$iterable() { + function throwSequenceErrors() { + throw (sequence_errors.length === 1 ? sequence_errors[0] : sequence_errors); + } + + function notifyErrors() { + var fn; + + seq_tick = null; + + if (seq_error) { + if (or_queue.length === 0 && !error_reported) { + error_reported = true; + throwSequenceErrors(); + } + + while (or_queue.length > 0) { + error_reported = true; + fn = or_queue.shift(); + try { + fn.apply(ø,sequence_errors); + } + catch (err) { + if (checkBranding(err)) { + sequence_errors = sequence_errors.concat(err); + } + else { + sequence_errors.push(err); + } + if (or_queue.length === 0) { + throwSequenceErrors(); + } + } + } + } + } + + function val() { + if (seq_error || seq_aborted || arguments.length === 0) { + return sequence_api; + } + + var args = ARRAY_SLICE.call(arguments).map(function mapper(arg){ + if (typeof arg != "function") return function $$val() { return arg; }; + else return arg; + }); + + val_queue.push.apply(val_queue,args); + + return sequence_api; + } + + function or() { + if (seq_aborted || arguments.length === 0) { + return sequence_api; + } + + or_queue.push.apply(or_queue,arguments); + + if (!seq_tick) { + seq_tick = schedule(notifyErrors); + } + + return sequence_api; + } + + function pipe() { + if (seq_aborted || arguments.length === 0) { + return sequence_api; + } + + ARRAY_SLICE.call(arguments) + .forEach(function $$each(fn){ + val(fn).or(fn.fail); + }); + + return sequence_api; + } + + function next() { + if (seq_error || seq_aborted || val_queue.length === 0) { + if (val_queue.length > 0) { + $throw$("Sequence cannot be iterated"); + } + return { done: true }; + } + + try { + return { value: val_queue.shift().apply(ø,arguments) }; + } + catch (err) { + if (ASQ.isMessageWrapper(err)) { + $throw$.apply(ø,err); + } + else { + $throw$(err); + } + + return {}; + } + } + + function $throw$() { + if (seq_error || seq_aborted) { + return sequence_api; + } + + sequence_errors.push.apply(sequence_errors,arguments); + seq_error = true; + if (!seq_tick) { + seq_tick = schedule(notifyErrors); + } + + return sequence_api; + } + + function $return$(val) { + if (seq_error || seq_aborted) { + val = void 0; + } + + abort(); + + return { done: true, value: val }; + } + + function abort() { + if (seq_error || seq_aborted) { + return; + } + + seq_aborted = true; + + clearTimeout(seq_tick); + seq_tick = null; + val_queue.length = or_queue.length = sequence_errors.length = 0; + } + + function duplicate() { + var isq; + + template = { + val_queue: val_queue.slice(), + or_queue: or_queue.slice() + }; + isq = ASQ.iterable(); + template = null; + + return isq; + } + + // opt-out of global error reporting for this sequence + function defer() { + or_queue.push(function $$ignored(){}); + return sequence_api; + } + + // *********************************************** + // Object branding utilities + // *********************************************** + function brandIt(obj) { + Object.defineProperty(obj,brand,{ + enumerable: false, + value: true + }); + + return obj; + } + + var sequence_api, + + seq_error = false, + error_reported = false, + seq_aborted = false, + + seq_tick, + + val_queue = [], + or_queue = [], + + sequence_errors = [] + ; + + // *********************************************** + // Setup the ASQ.iterable() public API + // *********************************************** + sequence_api = brandIt({ + val: val, + then: val, + or: or, + pipe: pipe, + next: next, + "throw": $throw$, + "return": $return$, + abort: abort, + duplicate: duplicate, + defer: defer + }); + + // useful for ES6 `for..of` loops, + // add `@@iterator` to simply hand back + // our iterable sequence itself! + sequence_api[(typeof Symbol == "function" && Symbol.iterator) || "@@iterator"] = function $$iter() { + return sequence_api; + }; + + // templating the iterable-sequence setup? + if (template) { + val_queue = template.val_queue.slice(0); + or_queue = template.or_queue.slice(0); + } + + // treat ASQ.iterable() constructor parameters as having been + // passed to `val()` + sequence_api.val.apply(ø,arguments); + + return sequence_api; + }; + +})(); +// "last" +ASQ.extend("last",function $$extend(api,internals){ + return function $$last() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages = null; + } + + function complete(trigger) { + if (success_messages != null) { + // last successful segment's message(s) sent + // to main sequence to proceed as success + trigger( + success_messages.length > 1 ? + ASQ.messages.apply(ø,success_messages) : + success_messages[0] + ); + } + else { + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages = args; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)), + success_messages + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "map" +ASQ.extend("map",function $$extend(api,internals){ + return function $$map(pArr,pEach) { + if (internals("seq_error") || internals("seq_aborted")) { + return api; + } + + api.seq(function $$seq(){ + var tmp, args = ARRAY_SLICE.call(arguments), + arr = pArr, each = pEach; + + // if missing `map(..)` args, use value-messages (if any) + if (!each) each = args.shift(); + if (!arr) arr = args.shift(); + + // if arg types in reverse order (each,arr), swap + if (typeof arr === "function" && Array.isArray(each)) { + tmp = arr; + arr = each; + each = tmp; + } + + return ASQ.apply(ø,args) + .gate.apply(ø,arr.map(function $$map(item){ + return function $$segment(){ + each.apply(ø,[item].concat(ARRAY_SLICE.call(arguments))); + }; + })); + }) + .val(function $$val(){ + // collect all gate segment output into one value-message + // Note: return a normal array here, not a message wrapper! + return ARRAY_SLICE.call(arguments); + }); + + return api; + }; +}); +// "none" +ASQ.extend("none",function $$extend(api,internals){ + return function $$none() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages.length = 0; + } + + function complete(trigger) { + if (success_messages.length > 0) { + // any successful segment's message(s) sent + // to main sequence to proceed as **error** + success_messages.length = fns.length; + trigger.fail.apply(ø,success_messages); + } + else { + // send errors as **success** to main sequence + error_messages.length = fns.length; + trigger.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)), + success_messages = [] + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "pThen" +ASQ.extend("pThen",function $$extend(api,internals){ + return function $$pthen(success,failure) { + if (internals("seq_aborted")) { + return api; + } + + var ignore_success_handler = false, ignore_failure_handler = false; + + if (typeof success === "function") { + api.then(function $$then(done){ + if (!ignore_success_handler) { + var ret, msgs = ASQ.messages.apply(ø,arguments); + msgs.shift(); + + if (msgs.length === 1) { + msgs = msgs[0]; + } + + ignore_failure_handler = true; + + try { + ret = success(msgs); + } + catch (err) { + if (!ASQ.isMessageWrapper(err)) { + err = [err]; + } + done.fail.apply(ø,err); + return; + } + + // returned a sequence? + if (ASQ.isSequence(ret)) { + ret.pipe(done); + } + // returned a message wrapper? + else if (ASQ.isMessageWrapper(ret)) { + done.apply(ø,ret); + } + // returned a promise/thenable? + else if (isPromise(ret)) { + ret.then(done,done.fail); + } + // just a normal value to pass along + else { + done(ret); + } + } + else { + done.apply(ø,ARRAY_SLICE.call(arguments,1)); + } + }); + } + if (typeof failure === "function") { + api.or(function $$or(){ + if (!ignore_failure_handler) { + var ret, msgs = ASQ.messages.apply(ø,arguments), smgs, + or_queue = ARRAY_SLICE.call(internals("or_queue")) + ; + + if (msgs.length === 1) { + msgs = msgs[0]; + } + + ignore_success_handler = true; + + // NOTE: if this call throws, that'll automatically + // be handled by core as we'd want it to be + ret = failure(msgs); + + // if we get this far: + // first, inject return value (if any) as + // next step's sequence messages + smgs = internals("sequence_messages"); + smgs.length = 0; + if (typeof ret !== "undefined") { + if (!ASQ.isMessageWrapper(ret)) { + ret = [ret]; + } + smgs.push.apply(smgs,ret); + } + + // reset internal error state, because we've exclusively + // handled any errors up to this point of the sequence + internals("sequence_errors").length = 0; + internals("seq_error",false); + internals("then_ready",true); + + // temporarily empty the or-queue + internals("or_queue").length = 0; + + // make sure to schedule success-procession on the chain + api.val(function $$val(){ + // pass thru messages + return ASQ.messages.apply(ø,arguments); + }); + + // at next cycle, reinstate the or-queue (if any) + if (or_queue.length > 0) { + schedule(function $$schedule(){ + api.or.apply(ø,or_queue); + }); + } + } + }); + } + return api; + }; +}); + +// "pCatch" +ASQ.extend("pCatch",function $$extend(api,internals){ + return function $$pcatch(failure) { + if (internals("seq_aborted")) { + return api; + } + + api.pThen(void 0,failure); + + return api; + }; +}); +// "race" +ASQ.extend("race",function $$extend(api,internals){ + return function $$race() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(v){ + var def; + // tap any directly-provided sequences immediately + if (ASQ.isSequence(v)) { + def = { seq: v }; + tapSequence(def); + return function $$fn(done) { + def.seq.pipe(done); + }; + } + else return v; + }); + + api.then(function $$then(done){ + var args = ARRAY_SLICE.call(arguments); + + fns.forEach(function $$each(fn){ + fn.apply(ø,args); + }); + }); + + return api; + }; +}); +// "react" (reactive sequences) +ASQ.react = function $$react(reactor) { + function next() { + if (!paused) { + if (template) { + var sq = template.duplicate(); + sq.unpause.apply(ø,arguments); + return sq; + } + return ASQ(function $$asq(){ throw "Disabled Sequence"; }); + } + } + + function registerTeardown(fn) { + if (template && typeof fn === "function") { + teardowns.push(fn); + } + } + + var template = ASQ().duplicate(), + teardowns = [], paused = false + ; + + // add reactive sequence kill switch + template.stop = function $$stop() { + if (template) { + template = null; + teardowns.forEach(Function.call,Function.call); + teardowns.length = 0; + } + }; + + template.pause = function $$pause() { + if (!paused && template) { + paused = true; + teardowns.forEach(Function.call,Function.call); + teardowns.length = 0; + } + }; + + template.resume = function $$resume() { + if (paused && template) { + paused = false; + reactor.call(template,next,registerTeardown); + } + }; + + template.push = next; + + next.onStream = function $$onStream() { + ARRAY_SLICE.call(arguments) + .forEach(function $$each(stream){ + stream.on("data",next); + stream.on("error",next); + }); + }; + + next.unStream = function $$unStream() { + ARRAY_SLICE.call(arguments) + .forEach(function $$each(stream){ + stream.removeListener("data",next); + stream.removeListener("error",next); + }); + }; + + // make sure `reactor(..)` is called async + ASQ.__schedule(function $$schedule(){ + reactor.call(template,next,registerTeardown); + }); + + return template; +}; +// "react" helpers +(function IIFE(){ + + var Ar = ASQ.react; + + Ar.of = function $$react$of() { + function reactor(next) { + if (!started) { + started = true; + if (args.length > 0) { + args.shift().val(function val(){ + next.apply(ø,arguments); + if (args.length > 0) { + args.shift().val(val); + } + }); + } + } + } + + var started, args = ARRAY_SLICE.call(arguments) + .map(function wrapper(arg){ + if (!ASQ.isSequence(arg)) arg = ASQ(arg); + return arg; + }); + + return Ar(reactor); + }; + + Ar.all = Ar.zip = makeReactOperator(/*buffer=*/true); + Ar.allLatest = makeReactOperator(/*buffer=false*/); + Ar.latest = Ar.combineLatest = makeReactOperator(/*buffer=*/false,/*keep=*/true); + + Ar.any = Ar.merge = function $$react$any(){ + function reactor(next,registerTeardown){ + function processSequence(def){ + function trigger(){ + var args = ASQ.messages.apply(ø,arguments); + // still observing sequence-streams? + if (seqs && seqs.length > 0) { + // fire off reactive sequence instance + next.apply(ø,args); + } + // keep sequence going + return args; + } + + // sequence-stream event listener + def.seq.val(trigger); + } + + // observe all sequence-streams + seqs.forEach(processSequence); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + seqs = null; + }); + } + + // observe all sequence-streams + var seqs = tapSequences.apply(null,arguments); + + if (seqs.length == 0) return; + + return Ar(reactor); + }; + + Ar.distinct = function $$react$distinct(seq){ + return Ar.filter(seq,makeDistinctFilterer(/*keepAll=*/true)); + }; + + Ar.distinctConsecutive = Ar.distinctUntilChanged = function $$react$distinct$consecutive(seq) { + return Ar.filter(seq,makeDistinctFilterer(/*keepAll=*/false)); + }; + + Ar.filter = function $$react$filter(seq,filterer){ + function reactor(next,registerTeardown) { + function trigger(){ + var messages = ASQ.messages.apply(ø,arguments); + + if (filterer && filterer.apply(ø,messages)) { + // fire off reactive sequence instance + next.apply(ø,messages); + } + + // keep sequence going + return messages; + } + + // sequence-stream event listener + def.seq.val(trigger); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + def = filterer = null; + }); + } + + // observe sequence-stream + var def = tapSequences(seq)[0]; + + if (!def) return; + + return Ar(reactor); + }; + + Ar.fromObservable = function $$react$from$observable(obsv){ + function reactor(next,registerTeardown){ + // process buffer (if any) + buffer.forEach(next); + buffer.length = 0; + + // start non-buffered notifications? + if (!buffer.complete) { + notify = next; + } + + registerTeardown(function $$teardown(){ + obsv.dispose(); + }); + } + + function notify(v) { + buffer.push(v); + } + + var buffer = []; + + obsv.subscribe( + function $$on$next(v){ + notify(v); + }, + function $$on$error(){}, + function $$on$complete(){ + buffer.complete = true; + obsv.dispose(); + } + ); + + return Ar(reactor); + }; + + ASQ.extend("toObservable",function $$extend(api,internals){ + return function $$to$observable(){ + function init(observer) { + function define(pair){ + function listen(){ + var args = ASQ.messages.apply(ø,arguments); + observer[pair[1]].apply(observer, + args.length == 1 ? [args[0]] : args + ); + return args; + } + + api[pair[0]](listen); + } + + [["val","onNext"],["or","onError"]] + .forEach(define); + } + + return Rx.Observable.create(init); + }; + }); + + function tapSequences() { + function tapSequence(seq) { + // temporary `trigger` which, if called before being replaced + // below, creates replacement proxy sequence with the + // event message(s) re-fired + function trigger() { + var args = ARRAY_SLICE.call(arguments); + def.seq = Ar(function $$react(next){ + next.apply(ø,args); + }); + } + + if (ASQ.isSequence(seq)) { + var def = { seq: seq }; + + // listen for events from the sequence-stream + seq.val(function $$val(){ + trigger.apply(ø,arguments); + return ASQ.messages.apply(ø,arguments); + }); + + // make a reactive sequence to act as a proxy to the original + // sequence + def.seq = Ar(function $$react(next){ + // replace the temporary trigger (created above) + // with this proxy's trigger + trigger = next; + }); + + return def; + } + } + + return ARRAY_SLICE.call(arguments) + .map(tapSequence) + .filter(Boolean); + } + + function makeReactOperator(buffer,keep) { + return function $$react$operator(){ + function reactor(next,registerTeardown){ + function processSequence(def) { + // sequence-stream event listener + function trigger() { + var args = ASQ.messages.apply(ø,arguments); + // still observing sequence-streams? + if (seqs && seqs.length > 0) { + // store event message(s), if any + seq_events[seq_id] = + (buffer ? seq_events[seq_id] : []).concat( + args.length > 0 ? (args.length > 1 ? [args] : args[0]) : undefined + ); + + // collect event message(s) across the + // sequence-stream sources + var messages = seq_events.reduce(function reducer(msgs,eventList,idx){ + if (eventList.length > 0) msgs.push(eventList[0]); + return msgs; + },[]); + + // did all sequence-streams get an event? + if (messages.length == seq_events.length) { + if (messages.length == 1) messages = messages[0]; + + // fire off reactive sequence instance + next.apply(ø,messages); + + // discard stored event message(s)? + if (!keep) { + seq_events.forEach(function $$each(eventList){ + eventList.shift(); + }); + } + } + } + // keep sequence going + return args; + } + + var seq_id = seq_events.length; + seq_events.push([]); + def.seq.val(trigger); + } + + // process all sequence-streams + seqs.forEach(processSequence); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + seqs = seq_events = null; + }); + } + + var seq_events = [], + // observe all sequence-streams + seqs = tapSequences.apply(null,arguments) + ; + + if (seqs.length == 0) return; + + return Ar(reactor); + }; + } + + function makeDistinctFilterer(keepAll) { + function filterer() { + function isDuplicate(msgSet) { + return ( + msgSet.length == message_set.length && + msgSet.every(function $$every(val,idx){ + return val === message_set[idx]; + }) + ); + } + + var message_set = ASQ.messages.apply(ø,arguments); + + // any messages in message-set to check against? + if (message_set.length > 0) { + // duplicate message-set? + if (msg_sets.some(isDuplicate)) { + return false; + } + + // remember all message-sets for future distinct checking? + if (keepAll) { + msg_sets.push(message_set); + } + // only keep the last message-set for distinct-consecutive + // checking + else { + msg_sets[0] = message_set; + } + } + + // allow distinct non-duplicate value through + return true; + } + + var msg_sets = []; + + return filterer; + } + +})(); +// "runner" +ASQ.extend("runner",function $$extend(api,internals){ + + return function $$runner() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var args = ARRAY_SLICE.call(arguments); + + api + .then(function $$then(mainDone){ + + function wrap(v) { + // function? expected to produce an iterator + // (like a generator) or a promise + if (typeof v === "function") { + // call function passing in the control token + // note: neutralize `this` in call to prevent + // unexpected behavior + v = v.call(ø,token); + + // promise returned (ie, from async function)? + if (isPromise(v)) { + // wrap it in iterable sequence + v = ASQ.iterable(v); + } + } + // an iterable sequence? duplicate it (in case of multiple runs) + else if (ASQ.isSequence(v) && "next" in v) { + v = v.duplicate(); + } + // wrap anything else in iterable sequence + else { + v = ASQ.iterable(v); + } + + // a sequence to tap for errors? + if (ASQ.isSequence(v)) { + // listen for any sequence failures + v.or(function $$or(){ + // signal iteration-error + mainDone.fail.apply(ø,arguments); + }); + } + + return v; + } + + function addWrapped() { + iterators.push.apply( + iterators, + ARRAY_SLICE.call(arguments).map(wrap) + ); + } + + function iterateOrQuit(iterFn,now) { + // still have some co-routine runs to process? + if (iterators.length > 0) { + if (now) iterFn(); + else schedule(iterFn); + } + // all done! + else { + // previous value message? + if (typeof next_val !== "undefined") { + // not a message wrapper array? + if (!ASQ.isMessageWrapper(next_val)) { + // wrap value for the subsequent `apply(..)` + next_val = [next_val]; + } + } + else { + // nothing to affirmatively pass along + next_val = []; + } + + // signal done with all co-routine runs + mainDone.apply(ø,next_val); + } + } + + var iterators = args, + token = { + messages: ARRAY_SLICE.call(arguments,1), + add: addWrapped + }, + iter, ret, next_val = token + ; + + // map co-routines to round-robin list of iterators + iterators = iterators.map(wrap); + + // async iteration of round-robin list + (function iterate(){ + // get next co-routine in list + iter = iterators.shift(); + + // process the iteration + try { + // multiple messages to send to an iterable + // sequence? + if (ASQ.isMessageWrapper(next_val) && + ASQ.isSequence(iter) + ) { + ret = iter.next.apply(iter,next_val); + } + else { + ret = iter.next(next_val); + } + } + catch (err) { + return mainDone.fail(err); + } + + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + // was the control token yielded? + if (ret.value === token) { + // round-robin: put co-routine back into the list + // at the end where it was so it can be processed + // again on next loop-iteration + if (!ret.done) { + iterators.push(iter); + } + next_val = token; + iterateOrQuit(iterate,/*now=*/false); + } + else { + // not a recognized ASQ instance returned? + if (!ASQ.isSequence(ret.value)) { + // received a thenable/promise back? + if (isPromise(ret.value)) { + // wrap in a sequence + ret.value = ASQ().promise(ret.value); + } + // thunk yielded? + else if (typeof ret.value === "function") { + // wrap thunk call in a sequence + var fn = ret.value; + ret.value = ASQ(function $$ASQ(done){ + fn(done.errfcb); + }); + } + // message wrapper returned? + else if (ASQ.isMessageWrapper(ret.value)) { + // wrap message(s) in a sequence + ret.value = ASQ.apply(ø, + // don't let `apply(..)` discard an empty message + // wrapper! instead, pass it along as its own value + // itself. + ret.value.length > 0 ? ret.value : ASQ.messages(undefined) + ); + } + // non-undefined value returned? + else if (typeof ret.value !== "undefined") { + // wrap the value in a sequence + ret.value = ASQ(ret.value); + } + else { + // make an empty sequence + ret.value = ASQ(); + } + } + + ret.value + .val(function $$val(){ + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + if (arguments.length > 0) { + // save any return messages for input + // to next iteration + next_val = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + } + + // still more to iterate? + if (!ret.done) { + // was the control token passed along? + if (next_val === token) { + // round-robin: put co-routine back into the list + // at the end, so that the the next iterator can be + // processed on next loop-iteration + iterators.push(iter); + } + else { + // put co-routine back in where it just + // was so it can be processed again on + // next loop-iteration + iterators.unshift(iter); + } + } + + iterateOrQuit(iterate,/*now=*/true); + }) + .or(function $$or(){ + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + try { + // if an error occurs in the step-continuation + // promise or sequence, throw it back into the + // generator or iterable-sequence + iter["throw"].apply(iter,arguments); + } + catch (err) { + // if an error comes back out of after the throw, + // pass it out to the main sequence, as iteration + // must now be complete + mainDone.fail(err); + } + }); + } + })(); + }); + + return api; + }; +}); +// "toPromise" +ASQ.extend("toPromise",function $$extend(api,internals){ + return function $$to$promise() { + return new Promise(function $$executor(resolve,reject){ + api + .val(function $$val(){ + var args = ARRAY_SLICE.call(arguments); + resolve.call(ø,args.length > 1 ? args : args[0]); + return ASQ.messages.apply(ø,args); + }) + .or(function $$or(){ + var args = ARRAY_SLICE.call(arguments); + reject.call(ø,args.length > 1 ? args : args[0]); + }); + }); + }; +}); +// "try" +ASQ.extend("try",function $$extend(api,internals){ + return function $$try() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(fn){ + return function $$then(mainDone) { + var main_args = ARRAY_SLICE.call(arguments), + sq = ASQ.apply(ø,main_args.slice(1)) + ; + + sq + .then(function $$inner$then(){ + fn.apply(ø,arguments); + }) + .val(function $$val(){ + mainDone.apply(ø,arguments); + }) + .or(function $$inner$or(){ + var msgs = ASQ.messages.apply(ø,arguments); + // failed, so map error(s) as `catch` + mainDone({ + "catch": msgs.length > 1 ? msgs : msgs[0] + }); + }); + }; + }); + + api.then.apply(ø,fns); + + return api; + }; +}); +// "until" +ASQ.extend("until",function $$extend(api,internals){ + return function $$until() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(fn){ + return function $$then(mainDone) { + var main_args = ARRAY_SLICE.call(arguments), + sq = ASQ.apply(ø,main_args.slice(1)) + ; + + sq + .then(function $$inner$then(){ + var args = ARRAY_SLICE.call(arguments); + args[0]["break"] = function $$break(){ + mainDone.fail.apply(ø,arguments); + sq.abort(); + }; + + fn.apply(ø,args); + }) + .val(function $$val(){ + mainDone.apply(ø,arguments); + }) + .or(function $$inner$or(){ + // failed, retry + $$then.apply(ø,main_args); + }); + }; + }); + + api.then.apply(ø,fns); + + return api; + }; +}); +// "waterfall" +ASQ.extend("waterfall",function $$extend(api,internals){ + return function $$waterfall() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + var msgs = ASQ.messages(), + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + fns.forEach(function $$each(fn){ + sq.then(fn) + .val(function $$val(){ + var args = ASQ.messages.apply(ø,arguments); + msgs.push(args.length > 1 ? args : args[0]); + return msgs; + }); + }); + + sq.pipe(done); + }); + + return api; + }; +}); +// "wrap" +ASQ.wrap = function $$wrap(fn,opts) { + function checkThis(t,o) { + return (!t || + (typeof window != "undefined" && t === window) || + (typeof global != "undefined" && t === global) + ) ? o : t; + } + + function paramSpread(gen) { + return function *paramSpread(token) { + yield *gen.apply(this,token.messages); + }; + } + + var errfcb, params_first, act, this_obj; + + opts = (opts && typeof opts == "object") ? opts : {}; + + if ( + (opts.errfcb && opts.splitcb) || + (opts.errfcb && opts.simplecb) || + (opts.splitcb && opts.simplecb) || + ("errfcb" in opts && !opts.errfcb && !opts.splitcb && !opts.simplecb) || + (opts.params_first && opts.params_last) || + (opts.spread && !opts.gen) + ) { + throw Error("Invalid options"); + } + + // initialize default flags + this_obj = (opts["this"] && typeof opts["this"] == "object") ? opts["this"] : ø; + errfcb = opts.errfcb || !(opts.splitcb || opts.simplecb); + params_first = !!opts.params_first || + (!opts.params_last && !("params_first" in opts || opts.params_first)) || + ("params_last" in opts && !opts.params_first && !opts.params_last) + ; + + if (params_first) { + act = "push"; + } + else { + act = "unshift"; + } + + if (opts.gen) { + if (opts.spread) { + fn = paramSpread(fn); + } + return function $$wrapped$gen() { + return ASQ.apply(ø,arguments).runner(fn); + }; + } + if (errfcb) { + return function $$wrapped$errfcb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done.errfcb); + fn.apply(_this,args); + }); + }; + } + if (opts.splitcb) { + return function $$wrapped$splitcb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done,done.fail); + fn.apply(_this,args); + }); + }; + } + if (opts.simplecb) { + return function $$wrapped$simplecb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done); + fn.apply(_this,args); + }); + }; + } +}; + + + // just return `ASQ` itself for convenience sake + return ASQ; +}); diff --git a/frontend-masters-exercises/exercises/ex10/dummy-data.js b/frontend-masters-exercises/exercises/ex10/dummy-data.js new file mode 100755 index 0000000..31c2a85 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex10/dummy-data.js @@ -0,0 +1,16 @@ +var ItemsText = (function(){ + + var words = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent vulputate consectetur sem sed efficitur. Nulla ac egestas velit. Cras elementum orci vel sodales dapibus. Etiam tempus ac mi eu elementum. Proin nibh lorem, luctus eget dolor eget, sollicitudin pharetra velit. Quisque scelerisque libero ut elit consectetur, vel placerat diam finibus. Vestibulum vitae velit eget orci mattis bibendum id sed nibh. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam bibendum nibh at nisi ullamcorper euismod. Phasellus sed varius metus. Nullam pretium ex id augue ultricies condimentum. Nunc nisl arcu, placerat quis condimentum in, consequat vel lectus. Pellentesque ullamcorper sed enim quis congue. Pellentesque et elit in dui fermentum tempor. Praesent enim quam, viverra sed ipsum non, iaculis aliquet libero. Maecenas quis egestas sem. Sed sit amet malesuada turpis. Nam tempor velit at nisi lacinia, at vestibulum dolor bibendum. Sed venenatis in eros quis blandit. Maecenas nec aliquet ex, at accumsan quam. Vestibulum semper, libero ac rhoncus facilisis, augue diam interdum ex, in eleifend turpis lorem euismod sem. Vivamus sit amet ipsum et nunc dignissim tincidunt vel eget risus. Sed et nunc tempus, cursus ante eget, egestas quam. Integer turpis nulla, rutrum a nunc non, maximus malesuada massa. Suspendisse vel egestas felis. Donec vehicula neque augue, sit amet mattis nulla pellentesque eu. Vestibulum gravida malesuada rhoncus. Curabitur rhoncus diam nunc, non dignissim risus ultrices at. Cras id ligula mattis, scelerisque diam nec, sagittis nibh. Quisque malesuada ipsum at magna molestie, ac ultricies ante consectetur. Vivamus turpis neque, faucibus et molestie vulputate, dictum at diam. Ut et massa vitae neque ultricies rutrum. Donec aliquet elementum tincidunt. In viverra sem ante, vel imperdiet nisi facilisis non. Nunc interdum, urna at tempor semper, sapien justo feugiat nisl, condimentum finibus metus nibh in diam. Aliquam erat volutpat. Maecenas ut felis euismod, vehicula augue ut, aliquet lorem. Suspendisse iaculis, magna nec ullamcorper rhoncus, sapien ex pellentesque odio, ut interdum ante sapien eu erat. Donec quam orci, aliquet eu varius in, tincidunt eu est. Proin vitae est a lectus congue laoreet. Vestibulum id sodales mauris. Vestibulum eu lacus a felis tempus fringilla eu et nunc. Curabitur et imperdiet enim. Vivamus sollicitudin efficitur risus hendrerit euismod. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nam sed auctor velit, sit amet facilisis nunc. Donec vestibulum convallis neque sed eleifend. Cras dapibus quis sem id sodales. Maecenas metus massa, facilisis quis scelerisque vel, commodo molestie enim. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Maecenas pulvinar ultrices nulla, vel convallis ex laoreet vel. Sed ornare dui eget ante luctus, mollis vehicula neque pulvinar. Nulla posuere, quam quis dapibus rutrum, arcu massa laoreet metus, at condimentum felis justo a est. Nullam pharetra est nunc, a accumsan metus pellentesque ut. Duis auctor justo sit amet tincidunt iaculis. Pellentesque sollicitudin mauris ut ligula suscipit sagittis. Nullam scelerisque tortor sed sem egestas, non auctor nulla fermentum. Aliquam ut nunc condimentum, pellentesque quam feugiat, lacinia elit. Fusce maximus nulla id justo efficitur, congue imperdiet purus feugiat. Pellentesque egestas ultrices tempus. Vestibulum interdum accumsan nulla quis ornare. Duis cursus vel ipsum nec mattis. Donec quam eros, convallis condimentum iaculis a, egestas id tellus. Nullam imperdiet velit sed purus porta, vitae vulputate elit vulputate. Vivamus in maximus libero. Etiam condimentum hendrerit bibendum. Morbi id urna eu erat placerat iaculis. Donec a vehicula purus, a tempus lacus. Mauris quis auctor metus. Maecenas id venenatis libero, nec faucibus est. Sed auctor scelerisque augue, vel efficitur sem sollicitudin quis. Aliquam non justo eu diam convallis posuere. Quisque consequat porta nulla. Nunc lacinia, eros pulvinar dictum mattis, justo lorem finibus nibh, non pellentesque justo metus vitae ligula. Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus ac interdum lorem, in elementum mi. Suspendisse auctor ex eget efficitur porta. Nam mollis lectus a ipsum gravida, eget hendrerit metus blandit. Suspendisse potenti. Quisque aliquet augue ut facilisis porttitor. Ut dui felis, interdum vitae lectus sit amet, consequat accumsan felis. Etiam malesuada ipsum vitae lacinia condimentum. Aliquam ac turpis eu risus tincidunt molestie. Sed ac leo libero. Quisque rutrum lacus sit amet augue eleifend sollicitudin. Nulla facilisi. Praesent egestas tortor et nibh rutrum accumsan. Suspendisse potenti. Proin vehicula massa id pretium aliquet. Nunc sed euismod justo, a ullamcorper odio. In ullamcorper diam ut leo pellentesque, at sollicitudin dolor suscipit. Interdum et malesuada fames ac ante ipsum primis in faucibus. Proin felis leo, mollis ut eros ut, dapibus imperdiet diam. Donec iaculis placerat ante, ac commodo nibh luctus id. Suspendisse iaculis feugiat massa quis vehicula. Mauris consequat finibus posuere. Aenean non turpis et quam luctus mattis a id enim. Ut ullamcorper, felis et ultricies lobortis, velit tellus mattis justo, a malesuada odio turpis at nisl. In sed augue maximus, bibendum tellus nec, maximus sapien. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut sem lorem, rhoncus a congue a, tempor nec metus. Suspendisse potenti. Curabitur ultrices pretium odio, et sollicitudin mauris vehicula in. Aenean sed semper neque, vitae lobortis lectus. In id interdum velit. Duis tempus purus diam, vitae tincidunt lacus commodo egestas. Morbi vestibulum, magna eget sollicitudin efficitur, ex libero consectetur odio, sollicitudin tincidunt mauris ante ac velit. Mauris a augue lacus. In bibendum, dui a pellentesque sagittis, tortor risus dignissim enim, eu tristique velit odio sit amet ex. Cras eros leo, convallis sit amet posuere vel, lacinia at enim. Maecenas nec feugiat ipsum. Nunc pellentesque tortor vitae mauris dictum imperdiet. Phasellus porttitor lectus vel neque sollicitudin, nec commodo leo faucibus. Aliquam dignissim ut est in vulputate. Donec ultrices, ex ac molestie porta, ligula sem efficitur velit, at pretium nisl tellus vel nisi. Sed volutpat nisi sed risus vulputate efficitur. Praesent venenatis nisl quis diam condimentum aliquet. Vestibulum et turpis tincidunt, pharetra urna id, egestas diam. Aliquam vitae gravida enim, eu scelerisque dolor. Nunc placerat vitae nisi eget commodo. In tincidunt viverra pellentesque. Duis a lacinia felis. Sed pharetra nibh eget diam finibus, a euismod ipsum placerat."; + + return { + more: function() { + var start = Math.trunc( Math.random() * 1E9 ) % + (words.length - 200); + var text = words.substr(start).match( + /(?:^|(?:\.\s+))((?:[A-Z][^\.]+\.(?:\s+|$)){3})/ + ); + return text ? text[0].replace(/^\.\s+/,"") : next(); + } + }; + +})(); diff --git a/frontend-masters-exercises/exercises/ex10/eventemitter2.js b/frontend-masters-exercises/exercises/ex10/eventemitter2.js new file mode 100755 index 0000000..bde69e8 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex10/eventemitter2.js @@ -0,0 +1,573 @@ +/*! + * EventEmitter2 + * https://github.com/hij1nx/EventEmitter2 + * + * Copyright (c) 2013 hij1nx + * Licensed under the MIT license. + */ +;!function(undefined) { + + var isArray = Array.isArray ? Array.isArray : function _isArray(obj) { + return Object.prototype.toString.call(obj) === "[object Array]"; + }; + var defaultMaxListeners = 10; + + function init() { + this._events = {}; + if (this._conf) { + configure.call(this, this._conf); + } + } + + function configure(conf) { + if (conf) { + + this._conf = conf; + + conf.delimiter && (this.delimiter = conf.delimiter); + conf.maxListeners && (this._events.maxListeners = conf.maxListeners); + conf.wildcard && (this.wildcard = conf.wildcard); + conf.newListener && (this.newListener = conf.newListener); + + if (this.wildcard) { + this.listenerTree = {}; + } + } + } + + function EventEmitter(conf) { + this._events = {}; + this.newListener = false; + configure.call(this, conf); + } + + // + // Attention, function return type now is array, always ! + // It has zero elements if no any matches found and one or more + // elements (leafs) if there are matches + // + function searchListenerTree(handlers, type, tree, i) { + if (!tree) { + return []; + } + var listeners=[], leaf, len, branch, xTree, xxTree, isolatedBranch, endReached, + typeLength = type.length, currentType = type[i], nextType = type[i+1]; + if (i === typeLength && tree._listeners) { + // + // If at the end of the event(s) list and the tree has listeners + // invoke those listeners. + // + if (typeof tree._listeners === 'function') { + handlers && handlers.push(tree._listeners); + return [tree]; + } else { + for (leaf = 0, len = tree._listeners.length; leaf < len; leaf++) { + handlers && handlers.push(tree._listeners[leaf]); + } + return [tree]; + } + } + + if ((currentType === '*' || currentType === '**') || tree[currentType]) { + // + // If the event emitted is '*' at this part + // or there is a concrete match at this patch + // + if (currentType === '*') { + for (branch in tree) { + if (branch !== '_listeners' && tree.hasOwnProperty(branch)) { + listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+1)); + } + } + return listeners; + } else if(currentType === '**') { + endReached = (i+1 === typeLength || (i+2 === typeLength && nextType === '*')); + if(endReached && tree._listeners) { + // The next element has a _listeners, add it to the handlers. + listeners = listeners.concat(searchListenerTree(handlers, type, tree, typeLength)); + } + + for (branch in tree) { + if (branch !== '_listeners' && tree.hasOwnProperty(branch)) { + if(branch === '*' || branch === '**') { + if(tree[branch]._listeners && !endReached) { + listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], typeLength)); + } + listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i)); + } else if(branch === nextType) { + listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+2)); + } else { + // No match on this one, shift into the tree but not in the type array. + listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i)); + } + } + } + return listeners; + } + + listeners = listeners.concat(searchListenerTree(handlers, type, tree[currentType], i+1)); + } + + xTree = tree['*']; + if (xTree) { + // + // If the listener tree will allow any match for this part, + // then recursively explore all branches of the tree + // + searchListenerTree(handlers, type, xTree, i+1); + } + + xxTree = tree['**']; + if(xxTree) { + if(i < typeLength) { + if(xxTree._listeners) { + // If we have a listener on a '**', it will catch all, so add its handler. + searchListenerTree(handlers, type, xxTree, typeLength); + } + + // Build arrays of matching next branches and others. + for(branch in xxTree) { + if(branch !== '_listeners' && xxTree.hasOwnProperty(branch)) { + if(branch === nextType) { + // We know the next element will match, so jump twice. + searchListenerTree(handlers, type, xxTree[branch], i+2); + } else if(branch === currentType) { + // Current node matches, move into the tree. + searchListenerTree(handlers, type, xxTree[branch], i+1); + } else { + isolatedBranch = {}; + isolatedBranch[branch] = xxTree[branch]; + searchListenerTree(handlers, type, { '**': isolatedBranch }, i+1); + } + } + } + } else if(xxTree._listeners) { + // We have reached the end and still on a '**' + searchListenerTree(handlers, type, xxTree, typeLength); + } else if(xxTree['*'] && xxTree['*']._listeners) { + searchListenerTree(handlers, type, xxTree['*'], typeLength); + } + } + + return listeners; + } + + function growListenerTree(type, listener) { + + type = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); + + // + // Looks for two consecutive '**', if so, don't add the event at all. + // + for(var i = 0, len = type.length; i+1 < len; i++) { + if(type[i] === '**' && type[i+1] === '**') { + return; + } + } + + var tree = this.listenerTree; + var name = type.shift(); + + while (name) { + + if (!tree[name]) { + tree[name] = {}; + } + + tree = tree[name]; + + if (type.length === 0) { + + if (!tree._listeners) { + tree._listeners = listener; + } + else if(typeof tree._listeners === 'function') { + tree._listeners = [tree._listeners, listener]; + } + else if (isArray(tree._listeners)) { + + tree._listeners.push(listener); + + if (!tree._listeners.warned) { + + var m = defaultMaxListeners; + + if (typeof this._events.maxListeners !== 'undefined') { + m = this._events.maxListeners; + } + + if (m > 0 && tree._listeners.length > m) { + + tree._listeners.warned = true; + console.error('(node) warning: possible EventEmitter memory ' + + 'leak detected. %d listeners added. ' + + 'Use emitter.setMaxListeners() to increase limit.', + tree._listeners.length); + console.trace(); + } + } + } + return true; + } + name = type.shift(); + } + return true; + } + + // By default EventEmitters will print a warning if more than + // 10 listeners are added to it. This is a useful default which + // helps finding memory leaks. + // + // Obviously not all Emitters should be limited to 10. This function allows + // that to be increased. Set to zero for unlimited. + + EventEmitter.prototype.delimiter = '.'; + + EventEmitter.prototype.setMaxListeners = function(n) { + this._events || init.call(this); + this._events.maxListeners = n; + if (!this._conf) this._conf = {}; + this._conf.maxListeners = n; + }; + + EventEmitter.prototype.event = ''; + + EventEmitter.prototype.once = function(event, fn) { + this.many(event, 1, fn); + return this; + }; + + EventEmitter.prototype.many = function(event, ttl, fn) { + var self = this; + + if (typeof fn !== 'function') { + throw new Error('many only accepts instances of Function'); + } + + function listener() { + if (--ttl === 0) { + self.off(event, listener); + } + fn.apply(this, arguments); + } + + listener._origin = fn; + + this.on(event, listener); + + return self; + }; + + EventEmitter.prototype.emit = function() { + + this._events || init.call(this); + + var type = arguments[0]; + + if (type === 'newListener' && !this.newListener) { + if (!this._events.newListener) { return false; } + } + + // Loop through the *_all* functions and invoke them. + if (this._all) { + var l = arguments.length; + var args = new Array(l - 1); + for (var i = 1; i < l; i++) args[i - 1] = arguments[i]; + for (i = 0, l = this._all.length; i < l; i++) { + this.event = type; + this._all[i].apply(this, args); + } + } + + // If there is no 'error' event listener then throw. + if (type === 'error') { + + if (!this._all && + !this._events.error && + !(this.wildcard && this.listenerTree.error)) { + + if (arguments[1] instanceof Error) { + throw arguments[1]; // Unhandled 'error' event + } else { + throw new Error("Uncaught, unspecified 'error' event."); + } + return false; + } + } + + var handler; + + if(this.wildcard) { + handler = []; + var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); + searchListenerTree.call(this, handler, ns, this.listenerTree, 0); + } + else { + handler = this._events[type]; + } + + if (typeof handler === 'function') { + this.event = type; + if (arguments.length === 1) { + handler.call(this); + } + else if (arguments.length > 1) + switch (arguments.length) { + case 2: + handler.call(this, arguments[1]); + break; + case 3: + handler.call(this, arguments[1], arguments[2]); + break; + // slower + default: + var l = arguments.length; + var args = new Array(l - 1); + for (var i = 1; i < l; i++) args[i - 1] = arguments[i]; + handler.apply(this, args); + } + return true; + } + else if (handler) { + var l = arguments.length; + var args = new Array(l - 1); + for (var i = 1; i < l; i++) args[i - 1] = arguments[i]; + + var listeners = handler.slice(); + for (var i = 0, l = listeners.length; i < l; i++) { + this.event = type; + listeners[i].apply(this, args); + } + return (listeners.length > 0) || !!this._all; + } + else { + return !!this._all; + } + + }; + + EventEmitter.prototype.on = function(type, listener) { + + if (typeof type === 'function') { + this.onAny(type); + return this; + } + + if (typeof listener !== 'function') { + throw new Error('on only accepts instances of Function'); + } + this._events || init.call(this); + + // To avoid recursion in the case that type == "newListeners"! Before + // adding it to the listeners, first emit "newListeners". + this.emit('newListener', type, listener); + + if(this.wildcard) { + growListenerTree.call(this, type, listener); + return this; + } + + if (!this._events[type]) { + // Optimize the case of one listener. Don't need the extra array object. + this._events[type] = listener; + } + else if(typeof this._events[type] === 'function') { + // Adding the second element, need to change to array. + this._events[type] = [this._events[type], listener]; + } + else if (isArray(this._events[type])) { + // If we've already got an array, just append. + this._events[type].push(listener); + + // Check for listener leak + if (!this._events[type].warned) { + + var m = defaultMaxListeners; + + if (typeof this._events.maxListeners !== 'undefined') { + m = this._events.maxListeners; + } + + if (m > 0 && this._events[type].length > m) { + + this._events[type].warned = true; + console.error('(node) warning: possible EventEmitter memory ' + + 'leak detected. %d listeners added. ' + + 'Use emitter.setMaxListeners() to increase limit.', + this._events[type].length); + console.trace(); + } + } + } + return this; + }; + + EventEmitter.prototype.onAny = function(fn) { + + if (typeof fn !== 'function') { + throw new Error('onAny only accepts instances of Function'); + } + + if(!this._all) { + this._all = []; + } + + // Add the function to the event listener collection. + this._all.push(fn); + return this; + }; + + EventEmitter.prototype.addListener = EventEmitter.prototype.on; + + EventEmitter.prototype.off = function(type, listener) { + if (typeof listener !== 'function') { + throw new Error('removeListener only takes instances of Function'); + } + + var handlers,leafs=[]; + + if(this.wildcard) { + var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); + leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0); + } + else { + // does not use listeners(), so no side effect of creating _events[type] + if (!this._events[type]) return this; + handlers = this._events[type]; + leafs.push({_listeners:handlers}); + } + + for (var iLeaf=0; iLeaf 0) { + fns = this._all; + for(i = 0, l = fns.length; i < l; i++) { + if(fn === fns[i]) { + fns.splice(i, 1); + return this; + } + } + } else { + this._all = []; + } + return this; + }; + + EventEmitter.prototype.removeListener = EventEmitter.prototype.off; + + EventEmitter.prototype.removeAllListeners = function(type) { + if (arguments.length === 0) { + !this._events || init.call(this); + return this; + } + + if(this.wildcard) { + var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); + var leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0); + + for (var iLeaf=0; iLeaf + + + +Exercise 10 + + + +

Exercise 10

+ +
+
+ +
+
+
+
+
+
+ +
+ + + + + + + + + + diff --git a/frontend-masters-exercises/exercises/ex10/feeds.js b/frontend-masters-exercises/exercises/ex10/feeds.js new file mode 100755 index 0000000..c26e829 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex10/feeds.js @@ -0,0 +1,238 @@ +(function Feeds(){ + "use strict"; + + var // signal event handler(s) + item_feed; + + EVT.on("setup-feeds",setupFeeds); + + + // *********************************** + + function setupFeeds() { + // setup fake item feed + fakeItemFeed(function setupItemFeed(sq){ + item_feed = sq; + }); + + // setup slow feed (feed 1) + var slow_feed_toggle; + setupFeed( + /*feedID=*/1, + /*delay=*/2000, + function setupSlowFeedToggle(sq){ + slow_feed_toggle = sq; + } + ); + + // setup fast feed (feed 2) + var fast_feed_toggle; + setupFeed( + /*feedID=*/2, + /*delay=*/1300, + function setupFastFeedToggle(sq){ + fast_feed_toggle = sq; + } + ); + + // track feed statuses + var st1 = true, st2 = true; + + // monitor feed statuses + var listenToFeedStatus = ASQ.wrap(function *wrapped(){ + // monitor each status + slow_feed_toggle.val(function val(st){ + st1 = st; + }); + fast_feed_toggle.then(function val(st){ + st2 = st; + }); + + // listen for either status to toggle + yield ASQ().race(slow_feed_toggle,fast_feed_toggle); + + monitorFeedStatus(st1,st2); + + // wait for next tick + yield ASQ(); + + listenToFeedStatus(); + },{ gen: true }); + listenToFeedStatus(); + + // setup my feed (duplicate checking) + setupMyFeed(); + } + + // fake a network stream of data + function fakeItemFeed(defineSequence) { + var next = sequenceBasedEventHandler(defineSequence); + + // fake a delay + var intv = setInterval(function timer(){ + // signal a new item + next( ItemsText.more() ); + },50); + } + + function setupFeed(feedID,delay,defineToggleSequence) { + // setup feed reactive sequences + var feed_is_running = true, + feed_status, feed_toggle, + + PAUSED_FEED = ASQ(function noop(){}); + + // start with feed running + feed_status = ASQ(true); + + setupNextFeedToggle(); + + fromEvent( + "status-" + feedID, + setupFeedToggle + ); + + sampledStream( + delay, + ASQ.wrap(setupStreamEventHandler,{ gen: true, spread: true }) + ); + + + // *********************************** + + function *setupFeedToggle(sq) { + // distinct consecutive + handleFeedToggle( yield sq ); + } + + function setupNextFeedToggle() { + feed_toggle = ASQ.iterable(); + defineToggleSequence(feed_toggle); + } + + function handleFeedToggle(st) { + // resuming feed? + if (st !== feed_is_running && st === true) { + feed_is_running = true; + feed_status = ASQ(true); + } + // switching to paused feed + else { + feed_is_running = false; + feed_status = PAUSED_FEED; + } + + feed_toggle.next(feed_is_running); + + setupNextFeedToggle(); + } + + function *setupStreamEventHandler(sq) { + var args = yield ASQ().all(sq,feed_status); + handleItemText(args[0]); + } + + function handleItemText(itemText) { + // feed still running? + if (feed_is_running) { + EVT.emit("feed-insertion",feedID,itemText); + } + } + } + + function sampledStream(delay,defineSequence) { + // throttle feed sampling + var intv = setInterval( + ASQ.wrap(timer,{ gen: true }), + delay + ); + + + // *********************************** + + function *timer() { + var sq = ASQ.iterable(); + + defineSequence(ASQ.messages(sq)); + + // signal a new feed item + sq.next( yield item_feed ); + } + } + + function monitorFeedStatus(running1,running2) { + // both feeds paused? + if (!running1 && !running2) { + // TODO: pause the item feed + } + // keep calm and carry on + else { + // TODO: resume the item feed + } + } + + function setupMyFeed() { + var my_feed_text = {}; + + fromEvent( + "item-selection", + function *setupItemSelection(sq){ + handleItemSelection.apply( null, yield sq ); + } + ); + + + // *********************************** + + function handleItemSelection(feedID,itemText,$item) { + // not a duplicate message? + if (!(itemText in my_feed_text)) { + my_feed_text[itemText] = true; + + // signal my-feed insertion + EVT.emit("my-feed-insertion",feedID,$item); + } + else { + // signal kill (duplicate) item + EVT.emit("feed-kill",$item); + } + } + } + + function fromEvent(evtName,defineSequence) { + EVT.on( + evtName, + sequenceBasedEventHandler( + ASQ.wrap(defineSequence,{ gen: true, spread: true }) + ) + ); + } + + function sequenceBasedEventHandler(defineSequence) { + var sq; + + // start out with a sequence + getNextSequence(); + + return eventHandler; + + + // *********************************** + + function eventHandler() { + // resolve previous sequence + sq.next.apply(null,arguments); + + // get the next sequence ready in case + // this event fires again + getNextSequence(); + } + + function getNextSequence() { + sq = ASQ.iterable(); + + defineSequence(ASQ.messages(sq)); + } + } + +})(); diff --git a/frontend-masters-exercises/exercises/ex10/jquery.js b/frontend-masters-exercises/exercises/ex10/jquery.js new file mode 100755 index 0000000..45477c0 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex10/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v1.8.3 jquery.com | jquery.org/license */ +(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write(""),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t
a",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="
t
",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="
",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;ti.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="
",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="

",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t0)for(i=r;i=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*\s*$/g,Nt={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X
","
"]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1>");try{for(;r1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]===""&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("
").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window); diff --git a/frontend-masters-exercises/exercises/ex10/npo.js b/frontend-masters-exercises/exercises/ex10/npo.js new file mode 100755 index 0000000..c363ed4 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex10/npo.js @@ -0,0 +1,5 @@ +/*! Native Promise Only + v0.8.1 (c) Kyle Simpson + MIT License: http://getify.mit-license.org +*/ +!function(t,n,e){n[t]=n[t]||e(),"undefined"!=typeof module&&module.exports?module.exports=n[t]:"function"==typeof define&&define.amd&&define(function(){return n[t]})}("Promise","undefined"!=typeof global?global:this,function(){"use strict";function t(t,n){l.add(t,n),h||(h=y(l.drain))}function n(t){var n,e=typeof t;return null==t||"object"!=e&&"function"!=e||(n=t.then),"function"==typeof n?n:!1}function e(){for(var t=0;t0&&t(e,u))}catch(a){i.call(new f(u),a)}}}function i(n){var o=this;o.triggered||(o.triggered=!0,o.def&&(o=o.def),o.msg=n,o.state=2,o.chain.length>0&&t(e,o))}function c(t,n,e,o){for(var r=0;r .toggle, +#feed-2 > .toggle { + position: absolute; + left: 50%; + transform: translate(-50%); + bottom: -25px; +} + +#my-feed { + padding: 5px 15px; + margin: 0px 30px; + display: inline-block; + position: relative; + width: 400px; + height: 500px; + border: 3px solid #000; + background-color: #f0f0f0; + vertical-align: top; +} + +#feed-1 > .content, +#feed-2 > .content, +#my-feed > .content { + position: relative; + width: 100%; + height: 100%; + overflow-y: scroll; +} + +.item { + display: block; + position: relative; + margin: 10px 0px; + padding: 5px; + width: 100%; + color: #000; + overflow: hidden; + white-space: nowrap; + text-decoration: none; + text-overflow: ellipsis; +} + +.item.floating { + cursor: default; + position: absolute; + transition: left 0.3s ease-out, top 0.3s ease-out; + max-width: 214px; + max-height: 100px; +} + +.item.killed { + text-decoration: line-through; +} + +#feed-1 > .content > .item, +#feed-2 > .content > .item { + max-height: 100px; +} + +#feed-1 > .content > .item:hover, +#feed-2 > .content > .item:hover { + background-color: rgba(0,0,0,0.1); +} + +#my-feed > .content > .item { + cursor: default; + max-height: inherit; + white-space: normal; + overflow: auto; + text-overflow: inherit; +} + +.first-list { + background-color: #ffb8b3; +} + +.second-list { + background-color: #b3caff; +} diff --git a/frontend-masters-exercises/exercises/ex10/ui.js b/frontend-masters-exercises/exercises/ex10/ui.js new file mode 100755 index 0000000..2655c99 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex10/ui.js @@ -0,0 +1,238 @@ +(function UI(global){ + "use strict"; + + var $body, $feed_1, $feed_2, $my_feed, + $feed_1_content, $feed_2_content, + $my_feed_content, + + // signal event handler(s) + toggle_clicks, + item_clicks, + + // sequence wrapper(s) + rAF, + docready; + + // pubsub hub + global.EVT = new EventEmitter2(); + + // run everything! + ASQ().runner(setup); + + + // *********************************** + + function *setup() { + // sequence-wrapper for requestAnimationFrame event + // note: this is a one-time event, so sequence OK + rAF = function rAF() { + return ASQ(function asq(done){ + requestAnimationFrame(done); + }); + }, + + // sequence-wrapper for DOM-ready event + // note: this is a one-time event, so sequence OK + docready = function docready() { + return ASQ(function asq(done){ + $(document).ready(done); + }); + }; + + // DOM event handlers from sequences + toggle_clicks = sequenceBasedEventHandler(function *setupToggleClicks(sq){ + toggleFeed( yield sq ); + }); + item_clicks = sequenceBasedEventHandler(function *setupItemClicks(sq){ + selectItem( yield sq ); + }); + + // wait for DOM-ready + yield docready(); + + $body = $(document.body); + + $feed_1 = $("[rel*=js-feed-1]"); + $feed_1_content = $feed_1.children("[rel*=js-content]"); + $feed_1.children("[rel*=js-toggle]") + .on("click",toggle_clicks); + + $feed_2 = $("[rel*=js-feed-2]"); + $feed_2_content = $feed_2.children("[rel*=js-content]"); + $feed_2.children("[rel*=js-toggle]") + .on("click",toggle_clicks); + + $my_feed = $("[rel*=js-my-feed]"); + $my_feed_content = $my_feed.children("[rel*=js-content]"); + $my_feed_content.on("click","[rel*=js-item]",noop); + + $feed_1.on("click","[rel*=js-item]",item_clicks); + $feed_2.on("click","[rel*=js-item]",item_clicks); + + EVT.on("feed-insertion",insertFeedItem); + EVT.on("my-feed-insertion",ASQ.wrap(insertMyFeedItem,{ gen: true, spread: true })); + EVT.on("feed-kill",ASQ.wrap(killFeedItem,{ gen: true, spread: true })); + + // signal the feeds setup to proceed + EVT.emit("setup-feeds"); + } + + function toggleFeed($btn) { + var $feed = $btn.closest("[rel*=js-feed-]"); + var feed_id = Number( $feed.attr("rel").substr(8) ); + var running = ($feed.attr("data-paused") !== "true"); + + // currently running feed? + if (running) { + // pause it + $feed.attr({ "data-paused": "true" }); + $btn.text("resume"); + } + // paused feed + else { + // resume it + $feed.removeAttr("data-paused"); + $btn.text("pause list"); + } + + // signal status message + EVT.emit("status-" + feed_id,!running); + } + + function insertFeedItem(feedID,itemText) { + var $content; + + // which feed to insert into? + if (feedID == 1) $content = $feed_1_content; + else if (feedID == 2) $content = $feed_2_content; + + var $item = $("") + .addClass("item") + .attr({ href: "#", rel: "js-item" }) + .text(itemText); + + $content.prepend($item); + + var $items = $content.children("[rel*=js-item]"); + if ($items.length > 20) { + $items.last().remove(); + } + } + + function selectItem($item) { + // item not yet killed? + if (!$item.is(".killed")) { + var $feed = $item.closest("[rel*=js-feed-]"); + var feed_id = Number( $feed.attr("rel").substr(8) ); + + // signal item selection + EVT.emit("item-selection",feed_id,$item.text(),$item); + } + } + + function *insertMyFeedItem(feed_id,$item) { + var $floating_item = $item.clone().addClass("floating"); + + if (feed_id == 1) $floating_item.addClass("first-list"); + else if (feed_id == 2) $floating_item.addClass("second-list"); + + var item_dims = $item.offset(); + var item_margin_left = parseInt($item.css("margin-left"),10); + var item_margin_top = parseInt($item.css("margin-top"),10); + + $floating_item.css({ + left: (Math.round(item_dims.left) - item_margin_left) + "px", + top: (Math.round(item_dims.top) - item_margin_top) + "px" + }) + .appendTo($body); + + $item.remove(); + + // wait for the next animation frame (CSS junk) + yield rAF(); + + var my_feed_dims = $my_feed_content.offset(); + + $floating_item.css({ + left: Math.round(my_feed_dims.left) + "px", + top: Math.round(my_feed_dims.top) + "px" + }); + + // wait for the transition to end + yield fromEventOnce($floating_item,"transitionend"); + + $floating_item + .unbind("transitionend") + .css({ left: "", top: "" }) + .removeClass("floating") + .prependTo($my_feed_content); + } + + function *killFeedItem($item) { + $item.addClass("killed"); + + // wait for a second + yield ASQ.after(1000); + + $item.remove(); + } + + // bridge DOM events to sequences + function fromEventOnce($el,evtName,defineSequenceChain) { + var sq = ASQ.iterable(); + + $el.on(evtName,onevt); + + return sq; + + + // *********************************** + + function onevt(evt) { + noop(evt); + + // unbind event handler since sequences are + // resolvable only once + $el.off(evtName,onevt); + + sq.next($(evt.target)); + } + } + + function sequenceBasedEventHandler(defineSequenceChain) { + var sq; + + defineSequenceChain = ASQ.wrap(defineSequenceChain,{ gen: true, spread: true }); + + // start out with a sequence + getNextSequence(); + + return eventHandler; + + // *********************************** + + function eventHandler(evt) { + noop(evt); + + // resolve previous sequence + sq.next($(evt.target)); + + // get the next sequence ready in case + // this event fires again + getNextSequence(); + } + + function getNextSequence() { + sq = ASQ.iterable(); + + defineSequenceChain(ASQ.messages(sq)); + } + } + + function noop(evt) { + evt.preventDefault(); + evt.stopPropagation(); + evt.stopImmediatePropagation(); + } + +})(window); diff --git a/frontend-masters-exercises/exercises/ex2/README.md b/frontend-masters-exercises/exercises/ex2/README.md new file mode 100755 index 0000000..626c49b --- /dev/null +++ b/frontend-masters-exercises/exercises/ex2/README.md @@ -0,0 +1,9 @@ +# Instructions + +1. You'll do the same thing as the previous exercise(s), but now you should use thunks. + +2. Expected behavior: + - Request all 3 files at the same time (in "parallel"). + - Render them ASAP (don't just blindly wait for all to finish loading) + - BUT, render them in proper (obvious) order: "file1", "file2", "file3". + - After all 3 are done, output "Complete!". diff --git a/frontend-masters-exercises/exercises/ex2/ex2-fixed.html b/frontend-masters-exercises/exercises/ex2/ex2-fixed.html new file mode 100755 index 0000000..22db9bb --- /dev/null +++ b/frontend-masters-exercises/exercises/ex2/ex2-fixed.html @@ -0,0 +1,13 @@ + + + + +Exercise 2 - Fixed + + +

Exercise 2 - Fixed

+ + + + + diff --git a/frontend-masters-exercises/exercises/ex2/ex2-fixed.js b/frontend-masters-exercises/exercises/ex2/ex2-fixed.js new file mode 100755 index 0000000..3c82b52 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex2/ex2-fixed.js @@ -0,0 +1,50 @@ +function fakeAjax(url,cb) { + var fake_responses = { + "file1": "The first text", + "file2": "The middle text", + "file3": "The last text" + }; + var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000; + + console.log("Requesting: " + url); + + setTimeout(function(){ + cb(fake_responses[url]); + },randomDelay); +} + +function output(text) { + console.log(text); +} + +// ************************************** + +function getFile(file) { + var resp; + + fakeAjax(file,function(text){ + if (!resp) resp = text; + else resp(text); + }); + + return function th(cb) { + if (resp) cb(resp); + else resp = cb; + }; +} + +// request all files at once in "parallel" +var th1 = getFile("file1"); +var th2 = getFile("file2"); +var th3 = getFile("file3"); + +th1(function ready(text){ + output(text); + th2(function ready(text){ + output(text); + th3(function ready(text){ + output(text); + output("Complete!"); + }); + }); +}); diff --git a/frontend-masters-exercises/exercises/ex2/ex2.html b/frontend-masters-exercises/exercises/ex2/ex2.html new file mode 100755 index 0000000..f858f4c --- /dev/null +++ b/frontend-masters-exercises/exercises/ex2/ex2.html @@ -0,0 +1,13 @@ + + + + +Exercise 2 + + +

Exercise 2

+ + + + + diff --git a/frontend-masters-exercises/exercises/ex2/ex2.js b/frontend-masters-exercises/exercises/ex2/ex2.js new file mode 100755 index 0000000..5a22087 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex2/ex2.js @@ -0,0 +1,52 @@ +function fakeAjax(url,cb) { + var fake_responses = { + "file1": "The first text", + "file2": "The middle text", + "file3": "The last text" + }; + var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000; + + console.log("Requesting: " + url); + + setTimeout(function(){ + cb(fake_responses[url]); + },randomDelay); +} + +function output(text) { + console.log(text); +} + +// ************************************** + +function getFile(file) { + // what do we do here? + var text, fn; + + fakeAjax(file, function(response) { + if (fn) fn(response); + else text = response; + }); + + return function(cb) { + if (text) cb(text); + else fn = cb; + }; +} + +// request all files at once in "parallel" +// ??? +var thunkOne = getFile("file1"); +var thunkTwo = getFile("file2"); +var thunkThree = getFile("file3"); + +thunkOne(function(text1) { + output(text1); + thunkTwo(function(text2) { + output(text2); + thunkThree(function(text3) { + output(text3); + output("Complete!"); + }); + }); +}); diff --git a/frontend-masters-exercises/exercises/ex3/README.md b/frontend-masters-exercises/exercises/ex3/README.md new file mode 100755 index 0000000..3565e50 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex3/README.md @@ -0,0 +1,9 @@ +# Instructions + +1. You'll do the same thing as the previous exercise(s), but now you should use promises. + +2. Expected behavior: + - Request all 3 files at the same time (in "parallel"). + - Render them ASAP (don't just blindly wait for all to finish loading) + - BUT, render them in proper (obvious) order: "file1", "file2", "file3". + - After all 3 are done, output "Complete!". diff --git a/frontend-masters-exercises/exercises/ex3/ex3-fixed.html b/frontend-masters-exercises/exercises/ex3/ex3-fixed.html new file mode 100755 index 0000000..abc2494 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex3/ex3-fixed.html @@ -0,0 +1,14 @@ + + + + +Exercise 3 - Fixed + + +

Exercise 3 - Fixed

+ + + + + + diff --git a/frontend-masters-exercises/exercises/ex3/ex3-fixed.js b/frontend-masters-exercises/exercises/ex3/ex3-fixed.js new file mode 100755 index 0000000..9a97735 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex3/ex3-fixed.js @@ -0,0 +1,49 @@ +function fakeAjax(url,cb) { + var fake_responses = { + "file1": "The first text", + "file2": "The middle text", + "file3": "The last text" + }; + var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000; + + console.log("Requesting: " + url); + + setTimeout(function(){ + cb(fake_responses[url]); + },randomDelay); +} + +function output(text) { + console.log(text); +} + +// ************************************** + +function getFile(file) { + return new Promise(function(resolve){ + fakeAjax(file,resolve); + }); +} + +// Request all files at once in +// "parallel" via `getFile(..)`. +var p1 = getFile("file1"); +var p2 = getFile("file2"); +var p3 = getFile("file3"); + +// Render as each one finishes, +// but only once previous rendering +// is done. +p1 +.then(output) +.then(function(){ + return p2; +}) +.then(output) +.then(function(){ + return p3; +}) +.then(output) +.then(function(){ + output("Complete!"); +}); diff --git a/frontend-masters-exercises/exercises/ex3/ex3.html b/frontend-masters-exercises/exercises/ex3/ex3.html new file mode 100755 index 0000000..33e5265 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex3/ex3.html @@ -0,0 +1,14 @@ + + + + +Exercise 3 + + +

Exercise 3

+ + + + + + diff --git a/frontend-masters-exercises/exercises/ex3/ex3.js b/frontend-masters-exercises/exercises/ex3/ex3.js new file mode 100755 index 0000000..3841b8f --- /dev/null +++ b/frontend-masters-exercises/exercises/ex3/ex3.js @@ -0,0 +1,139 @@ +function fakeAjax(url,cb) { + var fake_responses = { + "file1": "The first text", + "file2": "The middle text", + "file3": "The last text" + }; + var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000; + + console.log("Requesting: " + url); + + setTimeout(function(){ + cb(fake_responses[url]); + },randomDelay); +} + +function output(text) { + console.log(text); +} + +// ************************************** + +function getFile(file) { + // what do we do here? + // return new Promise(function executor(resolve, reject) { + // }) + //We arn't handling errors so we don't need the reject/error case + + //In real life you may or may not need to create your own promise based on the functionality of the utility you are in + + //Another way of writing it that highlights that resolve is a function t + //is being passed in as the callback for fakeAjax + + // return new Promise(function executor(resolve) { + // fakeAjax(file, function(text) { + // resolve(text); + // }); + // }); + + + return new Promise(function executor(resolve) { + fakeAjax(file, resolve); + }); + + + + fakeAjax(file, function(response) { + output(response) + }) +} + +// request all files at once in "parallel" +// ??? +//This is my solution and it works +getFile("file1").then(function(text) { + output(text) + return getFile("file2") +}).then(function(text) { + output(text) + return getFile("file3") +}).then(function(text) { + output(text) + output("Complete!") +}) + + +//For the separation fo concerns Kyle Simpson prefers the following way +function getFile(file) { + return new Promise(function(resolve){ + fakeAjax(file,resolve); + }); +} + +// Request all files at once in +// "parallel" via `getFile(..)`. +var p1 = getFile("file1"); +var p2 = getFile("file2"); +var p3 = getFile("file3"); + +// Render as each one finishes, +// but only once previous rendering +// is done. +p1 +.then(output) +.then(function(){ + return p2; +}) +.then(output) +.then(function(){ + return p3; +}) +.then(output) +.then(function(){ + output("Complete!"); +}); + + + +// The basics of error handling that it is good to know +p1 +.then(output) +//A catch here (like try catch) means an error caught here is "caught" and chain continues as normal +.catch(err) +.then(function(){ + return p2; +}) +.then(output) +.then(function(){ + return p3; +}) +.then(output) +.then(function(){ + output("Complete!"); +}) +//A catch here means it is fatal and any errors up to this point that havent been caught cause the whole thing to be considered no good +//synonymous way of writing a catch +// .then(null,function(err) { +// +// }) +// +.catch(function(err) { + +}) + + +//Technically, technically this works as well, but it is bad style +var p1 = getFile("file1"); +var p2 = getFile("file2"); +var p3 = getFile("file3"); + +p1.then(function(text) { + output(text); + p2.then(function(text) { + output(text); + p3.then(function(text) { + output(text); + output("Complete!") + }) + }) +}); diff --git a/frontend-masters-exercises/exercises/ex3/npo.js b/frontend-masters-exercises/exercises/ex3/npo.js new file mode 100755 index 0000000..c363ed4 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex3/npo.js @@ -0,0 +1,5 @@ +/*! Native Promise Only + v0.8.1 (c) Kyle Simpson + MIT License: http://getify.mit-license.org +*/ +!function(t,n,e){n[t]=n[t]||e(),"undefined"!=typeof module&&module.exports?module.exports=n[t]:"function"==typeof define&&define.amd&&define(function(){return n[t]})}("Promise","undefined"!=typeof global?global:this,function(){"use strict";function t(t,n){l.add(t,n),h||(h=y(l.drain))}function n(t){var n,e=typeof t;return null==t||"object"!=e&&"function"!=e||(n=t.then),"function"==typeof n?n:!1}function e(){for(var t=0;t0&&t(e,u))}catch(a){i.call(new f(u),a)}}}function i(n){var o=this;o.triggered||(o.triggered=!0,o.def&&(o=o.def),o.msg=n,o.state=2,o.chain.length>0&&t(e,o))}function c(t,n,e,o){for(var r=0;r + + + +Exercise 4 - Fixed + + +

Exercise 4 - Fixed

+ + + + + diff --git a/frontend-masters-exercises/exercises/ex4/ex4-fixed.js b/frontend-masters-exercises/exercises/ex4/ex4-fixed.js new file mode 100755 index 0000000..5dd3575 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex4/ex4-fixed.js @@ -0,0 +1,48 @@ +function fakeAjax(url,cb) { + var fake_responses = { + "file1": "The first text", + "file2": "The middle text", + "file3": "The last text" + }; + var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000; + + console.log("Requesting: " + url); + + setTimeout(function(){ + cb(fake_responses[url]); + },randomDelay); +} + +function output(text) { + console.log(text); +} + +// ************************************** + +function getFile(file) { + return new Promise(function(resolve){ + fakeAjax(file,resolve); + }); +} + +// Request all files at once in +// "parallel" via `getFile(..)`. +// +// Render as each one finishes, +// but only once previous rendering +// is done. +["file1","file2","file3"] +.map(getFile) +.reduce( + function(chain,filePromise){ + return chain + .then(function(){ + return filePromise; + }) + .then(output); + }, + Promise.resolve() // fulfilled promise to start chain +) +.then(function() { + output("Complete!"); +}); diff --git a/frontend-masters-exercises/exercises/ex4/ex4.html b/frontend-masters-exercises/exercises/ex4/ex4.html new file mode 100755 index 0000000..1d96dfb --- /dev/null +++ b/frontend-masters-exercises/exercises/ex4/ex4.html @@ -0,0 +1,13 @@ + + + + +Exercise 4 + + +

Exercise 4

+ + + + + diff --git a/frontend-masters-exercises/exercises/ex4/ex4.js b/frontend-masters-exercises/exercises/ex4/ex4.js new file mode 100755 index 0000000..5dd3575 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex4/ex4.js @@ -0,0 +1,48 @@ +function fakeAjax(url,cb) { + var fake_responses = { + "file1": "The first text", + "file2": "The middle text", + "file3": "The last text" + }; + var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000; + + console.log("Requesting: " + url); + + setTimeout(function(){ + cb(fake_responses[url]); + },randomDelay); +} + +function output(text) { + console.log(text); +} + +// ************************************** + +function getFile(file) { + return new Promise(function(resolve){ + fakeAjax(file,resolve); + }); +} + +// Request all files at once in +// "parallel" via `getFile(..)`. +// +// Render as each one finishes, +// but only once previous rendering +// is done. +["file1","file2","file3"] +.map(getFile) +.reduce( + function(chain,filePromise){ + return chain + .then(function(){ + return filePromise; + }) + .then(output); + }, + Promise.resolve() // fulfilled promise to start chain +) +.then(function() { + output("Complete!"); +}); diff --git a/frontend-masters-exercises/exercises/ex4/npo.js b/frontend-masters-exercises/exercises/ex4/npo.js new file mode 100755 index 0000000..c363ed4 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex4/npo.js @@ -0,0 +1,5 @@ +/*! Native Promise Only + v0.8.1 (c) Kyle Simpson + MIT License: http://getify.mit-license.org +*/ +!function(t,n,e){n[t]=n[t]||e(),"undefined"!=typeof module&&module.exports?module.exports=n[t]:"function"==typeof define&&define.amd&&define(function(){return n[t]})}("Promise","undefined"!=typeof global?global:this,function(){"use strict";function t(t,n){l.add(t,n),h||(h=y(l.drain))}function n(t){var n,e=typeof t;return null==t||"object"!=e&&"function"!=e||(n=t.then),"function"==typeof n?n:!1}function e(){for(var t=0;t0&&t(e,u))}catch(a){i.call(new f(u),a)}}}function i(n){var o=this;o.triggered||(o.triggered=!0,o.def&&(o=o.def),o.msg=n,o.state=2,o.chain.length>0&&t(e,o))}function c(t,n,e,o){for(var r=0;r0){u=!1,a=s.shift(),c=g.slice(),g.length=0,c.unshift(createStepCompletion());try{a.apply(h,c)}catch(i){l(i)?$=$.concat(i):$.push(i),n=!0,scheduleSequenceTick()}}}function createStepCompletion(){function done(){n||r||u||(u=!0,g.push.apply(g,arguments),$.length=0,scheduleSequenceTick())}return done.fail=function $$step$fail(){n||r||u||(n=!0,g.length=0,$.push.apply($,arguments),scheduleSequenceTick())},done.abort=function $$step$abort(){n||r||(u=!1,r=!0,g.length=$.length=0,scheduleSequenceTick())},done.errfcb=function $$step$errfcb(e){e?done.fail(e):done.apply(h,f.call(arguments,1))},done}function createGate(e,t,u){function resetGate(){clearTimeout(s),s=d=m=o=null}function scheduleGateTick(){return g?gateTick():void(s||(s=schedule(gateTick)))}function gateTick(){if(!(n||r||$)){var t=[];s=null,p?(e.fail.apply(h,o),resetGate()):g?(e.abort(),resetGate()):checkGate()&&($=!0,d.forEach(function $$each(e,n){t.push(m["s"+n])}),e.apply(h,t),resetGate())}}function checkGate(){if(0!==d.length){var e=!0;return d.some(function $$some(n){return null===n?(e=!1,!0):void 0}),e}}function createSegmentCompletion(){function done(){if(!(n||r||p||g||$||d[e])){var t=c.apply(h,arguments);m["s"+e]=t.length>1?t:t[0],d[e]=!0,scheduleGateTick()}}var e=d.length;return done.fail=function $$segment$fail(){n||r||p||g||$||d[e]||(p=!0,o=f.call(arguments),scheduleGateTick())},done.abort=function $$segment$abort(){n||r||p||g||$||(g=!0,gateTick())},done.errfcb=function $$segment$errfcb(e){e?done.fail(e):done.apply(h,f.call(arguments,1))},d[e]=null,done}var a,i,o,s,p=!1,g=!1,$=!1,d=[],m={};t.some(function $$some(e){if(p||g)return!0;a=u.slice(),a.unshift(createSegmentCompletion());try{e.apply(h,a)}catch(n){return i=n,p=!0,!0}}),i&&(l(i)?e.fail.apply(h,i):e.fail(i))}function then(){return n||r||0===arguments.length?d:(wrapArgs(arguments,thenWrapper).forEach(function $$each(e){i(e)?seq(e):s.push(e)}),scheduleSequenceTick(),d)}function or(){return r||0===arguments.length?d:(p.push.apply(p,arguments),scheduleSequenceTick(),d)}function gate(){if(n||r||0===arguments.length)return d;var e=f.call(arguments).map(function $$map(e){var n;return i(e)?(n={seq:e},tapSequence(n),function $$segment(e){n.seq.pipe(e)}):e});return then(function $$then(n){var t=f.call(arguments,1);createGate(n,e,t)}),d}function pipe(){return r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){then(function $$then(n){e.apply(h,f.call(arguments,1)),n()}).or(e.fail)}),d)}function seq(){return n||r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){var n={seq:e};i(e)&&tapSequence(n),then(function $$then(e){var t=n.seq;i(t)||(t=n.seq.apply(h,f.call(arguments,1))),t.pipe(e)})}),d)}function val(){return n||r||0===arguments.length?d:(f.call(wrapArgs(arguments,valWrapper)).forEach(function $$each(e){then(function $$then(n){var t=e.apply(h,f.call(arguments,1));l(t)||(t=c(t)),n.apply(h,t)})}),d)}function promise(){function wrap(e){return function $$fn(){e.apply(h,l(arguments[0])?arguments[0]:arguments)}}return n||r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){then(function $$then(n){var t=e;"function"==typeof e&&"function"!=typeof e.then&&(t=e.apply(h,f.call(arguments,1))),t.then(wrap(n),wrap(n.fail))})}),d)}function fork(){var e;return val(function $$val(){return e?e.apply(h,arguments):e=createSequence.apply(h,arguments).defer(),c.apply(h,arguments)}),or(function $$or(){if(e)e.fail.apply(h,arguments);else{var n=f.call(arguments);e=createSequence().then(function $$then(e){e.fail.apply(h,n)}).defer()}}),createSequence().then(function $$then(n){e?e.pipe(n):e=n}).defer()}function abort(){return n?d:(r=!0,sequenceTick(),d)}function duplicate(){var e;return a={then_queue:s.slice(),or_queue:p.slice()},e=createSequence(),a=null,e}function unpause(){g.push.apply(g,arguments),e===!0&&(e=null),scheduleSequenceTick()}function defer(){return p.push(function ignored(){}),d}function internals(e,t){var a=arguments.length>1;switch(e){case"seq_error":if(!a)return n;n=t;break;case"seq_aborted":if(!a)return r;r=t;break;case"then_ready":if(!a)return u;u=t;break;case"then_queue":return s;case"or_queue":return p;case"sequence_messages":return g;case"sequence_errors":return $}}function includeExtensions(){Object.keys(o).forEach(function $$each(e){d[e]=o[e](d,internals)})}var e,n=!1,t=!1,r=!1,u=!0,s=[],p=[],g=[],$=[],d=brandIt({then:then,or:or,onerror:or,gate:gate,all:gate,pipe:pipe,seq:seq,val:val,promise:promise,fork:fork,abort:abort,duplicate:duplicate,defer:defer});return includeExtensions(),a&&(s=a.then_queue.slice(),p=a.or_queue.slice(),d.unpause=unpause,e=!0),d.then.apply(h,arguments),d}function brandIt(e){return Object.defineProperty(e,p,{enumerable:!1,value:!0})}function checkBranding(e){return!(null==e||"object"!=typeof e||!e[p])}function valWrapper(e){return c.apply(h,f.call(arguments).slice(1,e+1))}function thenWrapper(e){arguments[e+1].apply(h,f.call(arguments).slice(1,e+1))}function wrapArgs(e,n){var t,r;for(e=f.call(e),t=0;t 1 ? + ARRAY_SLICE.call(arguments,1) : + void 0 + ; + num = +num || 0; + + api.then(function $$then(done){ + var args = orig_args || ARRAY_SLICE.call(arguments,1); + + setTimeout(function $$set$timeout(){ + done.apply(ø,args); + },num); + }); + + return api; + }; +}); + +ASQ.after = function $$after() { + return ASQ().after.apply(ø,arguments); +}; +// "any" +ASQ.extend("any",function $$extend(api,internals){ + return function $$any() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages.length = 0; + } + + function complete(trigger) { + if (success_messages.length > 0) { + // any successful segment's message(s) sent + // to main sequence to proceed as success + success_messages.length = fns.length; + trigger.apply(ø,success_messages); + } + else { + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + success_messages = [], + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "errfcb" +ASQ.extend("errfcb",function $$extend(api,internals){ + return function $$errfcb() { + // create a fake sequence to extract the callbacks + var sq = { + val: function $$then(cb){ sq.val_cb = cb; return sq; }, + or: function $$or(cb){ sq.or_cb = cb; return sq; } + }; + + // trick `seq(..)`s checks for a sequence + sq[brand] = true; + + // immediately register our fake sequence on the + // main sequence + api.seq(sq); + + // provide the "error-first" callback + return function $$errorfirst$callback(err) { + if (err) { + sq.or_cb(err); + } + else { + sq.val_cb.apply(ø,ARRAY_SLICE.call(arguments,1)); + } + }; + }; +}); +// "failAfter" +ASQ.extend("failAfter",function $$extend(api,internals){ + return function $$failAfter(num) { + var args = arguments.length > 1 ? + ARRAY_SLICE.call(arguments,1) : + void 0 + ; + num = +num || 0; + + api.then(function $$then(done){ + setTimeout(function $$set$timeout(){ + done.fail.apply(ø,args); + },num); + }); + + return api; + }; +}); + +ASQ.failAfter = function $$fail$after() { + return ASQ().failAfter.apply(ø,arguments); +}; +// "first" +ASQ.extend("first",function $$extend(api,internals){ + return function $$first() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + error_messages.length = 0; + } + + function success(trigger,idx,args) { + if (!finished) { + finished = true; + + // first successful segment triggers + // main sequence to proceed as success + trigger( + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ); + + reset(); + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete without success? + if (completed === fns.length) { + finished = true; + + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + + reset(); + } + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "go-style CSP" +(function IIFE(){ + + // filter out already-resolved queue entries + function filterResolved(queue) { + return queue.filter(function $$filter(entry){ + return !entry.resolved; + }); + } + + function closeQueue(queue,finalValue) { + queue.forEach(function $$each(iter){ + if (!iter.resolved) { + iter.next(); + iter.next(finalValue); + } + }); + queue.length = 0; + } + + function channel(bufSize) { + var ch = { + close: function $$close(){ + ch.closed = true; + closeQueue(ch.put_queue,false); + closeQueue(ch.take_queue,ASQ.csp.CLOSED); + }, + closed: false, + messages: [], + put_queue: [], + take_queue: [], + buffer_size: +bufSize || 0 + }; + return ch; + } + + function unblock(iter) { + if (iter && !iter.resolved) { + iter.next(iter.next().value); + } + } + + function put(channel,value) { + var ret; + + if (channel.closed) { + return false; + } + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + // immediate put? + if (channel.messages.length < channel.buffer_size) { + channel.messages.push(value); + unblock(channel.take_queue.shift()); + return true; + } + // queued put + else { + channel.put_queue.push( + // make a notifiable iterable for 'put' blocking + ASQ.iterable() + .then(function $$then(){ + if (!channel.closed) { + channel.messages.push(value); + return true; + } + else { + return false; + } + }) + ); + + // wrap a sequence/promise around the iterable + ret = ASQ( + channel.put_queue[channel.put_queue.length - 1] + ); + + // take waiting on this queued put? + if (channel.take_queue.length > 0) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + + return ret; + } + } + + function putAsync(channel,value,cb) { + var ret = ASQ(put(channel,value)); + + if (cb && typeof cb == "function") { + ret.val(cb); + } + else { + return ret; + } + } + + function take(channel) { + var ret; + + try { + ret = takem(channel); + } + catch (err) { + ret = err; + } + + if (ASQ.isSequence(ret)) { + ret.pCatch(function $$pcatch(err){ + return err; + }); + } + + return ret; + } + + function takeAsync(channel,cb) { + var ret = ASQ(take(channel)); + + if (cb && typeof cb == "function") { + ret.val(cb); + } + else { + return ret; + } + } + + function takem(channel) { + var msg; + + if (channel.closed) { + return ASQ.csp.CLOSED; + } + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + // immediate take? + if (channel.messages.length > 0) { + msg = channel.messages.shift(); + unblock(channel.put_queue.shift()); + if (msg instanceof Error) { + throw msg; + } + return msg; + } + // queued take + else { + channel.take_queue.push( + // make a notifiable iterable for 'take' blocking + ASQ.iterable() + .then(function $$then(){ + if (!channel.closed) { + var v = channel.messages.shift(); + if (v instanceof Error) { + throw v; + } + return v; + } + else { + return ASQ.csp.CLOSED; + } + }) + ); + + // wrap a sequence/promise around the iterable + msg = ASQ( + channel.take_queue[channel.take_queue.length - 1] + ); + + // put waiting on this take? + if (channel.put_queue.length > 0) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + + return msg; + } + } + + function takemAsync(channel,cb) { + var ret = ASQ(takem(channel)); + + if (cb && typeof cb == "function") { + ret.pThen(cb,cb); + } + else { + return ret.val(function $$val(v){ + if (v instanceof Error) { + throw v; + } + return v; + }); + } + } + + function alts(actions) { + var closed, open, handlers, i, isq, ret, resolved = false; + + // used `alts(..)` incorrectly? + if (!Array.isArray(actions) || actions.length == 0) { + throw Error("Invalid usage"); + } + + closed = []; + open = []; + handlers = []; + + // separate actions by open/closed channel status + actions.forEach(function $$each(action){ + var channel = Array.isArray(action) ? action[0] : action; + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + if (channel.closed) { + closed.push(channel); + } + else { + open.push(action); + } + }); + + // if no channels are still open, we're done + if (open.length == 0) { + return { value: ASQ.csp.CLOSED, channel: closed }; + } + + // can any channel action be executed immediately? + for (i=0; i 0) { + return { value: take(open[i]), channel: open[i] }; + } + } + + isq = ASQ.iterable(); + var ret = ASQ(isq); + + // setup channel action handlers + for (i=0; i 0) { + schedule(function handleUnblocking(){ + if (!resolved) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + },0); + } + } + // take action? + else { + channel = action; + + // define take handler + handlers.push( + ASQ.iterable() + .then(function $$then(){ + resolved = true; + + // mark all handlers across this `alts(..)` as resolved now + handlers = handlers.filter(function $$filter(handler){ + return !(handler.resolved = true); + }); + + // channel still open? + if (!channel.closed) { + isq.next({ value: channel.messages.shift(), channel: channel }); + } + // channel already closed? + else { + isq.next({ value: ASQ.csp.CLOSED, channel: channel }); + } + }) + ); + + // queue up take handler + channel.take_queue.push(handlers[handlers.length-1]); + + // put waiting on this queued take? + if (channel.put_queue.length > 0) { + schedule(function handleUnblocking(){ + if (!resolved) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + }); + } + } + })(open[i]); + } + + return ret; + } + + function altsAsync(chans,cb) { + var ret = ASQ(alts(chans)); + + if (cb && typeof cb == "function") { + ret.pThen(cb,cb); + } + else { + return ret; + } + } + + function timeout(delay) { + var ch = channel(); + setTimeout(ch.close,delay); + return ch; + } + + function go(gen,args) { + // goroutine arguments passed? + if (arguments.length > 1) { + if (!args || !Array.isArray(args)) { + args = [args]; + } + } + else { + args = []; + } + + return function *$$go(token) { + + // unblock the overall goroutine handling + function unblock() { + token.unblock_count++; + + if (token.block && !token.block.marked) { + token.block.marked = true; + token.block.next(); + } + } + + var ret, msg, err, type, done = false, it; + + // keep track of how many requests for unblocking + // have occurred + token.unblock_count = (token.unblock_count || 0); + + // keep track of how many goroutines are running + // so we can infer when we're done go'ing + token.go_count = (token.go_count || 0) + 1; + + // need to initialize a set of goroutines? + if (token.go_count === 1) { + // create a default channel for these goroutines + token.channel = channel(); + token.channel.messages = token.messages; + token.channel.go = function $$go(){ + // unblock the goroutine handling for this + // new goroutine + unblock(); + // add the goroutine (called with any args) to + // the handling queue + token.add( go.apply(ø,arguments) ); + }; + // starting out with initial channel messages? + if (token.channel.messages.length > 0) { + // fake back-pressure blocking for each + token.channel.put_queue = token.channel.messages.map(function $$map(){ + // make a notifiable iterable for 'put' blocking + return ASQ.iterable() + .then(function $$then(){ + unblock(token.channel.take_queue.shift()); + return !token.channel.closed; + }); + }); + } + } + + // initialize the generator + it = gen.apply(ø,[token.channel].concat(args)); + + (function iterate(){ + + function next() { + // keep going with next step in goroutine? + if (!done) { + iterate(); + } + // unblock overall goroutine handling to + // continue with other goroutines + else { + unblock(); + } + } + + // has a resumption value been achieved yet? + if (!ret) { + // try to resume the goroutine + try { + // resume with injected exception? + if (err) { + ret = it.throw(err); + err = null; + } + // resume normally + else { + ret = it.next(msg); + } + } + // resumption failed, so bail + catch (e) { + done = true; + err = e; + msg = null; + unblock(); + return; + } + + // keep track of the result of the resumption + done = ret.done; + ret = ret.value; + type = typeof ret; + + // if this goroutine is complete, unblock the + // overall goroutine handling + if (done) { + unblock(); + } + + // received a thenable/promise back? + if (isPromise(ret)) { + ret = ASQ().promise(ret); + } + + // wait for the value? + if (ASQ.isSequence(ret)) { + ret.val(function $$val(){ + ret = null; + msg = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + next(); + }) + .or(function $$or(){ + ret = null; + msg = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + if (msg instanceof Error) { + err = msg; + msg = null; + } + next(); + }); + } + // immediate value, prepare it to go right back in + else { + msg = ret; + ret = null; + next(); + } + } + })(); + + // keep this goroutine alive until completion + while (!done) { + // transfer control to another goroutine + yield token; + + // need to block overall goroutine handling + // while idle? + if (!done && !token.block && token.unblock_count === 0) { + // wait here while idle + yield (token.block = ASQ.iterable()); + + token.block = false; + } + + if (token.unblock_count > 0) token.unblock_count--; + } + + // this goroutine is done now + token.go_count--; + + // all goroutines done? + if (token.go_count === 0) { + // any lingering blocking need to be cleaned up? + unblock(); + + // capture any untaken messages + msg = ASQ.messages.apply(ø,token.messages); + + // need to implicitly force-close channel? + if (token.channel && !token.channel.closed) { + token.channel.closed = true; + token.channel.put_queue.length = token.channel.take_queue.length = 0; + token.channel.close = token.channel.go = token.channel.messages = null; + } + token.channel = null; + } + + // make sure leftover error or message are + // passed along + if (err) { + throw err; + } + else if (token.go_count === 0) { + return msg; + } + else { + return token; + } + }; + } + + ASQ.csp = { + chan: channel, + put: put, + putAsync: putAsync, + take: take, + takeAsync: takeAsync, + takem: takem, + takemAsync: takemAsync, + alts: alts, + altsAsync: altsAsync, + timeout: timeout, + go: go, + CLOSED: {} + }; + +})(); +// "ASQ.iterable()" +(function IIFE(){ + var template; + + ASQ.iterable = function $$iterable() { + function throwSequenceErrors() { + throw (sequence_errors.length === 1 ? sequence_errors[0] : sequence_errors); + } + + function notifyErrors() { + var fn; + + seq_tick = null; + + if (seq_error) { + if (or_queue.length === 0 && !error_reported) { + error_reported = true; + throwSequenceErrors(); + } + + while (or_queue.length > 0) { + error_reported = true; + fn = or_queue.shift(); + try { + fn.apply(ø,sequence_errors); + } + catch (err) { + if (checkBranding(err)) { + sequence_errors = sequence_errors.concat(err); + } + else { + sequence_errors.push(err); + } + if (or_queue.length === 0) { + throwSequenceErrors(); + } + } + } + } + } + + function val() { + if (seq_error || seq_aborted || arguments.length === 0) { + return sequence_api; + } + + var args = ARRAY_SLICE.call(arguments).map(function mapper(arg){ + if (typeof arg != "function") return function $$val() { return arg; }; + else return arg; + }); + + val_queue.push.apply(val_queue,args); + + return sequence_api; + } + + function or() { + if (seq_aborted || arguments.length === 0) { + return sequence_api; + } + + or_queue.push.apply(or_queue,arguments); + + if (!seq_tick) { + seq_tick = schedule(notifyErrors); + } + + return sequence_api; + } + + function pipe() { + if (seq_aborted || arguments.length === 0) { + return sequence_api; + } + + ARRAY_SLICE.call(arguments) + .forEach(function $$each(fn){ + val(fn).or(fn.fail); + }); + + return sequence_api; + } + + function next() { + if (seq_error || seq_aborted || val_queue.length === 0) { + if (val_queue.length > 0) { + $throw$("Sequence cannot be iterated"); + } + return { done: true }; + } + + try { + return { value: val_queue.shift().apply(ø,arguments) }; + } + catch (err) { + if (ASQ.isMessageWrapper(err)) { + $throw$.apply(ø,err); + } + else { + $throw$(err); + } + + return {}; + } + } + + function $throw$() { + if (seq_error || seq_aborted) { + return sequence_api; + } + + sequence_errors.push.apply(sequence_errors,arguments); + seq_error = true; + if (!seq_tick) { + seq_tick = schedule(notifyErrors); + } + + return sequence_api; + } + + function $return$(val) { + if (seq_error || seq_aborted) { + val = void 0; + } + + abort(); + + return { done: true, value: val }; + } + + function abort() { + if (seq_error || seq_aborted) { + return; + } + + seq_aborted = true; + + clearTimeout(seq_tick); + seq_tick = null; + val_queue.length = or_queue.length = sequence_errors.length = 0; + } + + function duplicate() { + var isq; + + template = { + val_queue: val_queue.slice(), + or_queue: or_queue.slice() + }; + isq = ASQ.iterable(); + template = null; + + return isq; + } + + // opt-out of global error reporting for this sequence + function defer() { + or_queue.push(function $$ignored(){}); + return sequence_api; + } + + // *********************************************** + // Object branding utilities + // *********************************************** + function brandIt(obj) { + Object.defineProperty(obj,brand,{ + enumerable: false, + value: true + }); + + return obj; + } + + var sequence_api, + + seq_error = false, + error_reported = false, + seq_aborted = false, + + seq_tick, + + val_queue = [], + or_queue = [], + + sequence_errors = [] + ; + + // *********************************************** + // Setup the ASQ.iterable() public API + // *********************************************** + sequence_api = brandIt({ + val: val, + then: val, + or: or, + pipe: pipe, + next: next, + "throw": $throw$, + "return": $return$, + abort: abort, + duplicate: duplicate, + defer: defer + }); + + // useful for ES6 `for..of` loops, + // add `@@iterator` to simply hand back + // our iterable sequence itself! + sequence_api[(typeof Symbol == "function" && Symbol.iterator) || "@@iterator"] = function $$iter() { + return sequence_api; + }; + + // templating the iterable-sequence setup? + if (template) { + val_queue = template.val_queue.slice(0); + or_queue = template.or_queue.slice(0); + } + + // treat ASQ.iterable() constructor parameters as having been + // passed to `val()` + sequence_api.val.apply(ø,arguments); + + return sequence_api; + }; + +})(); +// "last" +ASQ.extend("last",function $$extend(api,internals){ + return function $$last() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages = null; + } + + function complete(trigger) { + if (success_messages != null) { + // last successful segment's message(s) sent + // to main sequence to proceed as success + trigger( + success_messages.length > 1 ? + ASQ.messages.apply(ø,success_messages) : + success_messages[0] + ); + } + else { + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages = args; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)), + success_messages + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "map" +ASQ.extend("map",function $$extend(api,internals){ + return function $$map(pArr,pEach) { + if (internals("seq_error") || internals("seq_aborted")) { + return api; + } + + api.seq(function $$seq(){ + var tmp, args = ARRAY_SLICE.call(arguments), + arr = pArr, each = pEach; + + // if missing `map(..)` args, use value-messages (if any) + if (!each) each = args.shift(); + if (!arr) arr = args.shift(); + + // if arg types in reverse order (each,arr), swap + if (typeof arr === "function" && Array.isArray(each)) { + tmp = arr; + arr = each; + each = tmp; + } + + return ASQ.apply(ø,args) + .gate.apply(ø,arr.map(function $$map(item){ + return function $$segment(){ + each.apply(ø,[item].concat(ARRAY_SLICE.call(arguments))); + }; + })); + }) + .val(function $$val(){ + // collect all gate segment output into one value-message + // Note: return a normal array here, not a message wrapper! + return ARRAY_SLICE.call(arguments); + }); + + return api; + }; +}); +// "none" +ASQ.extend("none",function $$extend(api,internals){ + return function $$none() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages.length = 0; + } + + function complete(trigger) { + if (success_messages.length > 0) { + // any successful segment's message(s) sent + // to main sequence to proceed as **error** + success_messages.length = fns.length; + trigger.fail.apply(ø,success_messages); + } + else { + // send errors as **success** to main sequence + error_messages.length = fns.length; + trigger.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)), + success_messages = [] + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "pThen" +ASQ.extend("pThen",function $$extend(api,internals){ + return function $$pthen(success,failure) { + if (internals("seq_aborted")) { + return api; + } + + var ignore_success_handler = false, ignore_failure_handler = false; + + if (typeof success === "function") { + api.then(function $$then(done){ + if (!ignore_success_handler) { + var ret, msgs = ASQ.messages.apply(ø,arguments); + msgs.shift(); + + if (msgs.length === 1) { + msgs = msgs[0]; + } + + ignore_failure_handler = true; + + try { + ret = success(msgs); + } + catch (err) { + if (!ASQ.isMessageWrapper(err)) { + err = [err]; + } + done.fail.apply(ø,err); + return; + } + + // returned a sequence? + if (ASQ.isSequence(ret)) { + ret.pipe(done); + } + // returned a message wrapper? + else if (ASQ.isMessageWrapper(ret)) { + done.apply(ø,ret); + } + // returned a promise/thenable? + else if (isPromise(ret)) { + ret.then(done,done.fail); + } + // just a normal value to pass along + else { + done(ret); + } + } + else { + done.apply(ø,ARRAY_SLICE.call(arguments,1)); + } + }); + } + if (typeof failure === "function") { + api.or(function $$or(){ + if (!ignore_failure_handler) { + var ret, msgs = ASQ.messages.apply(ø,arguments), smgs, + or_queue = ARRAY_SLICE.call(internals("or_queue")) + ; + + if (msgs.length === 1) { + msgs = msgs[0]; + } + + ignore_success_handler = true; + + // NOTE: if this call throws, that'll automatically + // be handled by core as we'd want it to be + ret = failure(msgs); + + // if we get this far: + // first, inject return value (if any) as + // next step's sequence messages + smgs = internals("sequence_messages"); + smgs.length = 0; + if (typeof ret !== "undefined") { + if (!ASQ.isMessageWrapper(ret)) { + ret = [ret]; + } + smgs.push.apply(smgs,ret); + } + + // reset internal error state, because we've exclusively + // handled any errors up to this point of the sequence + internals("sequence_errors").length = 0; + internals("seq_error",false); + internals("then_ready",true); + + // temporarily empty the or-queue + internals("or_queue").length = 0; + + // make sure to schedule success-procession on the chain + api.val(function $$val(){ + // pass thru messages + return ASQ.messages.apply(ø,arguments); + }); + + // at next cycle, reinstate the or-queue (if any) + if (or_queue.length > 0) { + schedule(function $$schedule(){ + api.or.apply(ø,or_queue); + }); + } + } + }); + } + return api; + }; +}); + +// "pCatch" +ASQ.extend("pCatch",function $$extend(api,internals){ + return function $$pcatch(failure) { + if (internals("seq_aborted")) { + return api; + } + + api.pThen(void 0,failure); + + return api; + }; +}); +// "race" +ASQ.extend("race",function $$extend(api,internals){ + return function $$race() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(v){ + var def; + // tap any directly-provided sequences immediately + if (ASQ.isSequence(v)) { + def = { seq: v }; + tapSequence(def); + return function $$fn(done) { + def.seq.pipe(done); + }; + } + else return v; + }); + + api.then(function $$then(done){ + var args = ARRAY_SLICE.call(arguments); + + fns.forEach(function $$each(fn){ + fn.apply(ø,args); + }); + }); + + return api; + }; +}); +// "react" (reactive sequences) +ASQ.react = function $$react(reactor) { + function next() { + if (!paused) { + if (template) { + var sq = template.duplicate(); + sq.unpause.apply(ø,arguments); + return sq; + } + return ASQ(function $$asq(){ throw "Disabled Sequence"; }); + } + } + + function registerTeardown(fn) { + if (template && typeof fn === "function") { + teardowns.push(fn); + } + } + + var template = ASQ().duplicate(), + teardowns = [], paused = false + ; + + // add reactive sequence kill switch + template.stop = function $$stop() { + if (template) { + template = null; + teardowns.forEach(Function.call,Function.call); + teardowns.length = 0; + } + }; + + template.pause = function $$pause() { + if (!paused && template) { + paused = true; + teardowns.forEach(Function.call,Function.call); + teardowns.length = 0; + } + }; + + template.resume = function $$resume() { + if (paused && template) { + paused = false; + reactor.call(template,next,registerTeardown); + } + }; + + template.push = next; + + next.onStream = function $$onStream() { + ARRAY_SLICE.call(arguments) + .forEach(function $$each(stream){ + stream.on("data",next); + stream.on("error",next); + }); + }; + + next.unStream = function $$unStream() { + ARRAY_SLICE.call(arguments) + .forEach(function $$each(stream){ + stream.removeListener("data",next); + stream.removeListener("error",next); + }); + }; + + // make sure `reactor(..)` is called async + ASQ.__schedule(function $$schedule(){ + reactor.call(template,next,registerTeardown); + }); + + return template; +}; +// "react" helpers +(function IIFE(){ + + var Ar = ASQ.react; + + Ar.of = function $$react$of() { + function reactor(next) { + if (!started) { + started = true; + if (args.length > 0) { + args.shift().val(function val(){ + next.apply(ø,arguments); + if (args.length > 0) { + args.shift().val(val); + } + }); + } + } + } + + var started, args = ARRAY_SLICE.call(arguments) + .map(function wrapper(arg){ + if (!ASQ.isSequence(arg)) arg = ASQ(arg); + return arg; + }); + + return Ar(reactor); + }; + + Ar.all = Ar.zip = makeReactOperator(/*buffer=*/true); + Ar.allLatest = makeReactOperator(/*buffer=false*/); + Ar.latest = Ar.combineLatest = makeReactOperator(/*buffer=*/false,/*keep=*/true); + + Ar.any = Ar.merge = function $$react$any(){ + function reactor(next,registerTeardown){ + function processSequence(def){ + function trigger(){ + var args = ASQ.messages.apply(ø,arguments); + // still observing sequence-streams? + if (seqs && seqs.length > 0) { + // fire off reactive sequence instance + next.apply(ø,args); + } + // keep sequence going + return args; + } + + // sequence-stream event listener + def.seq.val(trigger); + } + + // observe all sequence-streams + seqs.forEach(processSequence); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + seqs = null; + }); + } + + // observe all sequence-streams + var seqs = tapSequences.apply(null,arguments); + + if (seqs.length == 0) return; + + return Ar(reactor); + }; + + Ar.distinct = function $$react$distinct(seq){ + return Ar.filter(seq,makeDistinctFilterer(/*keepAll=*/true)); + }; + + Ar.distinctConsecutive = Ar.distinctUntilChanged = function $$react$distinct$consecutive(seq) { + return Ar.filter(seq,makeDistinctFilterer(/*keepAll=*/false)); + }; + + Ar.filter = function $$react$filter(seq,filterer){ + function reactor(next,registerTeardown) { + function trigger(){ + var messages = ASQ.messages.apply(ø,arguments); + + if (filterer && filterer.apply(ø,messages)) { + // fire off reactive sequence instance + next.apply(ø,messages); + } + + // keep sequence going + return messages; + } + + // sequence-stream event listener + def.seq.val(trigger); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + def = filterer = null; + }); + } + + // observe sequence-stream + var def = tapSequences(seq)[0]; + + if (!def) return; + + return Ar(reactor); + }; + + Ar.fromObservable = function $$react$from$observable(obsv){ + function reactor(next,registerTeardown){ + // process buffer (if any) + buffer.forEach(next); + buffer.length = 0; + + // start non-buffered notifications? + if (!buffer.complete) { + notify = next; + } + + registerTeardown(function $$teardown(){ + obsv.dispose(); + }); + } + + function notify(v) { + buffer.push(v); + } + + var buffer = []; + + obsv.subscribe( + function $$on$next(v){ + notify(v); + }, + function $$on$error(){}, + function $$on$complete(){ + buffer.complete = true; + obsv.dispose(); + } + ); + + return Ar(reactor); + }; + + ASQ.extend("toObservable",function $$extend(api,internals){ + return function $$to$observable(){ + function init(observer) { + function define(pair){ + function listen(){ + var args = ASQ.messages.apply(ø,arguments); + observer[pair[1]].apply(observer, + args.length == 1 ? [args[0]] : args + ); + return args; + } + + api[pair[0]](listen); + } + + [["val","onNext"],["or","onError"]] + .forEach(define); + } + + return Rx.Observable.create(init); + }; + }); + + function tapSequences() { + function tapSequence(seq) { + // temporary `trigger` which, if called before being replaced + // below, creates replacement proxy sequence with the + // event message(s) re-fired + function trigger() { + var args = ARRAY_SLICE.call(arguments); + def.seq = Ar(function $$react(next){ + next.apply(ø,args); + }); + } + + if (ASQ.isSequence(seq)) { + var def = { seq: seq }; + + // listen for events from the sequence-stream + seq.val(function $$val(){ + trigger.apply(ø,arguments); + return ASQ.messages.apply(ø,arguments); + }); + + // make a reactive sequence to act as a proxy to the original + // sequence + def.seq = Ar(function $$react(next){ + // replace the temporary trigger (created above) + // with this proxy's trigger + trigger = next; + }); + + return def; + } + } + + return ARRAY_SLICE.call(arguments) + .map(tapSequence) + .filter(Boolean); + } + + function makeReactOperator(buffer,keep) { + return function $$react$operator(){ + function reactor(next,registerTeardown){ + function processSequence(def) { + // sequence-stream event listener + function trigger() { + var args = ASQ.messages.apply(ø,arguments); + // still observing sequence-streams? + if (seqs && seqs.length > 0) { + // store event message(s), if any + seq_events[seq_id] = + (buffer ? seq_events[seq_id] : []).concat( + args.length > 0 ? (args.length > 1 ? [args] : args[0]) : undefined + ); + + // collect event message(s) across the + // sequence-stream sources + var messages = seq_events.reduce(function reducer(msgs,eventList,idx){ + if (eventList.length > 0) msgs.push(eventList[0]); + return msgs; + },[]); + + // did all sequence-streams get an event? + if (messages.length == seq_events.length) { + if (messages.length == 1) messages = messages[0]; + + // fire off reactive sequence instance + next.apply(ø,messages); + + // discard stored event message(s)? + if (!keep) { + seq_events.forEach(function $$each(eventList){ + eventList.shift(); + }); + } + } + } + // keep sequence going + return args; + } + + var seq_id = seq_events.length; + seq_events.push([]); + def.seq.val(trigger); + } + + // process all sequence-streams + seqs.forEach(processSequence); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + seqs = seq_events = null; + }); + } + + var seq_events = [], + // observe all sequence-streams + seqs = tapSequences.apply(null,arguments) + ; + + if (seqs.length == 0) return; + + return Ar(reactor); + }; + } + + function makeDistinctFilterer(keepAll) { + function filterer() { + function isDuplicate(msgSet) { + return ( + msgSet.length == message_set.length && + msgSet.every(function $$every(val,idx){ + return val === message_set[idx]; + }) + ); + } + + var message_set = ASQ.messages.apply(ø,arguments); + + // any messages in message-set to check against? + if (message_set.length > 0) { + // duplicate message-set? + if (msg_sets.some(isDuplicate)) { + return false; + } + + // remember all message-sets for future distinct checking? + if (keepAll) { + msg_sets.push(message_set); + } + // only keep the last message-set for distinct-consecutive + // checking + else { + msg_sets[0] = message_set; + } + } + + // allow distinct non-duplicate value through + return true; + } + + var msg_sets = []; + + return filterer; + } + +})(); +// "runner" +ASQ.extend("runner",function $$extend(api,internals){ + + return function $$runner() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var args = ARRAY_SLICE.call(arguments); + + api + .then(function $$then(mainDone){ + + function wrap(v) { + // function? expected to produce an iterator + // (like a generator) or a promise + if (typeof v === "function") { + // call function passing in the control token + // note: neutralize `this` in call to prevent + // unexpected behavior + v = v.call(ø,token); + + // promise returned (ie, from async function)? + if (isPromise(v)) { + // wrap it in iterable sequence + v = ASQ.iterable(v); + } + } + // an iterable sequence? duplicate it (in case of multiple runs) + else if (ASQ.isSequence(v) && "next" in v) { + v = v.duplicate(); + } + // wrap anything else in iterable sequence + else { + v = ASQ.iterable(v); + } + + // a sequence to tap for errors? + if (ASQ.isSequence(v)) { + // listen for any sequence failures + v.or(function $$or(){ + // signal iteration-error + mainDone.fail.apply(ø,arguments); + }); + } + + return v; + } + + function addWrapped() { + iterators.push.apply( + iterators, + ARRAY_SLICE.call(arguments).map(wrap) + ); + } + + function iterateOrQuit(iterFn,now) { + // still have some co-routine runs to process? + if (iterators.length > 0) { + if (now) iterFn(); + else schedule(iterFn); + } + // all done! + else { + // previous value message? + if (typeof next_val !== "undefined") { + // not a message wrapper array? + if (!ASQ.isMessageWrapper(next_val)) { + // wrap value for the subsequent `apply(..)` + next_val = [next_val]; + } + } + else { + // nothing to affirmatively pass along + next_val = []; + } + + // signal done with all co-routine runs + mainDone.apply(ø,next_val); + } + } + + var iterators = args, + token = { + messages: ARRAY_SLICE.call(arguments,1), + add: addWrapped + }, + iter, ret, next_val = token + ; + + // map co-routines to round-robin list of iterators + iterators = iterators.map(wrap); + + // async iteration of round-robin list + (function iterate(){ + // get next co-routine in list + iter = iterators.shift(); + + // process the iteration + try { + // multiple messages to send to an iterable + // sequence? + if (ASQ.isMessageWrapper(next_val) && + ASQ.isSequence(iter) + ) { + ret = iter.next.apply(iter,next_val); + } + else { + ret = iter.next(next_val); + } + } + catch (err) { + return mainDone.fail(err); + } + + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + // was the control token yielded? + if (ret.value === token) { + // round-robin: put co-routine back into the list + // at the end where it was so it can be processed + // again on next loop-iteration + if (!ret.done) { + iterators.push(iter); + } + next_val = token; + iterateOrQuit(iterate,/*now=*/false); + } + else { + // not a recognized ASQ instance returned? + if (!ASQ.isSequence(ret.value)) { + // received a thenable/promise back? + if (isPromise(ret.value)) { + // wrap in a sequence + ret.value = ASQ().promise(ret.value); + } + // thunk yielded? + else if (typeof ret.value === "function") { + // wrap thunk call in a sequence + var fn = ret.value; + ret.value = ASQ(function $$ASQ(done){ + fn(done.errfcb); + }); + } + // message wrapper returned? + else if (ASQ.isMessageWrapper(ret.value)) { + // wrap message(s) in a sequence + ret.value = ASQ.apply(ø, + // don't let `apply(..)` discard an empty message + // wrapper! instead, pass it along as its own value + // itself. + ret.value.length > 0 ? ret.value : ASQ.messages(undefined) + ); + } + // non-undefined value returned? + else if (typeof ret.value !== "undefined") { + // wrap the value in a sequence + ret.value = ASQ(ret.value); + } + else { + // make an empty sequence + ret.value = ASQ(); + } + } + + ret.value + .val(function $$val(){ + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + if (arguments.length > 0) { + // save any return messages for input + // to next iteration + next_val = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + } + + // still more to iterate? + if (!ret.done) { + // was the control token passed along? + if (next_val === token) { + // round-robin: put co-routine back into the list + // at the end, so that the the next iterator can be + // processed on next loop-iteration + iterators.push(iter); + } + else { + // put co-routine back in where it just + // was so it can be processed again on + // next loop-iteration + iterators.unshift(iter); + } + } + + iterateOrQuit(iterate,/*now=*/true); + }) + .or(function $$or(){ + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + try { + // if an error occurs in the step-continuation + // promise or sequence, throw it back into the + // generator or iterable-sequence + iter["throw"].apply(iter,arguments); + } + catch (err) { + // if an error comes back out of after the throw, + // pass it out to the main sequence, as iteration + // must now be complete + mainDone.fail(err); + } + }); + } + })(); + }); + + return api; + }; +}); +// "toPromise" +ASQ.extend("toPromise",function $$extend(api,internals){ + return function $$to$promise() { + return new Promise(function $$executor(resolve,reject){ + api + .val(function $$val(){ + var args = ARRAY_SLICE.call(arguments); + resolve.call(ø,args.length > 1 ? args : args[0]); + return ASQ.messages.apply(ø,args); + }) + .or(function $$or(){ + var args = ARRAY_SLICE.call(arguments); + reject.call(ø,args.length > 1 ? args : args[0]); + }); + }); + }; +}); +// "try" +ASQ.extend("try",function $$extend(api,internals){ + return function $$try() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(fn){ + return function $$then(mainDone) { + var main_args = ARRAY_SLICE.call(arguments), + sq = ASQ.apply(ø,main_args.slice(1)) + ; + + sq + .then(function $$inner$then(){ + fn.apply(ø,arguments); + }) + .val(function $$val(){ + mainDone.apply(ø,arguments); + }) + .or(function $$inner$or(){ + var msgs = ASQ.messages.apply(ø,arguments); + // failed, so map error(s) as `catch` + mainDone({ + "catch": msgs.length > 1 ? msgs : msgs[0] + }); + }); + }; + }); + + api.then.apply(ø,fns); + + return api; + }; +}); +// "until" +ASQ.extend("until",function $$extend(api,internals){ + return function $$until() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(fn){ + return function $$then(mainDone) { + var main_args = ARRAY_SLICE.call(arguments), + sq = ASQ.apply(ø,main_args.slice(1)) + ; + + sq + .then(function $$inner$then(){ + var args = ARRAY_SLICE.call(arguments); + args[0]["break"] = function $$break(){ + mainDone.fail.apply(ø,arguments); + sq.abort(); + }; + + fn.apply(ø,args); + }) + .val(function $$val(){ + mainDone.apply(ø,arguments); + }) + .or(function $$inner$or(){ + // failed, retry + $$then.apply(ø,main_args); + }); + }; + }); + + api.then.apply(ø,fns); + + return api; + }; +}); +// "waterfall" +ASQ.extend("waterfall",function $$extend(api,internals){ + return function $$waterfall() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + var msgs = ASQ.messages(), + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + fns.forEach(function $$each(fn){ + sq.then(fn) + .val(function $$val(){ + var args = ASQ.messages.apply(ø,arguments); + msgs.push(args.length > 1 ? args : args[0]); + return msgs; + }); + }); + + sq.pipe(done); + }); + + return api; + }; +}); +// "wrap" +ASQ.wrap = function $$wrap(fn,opts) { + function checkThis(t,o) { + return (!t || + (typeof window != "undefined" && t === window) || + (typeof global != "undefined" && t === global) + ) ? o : t; + } + + function paramSpread(gen) { + return function *paramSpread(token) { + yield *gen.apply(this,token.messages); + }; + } + + var errfcb, params_first, act, this_obj; + + opts = (opts && typeof opts == "object") ? opts : {}; + + if ( + (opts.errfcb && opts.splitcb) || + (opts.errfcb && opts.simplecb) || + (opts.splitcb && opts.simplecb) || + ("errfcb" in opts && !opts.errfcb && !opts.splitcb && !opts.simplecb) || + (opts.params_first && opts.params_last) || + (opts.spread && !opts.gen) + ) { + throw Error("Invalid options"); + } + + // initialize default flags + this_obj = (opts["this"] && typeof opts["this"] == "object") ? opts["this"] : ø; + errfcb = opts.errfcb || !(opts.splitcb || opts.simplecb); + params_first = !!opts.params_first || + (!opts.params_last && !("params_first" in opts || opts.params_first)) || + ("params_last" in opts && !opts.params_first && !opts.params_last) + ; + + if (params_first) { + act = "push"; + } + else { + act = "unshift"; + } + + if (opts.gen) { + if (opts.spread) { + fn = paramSpread(fn); + } + return function $$wrapped$gen() { + return ASQ.apply(ø,arguments).runner(fn); + }; + } + if (errfcb) { + return function $$wrapped$errfcb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done.errfcb); + fn.apply(_this,args); + }); + }; + } + if (opts.splitcb) { + return function $$wrapped$splitcb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done,done.fail); + fn.apply(_this,args); + }); + }; + } + if (opts.simplecb) { + return function $$wrapped$simplecb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done); + fn.apply(_this,args); + }); + }; + } +}; + + + // just return `ASQ` itself for convenience sake + return ASQ; +}); diff --git a/frontend-masters-exercises/exercises/ex5/ex5-fixed.html b/frontend-masters-exercises/exercises/ex5/ex5-fixed.html new file mode 100755 index 0000000..1b24ff3 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex5/ex5-fixed.html @@ -0,0 +1,14 @@ + + + + +Exercise 5 - Fixed + + +

Exercise 5 - Fixed

+ + + + + + diff --git a/frontend-masters-exercises/exercises/ex5/ex5-fixed.js b/frontend-masters-exercises/exercises/ex5/ex5-fixed.js new file mode 100755 index 0000000..3ba5bbb --- /dev/null +++ b/frontend-masters-exercises/exercises/ex5/ex5-fixed.js @@ -0,0 +1,43 @@ +function fakeAjax(url,cb) { + var fake_responses = { + "file1": "The first text", + "file2": "The middle text", + "file3": "The last text" + }; + var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000; + + console.log("Requesting: " + url); + + setTimeout(function(){ + cb(fake_responses[url]); + },randomDelay); +} + +function output(text) { + console.log(text); +} + +// ************************************** + +function getFile(file) { + return ASQ(function(done){ + fakeAjax(file,done); + }); +} + +// Request all files at once in +// "parallel" via `getFile(..)`. +// +// Render as each one finishes, +// but only once previous rendering +// is done. +ASQ() +.seq( getFile("file1") ) +.val( output ) +.seq( getFile("file2") ) +.val( output ) +.seq( getFile("file3") ) +.val( output ) +.val(function(){ + output("Complete!"); +}); diff --git a/frontend-masters-exercises/exercises/ex5/ex5.html b/frontend-masters-exercises/exercises/ex5/ex5.html new file mode 100755 index 0000000..04171dd --- /dev/null +++ b/frontend-masters-exercises/exercises/ex5/ex5.html @@ -0,0 +1,14 @@ + + + + +Exercise 5 + + +

Exercise 5

+ + + + + + diff --git a/frontend-masters-exercises/exercises/ex5/ex5.js b/frontend-masters-exercises/exercises/ex5/ex5.js new file mode 100755 index 0000000..3ba5bbb --- /dev/null +++ b/frontend-masters-exercises/exercises/ex5/ex5.js @@ -0,0 +1,43 @@ +function fakeAjax(url,cb) { + var fake_responses = { + "file1": "The first text", + "file2": "The middle text", + "file3": "The last text" + }; + var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000; + + console.log("Requesting: " + url); + + setTimeout(function(){ + cb(fake_responses[url]); + },randomDelay); +} + +function output(text) { + console.log(text); +} + +// ************************************** + +function getFile(file) { + return ASQ(function(done){ + fakeAjax(file,done); + }); +} + +// Request all files at once in +// "parallel" via `getFile(..)`. +// +// Render as each one finishes, +// but only once previous rendering +// is done. +ASQ() +.seq( getFile("file1") ) +.val( output ) +.seq( getFile("file2") ) +.val( output ) +.seq( getFile("file3") ) +.val( output ) +.val(function(){ + output("Complete!"); +}); diff --git a/frontend-masters-exercises/exercises/ex6/README.md b/frontend-masters-exercises/exercises/ex6/README.md new file mode 100755 index 0000000..476a277 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex6/README.md @@ -0,0 +1,9 @@ +# Instructions + +1. You'll do the same thing as the previous exercise(s), but now you should use map/reduce, asynquence, and an array of files. + +2. Expected behavior: + - Request all 3 files at the same time (in "parallel"). + - Render them ASAP (don't just blindly wait for all to finish loading) + - BUT, render them in proper (obvious) order: "file1", "file2", "file3". + - After all 3 are done, output "Complete!". diff --git a/frontend-masters-exercises/exercises/ex6/asq.bundle.js b/frontend-masters-exercises/exercises/ex6/asq.bundle.js new file mode 100755 index 0000000..93c9ada --- /dev/null +++ b/frontend-masters-exercises/exercises/ex6/asq.bundle.js @@ -0,0 +1,2333 @@ +/*! asynquence + v0.8.2 (c) Kyle Simpson + MIT License: http://getify.mit-license.org +*/ +!function UMD(e,n,t){"function"==typeof define&&define.amd?define(t):"undefined"!=typeof module&&module.exports?module.exports=t():n[e]=t(e,n)}("ASQ",this,function DEF(e,n){"use strict";function Queue(){function Item(e){this.fn=e,this.next=void 0}var e,n,r;return{add:function $$add(t){r=new Item(t),n?n.next=r:e=r,n=r,r=void 0},drain:function $$drain(){var r=e;for(e=n=t=null;r;)r.fn(),r=r.next}}}function schedule(e){r.add(e),t||(t=u(r.drain))}function tapSequence(e){function trigger(){e.seq=createSequence.apply(h,arguments).defer()}trigger.fail=function $$trigger$fail(){var n=f.call(arguments);e.seq=createSequence(function $$create$sequence(e){e.fail.apply(h,n)}).defer()},e.seq.val(function $$val(){return trigger.apply(h,arguments),c.apply(h,arguments)}).or(function $$or(){trigger.fail.apply(h,arguments)}),e.seq=createSequence(function $$create$sequence(e){trigger=e}).defer()}function createSequence(){function scheduleSequenceTick(){r?sequenceTick():e||(e=schedule(sequenceTick))}function throwSequenceErrors(){throw 1===$.length?$[0]:$}function sequenceTick(){var a,c;if(e=null,delete d.unpause,r)clearTimeout(e),e=null,s.length=p.length=g.length=$.length=0;else if(n)for(0!==p.length||t||(t=!0,throwSequenceErrors());p.length;){t=!0,a=p.shift();try{a.apply(h,$)}catch(i){l(i)?$=$.concat(i):($.push(i),i.stack&&$.push(i.stack)),0===p.length&&throwSequenceErrors()}}else if(u&&s.length>0){u=!1,a=s.shift(),c=g.slice(),g.length=0,c.unshift(createStepCompletion());try{a.apply(h,c)}catch(i){l(i)?$=$.concat(i):$.push(i),n=!0,scheduleSequenceTick()}}}function createStepCompletion(){function done(){n||r||u||(u=!0,g.push.apply(g,arguments),$.length=0,scheduleSequenceTick())}return done.fail=function $$step$fail(){n||r||u||(n=!0,g.length=0,$.push.apply($,arguments),scheduleSequenceTick())},done.abort=function $$step$abort(){n||r||(u=!1,r=!0,g.length=$.length=0,scheduleSequenceTick())},done.errfcb=function $$step$errfcb(e){e?done.fail(e):done.apply(h,f.call(arguments,1))},done}function createGate(e,t,u){function resetGate(){clearTimeout(s),s=d=m=o=null}function scheduleGateTick(){return g?gateTick():void(s||(s=schedule(gateTick)))}function gateTick(){if(!(n||r||$)){var t=[];s=null,p?(e.fail.apply(h,o),resetGate()):g?(e.abort(),resetGate()):checkGate()&&($=!0,d.forEach(function $$each(e,n){t.push(m["s"+n])}),e.apply(h,t),resetGate())}}function checkGate(){if(0!==d.length){var e=!0;return d.some(function $$some(n){return null===n?(e=!1,!0):void 0}),e}}function createSegmentCompletion(){function done(){if(!(n||r||p||g||$||d[e])){var t=c.apply(h,arguments);m["s"+e]=t.length>1?t:t[0],d[e]=!0,scheduleGateTick()}}var e=d.length;return done.fail=function $$segment$fail(){n||r||p||g||$||d[e]||(p=!0,o=f.call(arguments),scheduleGateTick())},done.abort=function $$segment$abort(){n||r||p||g||$||(g=!0,gateTick())},done.errfcb=function $$segment$errfcb(e){e?done.fail(e):done.apply(h,f.call(arguments,1))},d[e]=null,done}var a,i,o,s,p=!1,g=!1,$=!1,d=[],m={};t.some(function $$some(e){if(p||g)return!0;a=u.slice(),a.unshift(createSegmentCompletion());try{e.apply(h,a)}catch(n){return i=n,p=!0,!0}}),i&&(l(i)?e.fail.apply(h,i):e.fail(i))}function then(){return n||r||0===arguments.length?d:(wrapArgs(arguments,thenWrapper).forEach(function $$each(e){i(e)?seq(e):s.push(e)}),scheduleSequenceTick(),d)}function or(){return r||0===arguments.length?d:(p.push.apply(p,arguments),scheduleSequenceTick(),d)}function gate(){if(n||r||0===arguments.length)return d;var e=f.call(arguments).map(function $$map(e){var n;return i(e)?(n={seq:e},tapSequence(n),function $$segment(e){n.seq.pipe(e)}):e});return then(function $$then(n){var t=f.call(arguments,1);createGate(n,e,t)}),d}function pipe(){return r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){then(function $$then(n){e.apply(h,f.call(arguments,1)),n()}).or(e.fail)}),d)}function seq(){return n||r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){var n={seq:e};i(e)&&tapSequence(n),then(function $$then(e){var t=n.seq;i(t)||(t=n.seq.apply(h,f.call(arguments,1))),t.pipe(e)})}),d)}function val(){return n||r||0===arguments.length?d:(f.call(wrapArgs(arguments,valWrapper)).forEach(function $$each(e){then(function $$then(n){var t=e.apply(h,f.call(arguments,1));l(t)||(t=c(t)),n.apply(h,t)})}),d)}function promise(){function wrap(e){return function $$fn(){e.apply(h,l(arguments[0])?arguments[0]:arguments)}}return n||r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){then(function $$then(n){var t=e;"function"==typeof e&&"function"!=typeof e.then&&(t=e.apply(h,f.call(arguments,1))),t.then(wrap(n),wrap(n.fail))})}),d)}function fork(){var e;return val(function $$val(){return e?e.apply(h,arguments):e=createSequence.apply(h,arguments).defer(),c.apply(h,arguments)}),or(function $$or(){if(e)e.fail.apply(h,arguments);else{var n=f.call(arguments);e=createSequence().then(function $$then(e){e.fail.apply(h,n)}).defer()}}),createSequence().then(function $$then(n){e?e.pipe(n):e=n}).defer()}function abort(){return n?d:(r=!0,sequenceTick(),d)}function duplicate(){var e;return a={then_queue:s.slice(),or_queue:p.slice()},e=createSequence(),a=null,e}function unpause(){g.push.apply(g,arguments),e===!0&&(e=null),scheduleSequenceTick()}function defer(){return p.push(function ignored(){}),d}function internals(e,t){var a=arguments.length>1;switch(e){case"seq_error":if(!a)return n;n=t;break;case"seq_aborted":if(!a)return r;r=t;break;case"then_ready":if(!a)return u;u=t;break;case"then_queue":return s;case"or_queue":return p;case"sequence_messages":return g;case"sequence_errors":return $}}function includeExtensions(){Object.keys(o).forEach(function $$each(e){d[e]=o[e](d,internals)})}var e,n=!1,t=!1,r=!1,u=!0,s=[],p=[],g=[],$=[],d=brandIt({then:then,or:or,onerror:or,gate:gate,all:gate,pipe:pipe,seq:seq,val:val,promise:promise,fork:fork,abort:abort,duplicate:duplicate,defer:defer});return includeExtensions(),a&&(s=a.then_queue.slice(),p=a.or_queue.slice(),d.unpause=unpause,e=!0),d.then.apply(h,arguments),d}function brandIt(e){return Object.defineProperty(e,p,{enumerable:!1,value:!0})}function checkBranding(e){return!(null==e||"object"!=typeof e||!e[p])}function valWrapper(e){return c.apply(h,f.call(arguments).slice(1,e+1))}function thenWrapper(e){arguments[e+1].apply(h,f.call(arguments).slice(1,e+1))}function wrapArgs(e,n){var t,r;for(e=f.call(e),t=0;t 1 ? + ARRAY_SLICE.call(arguments,1) : + void 0 + ; + num = +num || 0; + + api.then(function $$then(done){ + var args = orig_args || ARRAY_SLICE.call(arguments,1); + + setTimeout(function $$set$timeout(){ + done.apply(ø,args); + },num); + }); + + return api; + }; +}); + +ASQ.after = function $$after() { + return ASQ().after.apply(ø,arguments); +}; +// "any" +ASQ.extend("any",function $$extend(api,internals){ + return function $$any() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages.length = 0; + } + + function complete(trigger) { + if (success_messages.length > 0) { + // any successful segment's message(s) sent + // to main sequence to proceed as success + success_messages.length = fns.length; + trigger.apply(ø,success_messages); + } + else { + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + success_messages = [], + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "errfcb" +ASQ.extend("errfcb",function $$extend(api,internals){ + return function $$errfcb() { + // create a fake sequence to extract the callbacks + var sq = { + val: function $$then(cb){ sq.val_cb = cb; return sq; }, + or: function $$or(cb){ sq.or_cb = cb; return sq; } + }; + + // trick `seq(..)`s checks for a sequence + sq[brand] = true; + + // immediately register our fake sequence on the + // main sequence + api.seq(sq); + + // provide the "error-first" callback + return function $$errorfirst$callback(err) { + if (err) { + sq.or_cb(err); + } + else { + sq.val_cb.apply(ø,ARRAY_SLICE.call(arguments,1)); + } + }; + }; +}); +// "failAfter" +ASQ.extend("failAfter",function $$extend(api,internals){ + return function $$failAfter(num) { + var args = arguments.length > 1 ? + ARRAY_SLICE.call(arguments,1) : + void 0 + ; + num = +num || 0; + + api.then(function $$then(done){ + setTimeout(function $$set$timeout(){ + done.fail.apply(ø,args); + },num); + }); + + return api; + }; +}); + +ASQ.failAfter = function $$fail$after() { + return ASQ().failAfter.apply(ø,arguments); +}; +// "first" +ASQ.extend("first",function $$extend(api,internals){ + return function $$first() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + error_messages.length = 0; + } + + function success(trigger,idx,args) { + if (!finished) { + finished = true; + + // first successful segment triggers + // main sequence to proceed as success + trigger( + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ); + + reset(); + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete without success? + if (completed === fns.length) { + finished = true; + + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + + reset(); + } + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "go-style CSP" +(function IIFE(){ + + // filter out already-resolved queue entries + function filterResolved(queue) { + return queue.filter(function $$filter(entry){ + return !entry.resolved; + }); + } + + function closeQueue(queue,finalValue) { + queue.forEach(function $$each(iter){ + if (!iter.resolved) { + iter.next(); + iter.next(finalValue); + } + }); + queue.length = 0; + } + + function channel(bufSize) { + var ch = { + close: function $$close(){ + ch.closed = true; + closeQueue(ch.put_queue,false); + closeQueue(ch.take_queue,ASQ.csp.CLOSED); + }, + closed: false, + messages: [], + put_queue: [], + take_queue: [], + buffer_size: +bufSize || 0 + }; + return ch; + } + + function unblock(iter) { + if (iter && !iter.resolved) { + iter.next(iter.next().value); + } + } + + function put(channel,value) { + var ret; + + if (channel.closed) { + return false; + } + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + // immediate put? + if (channel.messages.length < channel.buffer_size) { + channel.messages.push(value); + unblock(channel.take_queue.shift()); + return true; + } + // queued put + else { + channel.put_queue.push( + // make a notifiable iterable for 'put' blocking + ASQ.iterable() + .then(function $$then(){ + if (!channel.closed) { + channel.messages.push(value); + return true; + } + else { + return false; + } + }) + ); + + // wrap a sequence/promise around the iterable + ret = ASQ( + channel.put_queue[channel.put_queue.length - 1] + ); + + // take waiting on this queued put? + if (channel.take_queue.length > 0) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + + return ret; + } + } + + function putAsync(channel,value,cb) { + var ret = ASQ(put(channel,value)); + + if (cb && typeof cb == "function") { + ret.val(cb); + } + else { + return ret; + } + } + + function take(channel) { + var ret; + + try { + ret = takem(channel); + } + catch (err) { + ret = err; + } + + if (ASQ.isSequence(ret)) { + ret.pCatch(function $$pcatch(err){ + return err; + }); + } + + return ret; + } + + function takeAsync(channel,cb) { + var ret = ASQ(take(channel)); + + if (cb && typeof cb == "function") { + ret.val(cb); + } + else { + return ret; + } + } + + function takem(channel) { + var msg; + + if (channel.closed) { + return ASQ.csp.CLOSED; + } + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + // immediate take? + if (channel.messages.length > 0) { + msg = channel.messages.shift(); + unblock(channel.put_queue.shift()); + if (msg instanceof Error) { + throw msg; + } + return msg; + } + // queued take + else { + channel.take_queue.push( + // make a notifiable iterable for 'take' blocking + ASQ.iterable() + .then(function $$then(){ + if (!channel.closed) { + var v = channel.messages.shift(); + if (v instanceof Error) { + throw v; + } + return v; + } + else { + return ASQ.csp.CLOSED; + } + }) + ); + + // wrap a sequence/promise around the iterable + msg = ASQ( + channel.take_queue[channel.take_queue.length - 1] + ); + + // put waiting on this take? + if (channel.put_queue.length > 0) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + + return msg; + } + } + + function takemAsync(channel,cb) { + var ret = ASQ(takem(channel)); + + if (cb && typeof cb == "function") { + ret.pThen(cb,cb); + } + else { + return ret.val(function $$val(v){ + if (v instanceof Error) { + throw v; + } + return v; + }); + } + } + + function alts(actions) { + var closed, open, handlers, i, isq, ret, resolved = false; + + // used `alts(..)` incorrectly? + if (!Array.isArray(actions) || actions.length == 0) { + throw Error("Invalid usage"); + } + + closed = []; + open = []; + handlers = []; + + // separate actions by open/closed channel status + actions.forEach(function $$each(action){ + var channel = Array.isArray(action) ? action[0] : action; + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + if (channel.closed) { + closed.push(channel); + } + else { + open.push(action); + } + }); + + // if no channels are still open, we're done + if (open.length == 0) { + return { value: ASQ.csp.CLOSED, channel: closed }; + } + + // can any channel action be executed immediately? + for (i=0; i 0) { + return { value: take(open[i]), channel: open[i] }; + } + } + + isq = ASQ.iterable(); + var ret = ASQ(isq); + + // setup channel action handlers + for (i=0; i 0) { + schedule(function handleUnblocking(){ + if (!resolved) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + },0); + } + } + // take action? + else { + channel = action; + + // define take handler + handlers.push( + ASQ.iterable() + .then(function $$then(){ + resolved = true; + + // mark all handlers across this `alts(..)` as resolved now + handlers = handlers.filter(function $$filter(handler){ + return !(handler.resolved = true); + }); + + // channel still open? + if (!channel.closed) { + isq.next({ value: channel.messages.shift(), channel: channel }); + } + // channel already closed? + else { + isq.next({ value: ASQ.csp.CLOSED, channel: channel }); + } + }) + ); + + // queue up take handler + channel.take_queue.push(handlers[handlers.length-1]); + + // put waiting on this queued take? + if (channel.put_queue.length > 0) { + schedule(function handleUnblocking(){ + if (!resolved) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + }); + } + } + })(open[i]); + } + + return ret; + } + + function altsAsync(chans,cb) { + var ret = ASQ(alts(chans)); + + if (cb && typeof cb == "function") { + ret.pThen(cb,cb); + } + else { + return ret; + } + } + + function timeout(delay) { + var ch = channel(); + setTimeout(ch.close,delay); + return ch; + } + + function go(gen,args) { + // goroutine arguments passed? + if (arguments.length > 1) { + if (!args || !Array.isArray(args)) { + args = [args]; + } + } + else { + args = []; + } + + return function *$$go(token) { + + // unblock the overall goroutine handling + function unblock() { + token.unblock_count++; + + if (token.block && !token.block.marked) { + token.block.marked = true; + token.block.next(); + } + } + + var ret, msg, err, type, done = false, it; + + // keep track of how many requests for unblocking + // have occurred + token.unblock_count = (token.unblock_count || 0); + + // keep track of how many goroutines are running + // so we can infer when we're done go'ing + token.go_count = (token.go_count || 0) + 1; + + // need to initialize a set of goroutines? + if (token.go_count === 1) { + // create a default channel for these goroutines + token.channel = channel(); + token.channel.messages = token.messages; + token.channel.go = function $$go(){ + // unblock the goroutine handling for this + // new goroutine + unblock(); + // add the goroutine (called with any args) to + // the handling queue + token.add( go.apply(ø,arguments) ); + }; + // starting out with initial channel messages? + if (token.channel.messages.length > 0) { + // fake back-pressure blocking for each + token.channel.put_queue = token.channel.messages.map(function $$map(){ + // make a notifiable iterable for 'put' blocking + return ASQ.iterable() + .then(function $$then(){ + unblock(token.channel.take_queue.shift()); + return !token.channel.closed; + }); + }); + } + } + + // initialize the generator + it = gen.apply(ø,[token.channel].concat(args)); + + (function iterate(){ + + function next() { + // keep going with next step in goroutine? + if (!done) { + iterate(); + } + // unblock overall goroutine handling to + // continue with other goroutines + else { + unblock(); + } + } + + // has a resumption value been achieved yet? + if (!ret) { + // try to resume the goroutine + try { + // resume with injected exception? + if (err) { + ret = it.throw(err); + err = null; + } + // resume normally + else { + ret = it.next(msg); + } + } + // resumption failed, so bail + catch (e) { + done = true; + err = e; + msg = null; + unblock(); + return; + } + + // keep track of the result of the resumption + done = ret.done; + ret = ret.value; + type = typeof ret; + + // if this goroutine is complete, unblock the + // overall goroutine handling + if (done) { + unblock(); + } + + // received a thenable/promise back? + if (isPromise(ret)) { + ret = ASQ().promise(ret); + } + + // wait for the value? + if (ASQ.isSequence(ret)) { + ret.val(function $$val(){ + ret = null; + msg = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + next(); + }) + .or(function $$or(){ + ret = null; + msg = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + if (msg instanceof Error) { + err = msg; + msg = null; + } + next(); + }); + } + // immediate value, prepare it to go right back in + else { + msg = ret; + ret = null; + next(); + } + } + })(); + + // keep this goroutine alive until completion + while (!done) { + // transfer control to another goroutine + yield token; + + // need to block overall goroutine handling + // while idle? + if (!done && !token.block && token.unblock_count === 0) { + // wait here while idle + yield (token.block = ASQ.iterable()); + + token.block = false; + } + + if (token.unblock_count > 0) token.unblock_count--; + } + + // this goroutine is done now + token.go_count--; + + // all goroutines done? + if (token.go_count === 0) { + // any lingering blocking need to be cleaned up? + unblock(); + + // capture any untaken messages + msg = ASQ.messages.apply(ø,token.messages); + + // need to implicitly force-close channel? + if (token.channel && !token.channel.closed) { + token.channel.closed = true; + token.channel.put_queue.length = token.channel.take_queue.length = 0; + token.channel.close = token.channel.go = token.channel.messages = null; + } + token.channel = null; + } + + // make sure leftover error or message are + // passed along + if (err) { + throw err; + } + else if (token.go_count === 0) { + return msg; + } + else { + return token; + } + }; + } + + ASQ.csp = { + chan: channel, + put: put, + putAsync: putAsync, + take: take, + takeAsync: takeAsync, + takem: takem, + takemAsync: takemAsync, + alts: alts, + altsAsync: altsAsync, + timeout: timeout, + go: go, + CLOSED: {} + }; + +})(); +// "ASQ.iterable()" +(function IIFE(){ + var template; + + ASQ.iterable = function $$iterable() { + function throwSequenceErrors() { + throw (sequence_errors.length === 1 ? sequence_errors[0] : sequence_errors); + } + + function notifyErrors() { + var fn; + + seq_tick = null; + + if (seq_error) { + if (or_queue.length === 0 && !error_reported) { + error_reported = true; + throwSequenceErrors(); + } + + while (or_queue.length > 0) { + error_reported = true; + fn = or_queue.shift(); + try { + fn.apply(ø,sequence_errors); + } + catch (err) { + if (checkBranding(err)) { + sequence_errors = sequence_errors.concat(err); + } + else { + sequence_errors.push(err); + } + if (or_queue.length === 0) { + throwSequenceErrors(); + } + } + } + } + } + + function val() { + if (seq_error || seq_aborted || arguments.length === 0) { + return sequence_api; + } + + var args = ARRAY_SLICE.call(arguments).map(function mapper(arg){ + if (typeof arg != "function") return function $$val() { return arg; }; + else return arg; + }); + + val_queue.push.apply(val_queue,args); + + return sequence_api; + } + + function or() { + if (seq_aborted || arguments.length === 0) { + return sequence_api; + } + + or_queue.push.apply(or_queue,arguments); + + if (!seq_tick) { + seq_tick = schedule(notifyErrors); + } + + return sequence_api; + } + + function pipe() { + if (seq_aborted || arguments.length === 0) { + return sequence_api; + } + + ARRAY_SLICE.call(arguments) + .forEach(function $$each(fn){ + val(fn).or(fn.fail); + }); + + return sequence_api; + } + + function next() { + if (seq_error || seq_aborted || val_queue.length === 0) { + if (val_queue.length > 0) { + $throw$("Sequence cannot be iterated"); + } + return { done: true }; + } + + try { + return { value: val_queue.shift().apply(ø,arguments) }; + } + catch (err) { + if (ASQ.isMessageWrapper(err)) { + $throw$.apply(ø,err); + } + else { + $throw$(err); + } + + return {}; + } + } + + function $throw$() { + if (seq_error || seq_aborted) { + return sequence_api; + } + + sequence_errors.push.apply(sequence_errors,arguments); + seq_error = true; + if (!seq_tick) { + seq_tick = schedule(notifyErrors); + } + + return sequence_api; + } + + function $return$(val) { + if (seq_error || seq_aborted) { + val = void 0; + } + + abort(); + + return { done: true, value: val }; + } + + function abort() { + if (seq_error || seq_aborted) { + return; + } + + seq_aborted = true; + + clearTimeout(seq_tick); + seq_tick = null; + val_queue.length = or_queue.length = sequence_errors.length = 0; + } + + function duplicate() { + var isq; + + template = { + val_queue: val_queue.slice(), + or_queue: or_queue.slice() + }; + isq = ASQ.iterable(); + template = null; + + return isq; + } + + // opt-out of global error reporting for this sequence + function defer() { + or_queue.push(function $$ignored(){}); + return sequence_api; + } + + // *********************************************** + // Object branding utilities + // *********************************************** + function brandIt(obj) { + Object.defineProperty(obj,brand,{ + enumerable: false, + value: true + }); + + return obj; + } + + var sequence_api, + + seq_error = false, + error_reported = false, + seq_aborted = false, + + seq_tick, + + val_queue = [], + or_queue = [], + + sequence_errors = [] + ; + + // *********************************************** + // Setup the ASQ.iterable() public API + // *********************************************** + sequence_api = brandIt({ + val: val, + then: val, + or: or, + pipe: pipe, + next: next, + "throw": $throw$, + "return": $return$, + abort: abort, + duplicate: duplicate, + defer: defer + }); + + // useful for ES6 `for..of` loops, + // add `@@iterator` to simply hand back + // our iterable sequence itself! + sequence_api[(typeof Symbol == "function" && Symbol.iterator) || "@@iterator"] = function $$iter() { + return sequence_api; + }; + + // templating the iterable-sequence setup? + if (template) { + val_queue = template.val_queue.slice(0); + or_queue = template.or_queue.slice(0); + } + + // treat ASQ.iterable() constructor parameters as having been + // passed to `val()` + sequence_api.val.apply(ø,arguments); + + return sequence_api; + }; + +})(); +// "last" +ASQ.extend("last",function $$extend(api,internals){ + return function $$last() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages = null; + } + + function complete(trigger) { + if (success_messages != null) { + // last successful segment's message(s) sent + // to main sequence to proceed as success + trigger( + success_messages.length > 1 ? + ASQ.messages.apply(ø,success_messages) : + success_messages[0] + ); + } + else { + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages = args; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)), + success_messages + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "map" +ASQ.extend("map",function $$extend(api,internals){ + return function $$map(pArr,pEach) { + if (internals("seq_error") || internals("seq_aborted")) { + return api; + } + + api.seq(function $$seq(){ + var tmp, args = ARRAY_SLICE.call(arguments), + arr = pArr, each = pEach; + + // if missing `map(..)` args, use value-messages (if any) + if (!each) each = args.shift(); + if (!arr) arr = args.shift(); + + // if arg types in reverse order (each,arr), swap + if (typeof arr === "function" && Array.isArray(each)) { + tmp = arr; + arr = each; + each = tmp; + } + + return ASQ.apply(ø,args) + .gate.apply(ø,arr.map(function $$map(item){ + return function $$segment(){ + each.apply(ø,[item].concat(ARRAY_SLICE.call(arguments))); + }; + })); + }) + .val(function $$val(){ + // collect all gate segment output into one value-message + // Note: return a normal array here, not a message wrapper! + return ARRAY_SLICE.call(arguments); + }); + + return api; + }; +}); +// "none" +ASQ.extend("none",function $$extend(api,internals){ + return function $$none() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages.length = 0; + } + + function complete(trigger) { + if (success_messages.length > 0) { + // any successful segment's message(s) sent + // to main sequence to proceed as **error** + success_messages.length = fns.length; + trigger.fail.apply(ø,success_messages); + } + else { + // send errors as **success** to main sequence + error_messages.length = fns.length; + trigger.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)), + success_messages = [] + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "pThen" +ASQ.extend("pThen",function $$extend(api,internals){ + return function $$pthen(success,failure) { + if (internals("seq_aborted")) { + return api; + } + + var ignore_success_handler = false, ignore_failure_handler = false; + + if (typeof success === "function") { + api.then(function $$then(done){ + if (!ignore_success_handler) { + var ret, msgs = ASQ.messages.apply(ø,arguments); + msgs.shift(); + + if (msgs.length === 1) { + msgs = msgs[0]; + } + + ignore_failure_handler = true; + + try { + ret = success(msgs); + } + catch (err) { + if (!ASQ.isMessageWrapper(err)) { + err = [err]; + } + done.fail.apply(ø,err); + return; + } + + // returned a sequence? + if (ASQ.isSequence(ret)) { + ret.pipe(done); + } + // returned a message wrapper? + else if (ASQ.isMessageWrapper(ret)) { + done.apply(ø,ret); + } + // returned a promise/thenable? + else if (isPromise(ret)) { + ret.then(done,done.fail); + } + // just a normal value to pass along + else { + done(ret); + } + } + else { + done.apply(ø,ARRAY_SLICE.call(arguments,1)); + } + }); + } + if (typeof failure === "function") { + api.or(function $$or(){ + if (!ignore_failure_handler) { + var ret, msgs = ASQ.messages.apply(ø,arguments), smgs, + or_queue = ARRAY_SLICE.call(internals("or_queue")) + ; + + if (msgs.length === 1) { + msgs = msgs[0]; + } + + ignore_success_handler = true; + + // NOTE: if this call throws, that'll automatically + // be handled by core as we'd want it to be + ret = failure(msgs); + + // if we get this far: + // first, inject return value (if any) as + // next step's sequence messages + smgs = internals("sequence_messages"); + smgs.length = 0; + if (typeof ret !== "undefined") { + if (!ASQ.isMessageWrapper(ret)) { + ret = [ret]; + } + smgs.push.apply(smgs,ret); + } + + // reset internal error state, because we've exclusively + // handled any errors up to this point of the sequence + internals("sequence_errors").length = 0; + internals("seq_error",false); + internals("then_ready",true); + + // temporarily empty the or-queue + internals("or_queue").length = 0; + + // make sure to schedule success-procession on the chain + api.val(function $$val(){ + // pass thru messages + return ASQ.messages.apply(ø,arguments); + }); + + // at next cycle, reinstate the or-queue (if any) + if (or_queue.length > 0) { + schedule(function $$schedule(){ + api.or.apply(ø,or_queue); + }); + } + } + }); + } + return api; + }; +}); + +// "pCatch" +ASQ.extend("pCatch",function $$extend(api,internals){ + return function $$pcatch(failure) { + if (internals("seq_aborted")) { + return api; + } + + api.pThen(void 0,failure); + + return api; + }; +}); +// "race" +ASQ.extend("race",function $$extend(api,internals){ + return function $$race() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(v){ + var def; + // tap any directly-provided sequences immediately + if (ASQ.isSequence(v)) { + def = { seq: v }; + tapSequence(def); + return function $$fn(done) { + def.seq.pipe(done); + }; + } + else return v; + }); + + api.then(function $$then(done){ + var args = ARRAY_SLICE.call(arguments); + + fns.forEach(function $$each(fn){ + fn.apply(ø,args); + }); + }); + + return api; + }; +}); +// "react" (reactive sequences) +ASQ.react = function $$react(reactor) { + function next() { + if (!paused) { + if (template) { + var sq = template.duplicate(); + sq.unpause.apply(ø,arguments); + return sq; + } + return ASQ(function $$asq(){ throw "Disabled Sequence"; }); + } + } + + function registerTeardown(fn) { + if (template && typeof fn === "function") { + teardowns.push(fn); + } + } + + var template = ASQ().duplicate(), + teardowns = [], paused = false + ; + + // add reactive sequence kill switch + template.stop = function $$stop() { + if (template) { + template = null; + teardowns.forEach(Function.call,Function.call); + teardowns.length = 0; + } + }; + + template.pause = function $$pause() { + if (!paused && template) { + paused = true; + teardowns.forEach(Function.call,Function.call); + teardowns.length = 0; + } + }; + + template.resume = function $$resume() { + if (paused && template) { + paused = false; + reactor.call(template,next,registerTeardown); + } + }; + + template.push = next; + + next.onStream = function $$onStream() { + ARRAY_SLICE.call(arguments) + .forEach(function $$each(stream){ + stream.on("data",next); + stream.on("error",next); + }); + }; + + next.unStream = function $$unStream() { + ARRAY_SLICE.call(arguments) + .forEach(function $$each(stream){ + stream.removeListener("data",next); + stream.removeListener("error",next); + }); + }; + + // make sure `reactor(..)` is called async + ASQ.__schedule(function $$schedule(){ + reactor.call(template,next,registerTeardown); + }); + + return template; +}; +// "react" helpers +(function IIFE(){ + + var Ar = ASQ.react; + + Ar.of = function $$react$of() { + function reactor(next) { + if (!started) { + started = true; + if (args.length > 0) { + args.shift().val(function val(){ + next.apply(ø,arguments); + if (args.length > 0) { + args.shift().val(val); + } + }); + } + } + } + + var started, args = ARRAY_SLICE.call(arguments) + .map(function wrapper(arg){ + if (!ASQ.isSequence(arg)) arg = ASQ(arg); + return arg; + }); + + return Ar(reactor); + }; + + Ar.all = Ar.zip = makeReactOperator(/*buffer=*/true); + Ar.allLatest = makeReactOperator(/*buffer=false*/); + Ar.latest = Ar.combineLatest = makeReactOperator(/*buffer=*/false,/*keep=*/true); + + Ar.any = Ar.merge = function $$react$any(){ + function reactor(next,registerTeardown){ + function processSequence(def){ + function trigger(){ + var args = ASQ.messages.apply(ø,arguments); + // still observing sequence-streams? + if (seqs && seqs.length > 0) { + // fire off reactive sequence instance + next.apply(ø,args); + } + // keep sequence going + return args; + } + + // sequence-stream event listener + def.seq.val(trigger); + } + + // observe all sequence-streams + seqs.forEach(processSequence); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + seqs = null; + }); + } + + // observe all sequence-streams + var seqs = tapSequences.apply(null,arguments); + + if (seqs.length == 0) return; + + return Ar(reactor); + }; + + Ar.distinct = function $$react$distinct(seq){ + return Ar.filter(seq,makeDistinctFilterer(/*keepAll=*/true)); + }; + + Ar.distinctConsecutive = Ar.distinctUntilChanged = function $$react$distinct$consecutive(seq) { + return Ar.filter(seq,makeDistinctFilterer(/*keepAll=*/false)); + }; + + Ar.filter = function $$react$filter(seq,filterer){ + function reactor(next,registerTeardown) { + function trigger(){ + var messages = ASQ.messages.apply(ø,arguments); + + if (filterer && filterer.apply(ø,messages)) { + // fire off reactive sequence instance + next.apply(ø,messages); + } + + // keep sequence going + return messages; + } + + // sequence-stream event listener + def.seq.val(trigger); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + def = filterer = null; + }); + } + + // observe sequence-stream + var def = tapSequences(seq)[0]; + + if (!def) return; + + return Ar(reactor); + }; + + Ar.fromObservable = function $$react$from$observable(obsv){ + function reactor(next,registerTeardown){ + // process buffer (if any) + buffer.forEach(next); + buffer.length = 0; + + // start non-buffered notifications? + if (!buffer.complete) { + notify = next; + } + + registerTeardown(function $$teardown(){ + obsv.dispose(); + }); + } + + function notify(v) { + buffer.push(v); + } + + var buffer = []; + + obsv.subscribe( + function $$on$next(v){ + notify(v); + }, + function $$on$error(){}, + function $$on$complete(){ + buffer.complete = true; + obsv.dispose(); + } + ); + + return Ar(reactor); + }; + + ASQ.extend("toObservable",function $$extend(api,internals){ + return function $$to$observable(){ + function init(observer) { + function define(pair){ + function listen(){ + var args = ASQ.messages.apply(ø,arguments); + observer[pair[1]].apply(observer, + args.length == 1 ? [args[0]] : args + ); + return args; + } + + api[pair[0]](listen); + } + + [["val","onNext"],["or","onError"]] + .forEach(define); + } + + return Rx.Observable.create(init); + }; + }); + + function tapSequences() { + function tapSequence(seq) { + // temporary `trigger` which, if called before being replaced + // below, creates replacement proxy sequence with the + // event message(s) re-fired + function trigger() { + var args = ARRAY_SLICE.call(arguments); + def.seq = Ar(function $$react(next){ + next.apply(ø,args); + }); + } + + if (ASQ.isSequence(seq)) { + var def = { seq: seq }; + + // listen for events from the sequence-stream + seq.val(function $$val(){ + trigger.apply(ø,arguments); + return ASQ.messages.apply(ø,arguments); + }); + + // make a reactive sequence to act as a proxy to the original + // sequence + def.seq = Ar(function $$react(next){ + // replace the temporary trigger (created above) + // with this proxy's trigger + trigger = next; + }); + + return def; + } + } + + return ARRAY_SLICE.call(arguments) + .map(tapSequence) + .filter(Boolean); + } + + function makeReactOperator(buffer,keep) { + return function $$react$operator(){ + function reactor(next,registerTeardown){ + function processSequence(def) { + // sequence-stream event listener + function trigger() { + var args = ASQ.messages.apply(ø,arguments); + // still observing sequence-streams? + if (seqs && seqs.length > 0) { + // store event message(s), if any + seq_events[seq_id] = + (buffer ? seq_events[seq_id] : []).concat( + args.length > 0 ? (args.length > 1 ? [args] : args[0]) : undefined + ); + + // collect event message(s) across the + // sequence-stream sources + var messages = seq_events.reduce(function reducer(msgs,eventList,idx){ + if (eventList.length > 0) msgs.push(eventList[0]); + return msgs; + },[]); + + // did all sequence-streams get an event? + if (messages.length == seq_events.length) { + if (messages.length == 1) messages = messages[0]; + + // fire off reactive sequence instance + next.apply(ø,messages); + + // discard stored event message(s)? + if (!keep) { + seq_events.forEach(function $$each(eventList){ + eventList.shift(); + }); + } + } + } + // keep sequence going + return args; + } + + var seq_id = seq_events.length; + seq_events.push([]); + def.seq.val(trigger); + } + + // process all sequence-streams + seqs.forEach(processSequence); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + seqs = seq_events = null; + }); + } + + var seq_events = [], + // observe all sequence-streams + seqs = tapSequences.apply(null,arguments) + ; + + if (seqs.length == 0) return; + + return Ar(reactor); + }; + } + + function makeDistinctFilterer(keepAll) { + function filterer() { + function isDuplicate(msgSet) { + return ( + msgSet.length == message_set.length && + msgSet.every(function $$every(val,idx){ + return val === message_set[idx]; + }) + ); + } + + var message_set = ASQ.messages.apply(ø,arguments); + + // any messages in message-set to check against? + if (message_set.length > 0) { + // duplicate message-set? + if (msg_sets.some(isDuplicate)) { + return false; + } + + // remember all message-sets for future distinct checking? + if (keepAll) { + msg_sets.push(message_set); + } + // only keep the last message-set for distinct-consecutive + // checking + else { + msg_sets[0] = message_set; + } + } + + // allow distinct non-duplicate value through + return true; + } + + var msg_sets = []; + + return filterer; + } + +})(); +// "runner" +ASQ.extend("runner",function $$extend(api,internals){ + + return function $$runner() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var args = ARRAY_SLICE.call(arguments); + + api + .then(function $$then(mainDone){ + + function wrap(v) { + // function? expected to produce an iterator + // (like a generator) or a promise + if (typeof v === "function") { + // call function passing in the control token + // note: neutralize `this` in call to prevent + // unexpected behavior + v = v.call(ø,token); + + // promise returned (ie, from async function)? + if (isPromise(v)) { + // wrap it in iterable sequence + v = ASQ.iterable(v); + } + } + // an iterable sequence? duplicate it (in case of multiple runs) + else if (ASQ.isSequence(v) && "next" in v) { + v = v.duplicate(); + } + // wrap anything else in iterable sequence + else { + v = ASQ.iterable(v); + } + + // a sequence to tap for errors? + if (ASQ.isSequence(v)) { + // listen for any sequence failures + v.or(function $$or(){ + // signal iteration-error + mainDone.fail.apply(ø,arguments); + }); + } + + return v; + } + + function addWrapped() { + iterators.push.apply( + iterators, + ARRAY_SLICE.call(arguments).map(wrap) + ); + } + + function iterateOrQuit(iterFn,now) { + // still have some co-routine runs to process? + if (iterators.length > 0) { + if (now) iterFn(); + else schedule(iterFn); + } + // all done! + else { + // previous value message? + if (typeof next_val !== "undefined") { + // not a message wrapper array? + if (!ASQ.isMessageWrapper(next_val)) { + // wrap value for the subsequent `apply(..)` + next_val = [next_val]; + } + } + else { + // nothing to affirmatively pass along + next_val = []; + } + + // signal done with all co-routine runs + mainDone.apply(ø,next_val); + } + } + + var iterators = args, + token = { + messages: ARRAY_SLICE.call(arguments,1), + add: addWrapped + }, + iter, ret, next_val = token + ; + + // map co-routines to round-robin list of iterators + iterators = iterators.map(wrap); + + // async iteration of round-robin list + (function iterate(){ + // get next co-routine in list + iter = iterators.shift(); + + // process the iteration + try { + // multiple messages to send to an iterable + // sequence? + if (ASQ.isMessageWrapper(next_val) && + ASQ.isSequence(iter) + ) { + ret = iter.next.apply(iter,next_val); + } + else { + ret = iter.next(next_val); + } + } + catch (err) { + return mainDone.fail(err); + } + + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + // was the control token yielded? + if (ret.value === token) { + // round-robin: put co-routine back into the list + // at the end where it was so it can be processed + // again on next loop-iteration + if (!ret.done) { + iterators.push(iter); + } + next_val = token; + iterateOrQuit(iterate,/*now=*/false); + } + else { + // not a recognized ASQ instance returned? + if (!ASQ.isSequence(ret.value)) { + // received a thenable/promise back? + if (isPromise(ret.value)) { + // wrap in a sequence + ret.value = ASQ().promise(ret.value); + } + // thunk yielded? + else if (typeof ret.value === "function") { + // wrap thunk call in a sequence + var fn = ret.value; + ret.value = ASQ(function $$ASQ(done){ + fn(done.errfcb); + }); + } + // message wrapper returned? + else if (ASQ.isMessageWrapper(ret.value)) { + // wrap message(s) in a sequence + ret.value = ASQ.apply(ø, + // don't let `apply(..)` discard an empty message + // wrapper! instead, pass it along as its own value + // itself. + ret.value.length > 0 ? ret.value : ASQ.messages(undefined) + ); + } + // non-undefined value returned? + else if (typeof ret.value !== "undefined") { + // wrap the value in a sequence + ret.value = ASQ(ret.value); + } + else { + // make an empty sequence + ret.value = ASQ(); + } + } + + ret.value + .val(function $$val(){ + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + if (arguments.length > 0) { + // save any return messages for input + // to next iteration + next_val = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + } + + // still more to iterate? + if (!ret.done) { + // was the control token passed along? + if (next_val === token) { + // round-robin: put co-routine back into the list + // at the end, so that the the next iterator can be + // processed on next loop-iteration + iterators.push(iter); + } + else { + // put co-routine back in where it just + // was so it can be processed again on + // next loop-iteration + iterators.unshift(iter); + } + } + + iterateOrQuit(iterate,/*now=*/true); + }) + .or(function $$or(){ + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + try { + // if an error occurs in the step-continuation + // promise or sequence, throw it back into the + // generator or iterable-sequence + iter["throw"].apply(iter,arguments); + } + catch (err) { + // if an error comes back out of after the throw, + // pass it out to the main sequence, as iteration + // must now be complete + mainDone.fail(err); + } + }); + } + })(); + }); + + return api; + }; +}); +// "toPromise" +ASQ.extend("toPromise",function $$extend(api,internals){ + return function $$to$promise() { + return new Promise(function $$executor(resolve,reject){ + api + .val(function $$val(){ + var args = ARRAY_SLICE.call(arguments); + resolve.call(ø,args.length > 1 ? args : args[0]); + return ASQ.messages.apply(ø,args); + }) + .or(function $$or(){ + var args = ARRAY_SLICE.call(arguments); + reject.call(ø,args.length > 1 ? args : args[0]); + }); + }); + }; +}); +// "try" +ASQ.extend("try",function $$extend(api,internals){ + return function $$try() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(fn){ + return function $$then(mainDone) { + var main_args = ARRAY_SLICE.call(arguments), + sq = ASQ.apply(ø,main_args.slice(1)) + ; + + sq + .then(function $$inner$then(){ + fn.apply(ø,arguments); + }) + .val(function $$val(){ + mainDone.apply(ø,arguments); + }) + .or(function $$inner$or(){ + var msgs = ASQ.messages.apply(ø,arguments); + // failed, so map error(s) as `catch` + mainDone({ + "catch": msgs.length > 1 ? msgs : msgs[0] + }); + }); + }; + }); + + api.then.apply(ø,fns); + + return api; + }; +}); +// "until" +ASQ.extend("until",function $$extend(api,internals){ + return function $$until() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(fn){ + return function $$then(mainDone) { + var main_args = ARRAY_SLICE.call(arguments), + sq = ASQ.apply(ø,main_args.slice(1)) + ; + + sq + .then(function $$inner$then(){ + var args = ARRAY_SLICE.call(arguments); + args[0]["break"] = function $$break(){ + mainDone.fail.apply(ø,arguments); + sq.abort(); + }; + + fn.apply(ø,args); + }) + .val(function $$val(){ + mainDone.apply(ø,arguments); + }) + .or(function $$inner$or(){ + // failed, retry + $$then.apply(ø,main_args); + }); + }; + }); + + api.then.apply(ø,fns); + + return api; + }; +}); +// "waterfall" +ASQ.extend("waterfall",function $$extend(api,internals){ + return function $$waterfall() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + var msgs = ASQ.messages(), + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + fns.forEach(function $$each(fn){ + sq.then(fn) + .val(function $$val(){ + var args = ASQ.messages.apply(ø,arguments); + msgs.push(args.length > 1 ? args : args[0]); + return msgs; + }); + }); + + sq.pipe(done); + }); + + return api; + }; +}); +// "wrap" +ASQ.wrap = function $$wrap(fn,opts) { + function checkThis(t,o) { + return (!t || + (typeof window != "undefined" && t === window) || + (typeof global != "undefined" && t === global) + ) ? o : t; + } + + function paramSpread(gen) { + return function *paramSpread(token) { + yield *gen.apply(this,token.messages); + }; + } + + var errfcb, params_first, act, this_obj; + + opts = (opts && typeof opts == "object") ? opts : {}; + + if ( + (opts.errfcb && opts.splitcb) || + (opts.errfcb && opts.simplecb) || + (opts.splitcb && opts.simplecb) || + ("errfcb" in opts && !opts.errfcb && !opts.splitcb && !opts.simplecb) || + (opts.params_first && opts.params_last) || + (opts.spread && !opts.gen) + ) { + throw Error("Invalid options"); + } + + // initialize default flags + this_obj = (opts["this"] && typeof opts["this"] == "object") ? opts["this"] : ø; + errfcb = opts.errfcb || !(opts.splitcb || opts.simplecb); + params_first = !!opts.params_first || + (!opts.params_last && !("params_first" in opts || opts.params_first)) || + ("params_last" in opts && !opts.params_first && !opts.params_last) + ; + + if (params_first) { + act = "push"; + } + else { + act = "unshift"; + } + + if (opts.gen) { + if (opts.spread) { + fn = paramSpread(fn); + } + return function $$wrapped$gen() { + return ASQ.apply(ø,arguments).runner(fn); + }; + } + if (errfcb) { + return function $$wrapped$errfcb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done.errfcb); + fn.apply(_this,args); + }); + }; + } + if (opts.splitcb) { + return function $$wrapped$splitcb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done,done.fail); + fn.apply(_this,args); + }); + }; + } + if (opts.simplecb) { + return function $$wrapped$simplecb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done); + fn.apply(_this,args); + }); + }; + } +}; + + + // just return `ASQ` itself for convenience sake + return ASQ; +}); diff --git a/frontend-masters-exercises/exercises/ex6/ex6-fixed.html b/frontend-masters-exercises/exercises/ex6/ex6-fixed.html new file mode 100755 index 0000000..4c627e8 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex6/ex6-fixed.html @@ -0,0 +1,14 @@ + + + + +Exercise 6 - Fixed + + +

Exercise 6 - Fixed

+ + + + + + diff --git a/frontend-masters-exercises/exercises/ex6/ex6-fixed.js b/frontend-masters-exercises/exercises/ex6/ex6-fixed.js new file mode 100755 index 0000000..0d36482 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex6/ex6-fixed.js @@ -0,0 +1,49 @@ +function fakeAjax(url,cb) { + var fake_responses = { + "file1": "The first text", + "file2": "The middle text", + "file3": "The last text" + }; + var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000; + + console.log("Requesting: " + url); + + setTimeout(function(){ + cb(fake_responses[url]); + },randomDelay); +} + +function output(text) { + console.log(text); +} + +// ************************************** + +function getFile(file) { + return ASQ(function(done){ + fakeAjax(file,done); + }); +} + +// Request all files at once in +// "parallel" via `getFile(..)`. +// +// Render as each one finishes, +// but only once previous rendering +// is done. +ASQ() +.seq.apply(null, + ["file1","file2","file3"] + // Request all files at once in "parallel" + .map(getFile) + // Render output as each file finishes, but + // only once previous rendering is done + .map(function(sq){ + return function(){ + return sq.val(output); + }; + }) +) +.val(function(){ + output("Complete!"); +}); diff --git a/frontend-masters-exercises/exercises/ex6/ex6.html b/frontend-masters-exercises/exercises/ex6/ex6.html new file mode 100755 index 0000000..2b24736 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex6/ex6.html @@ -0,0 +1,14 @@ + + + + +Exercise 6 + + +

Exercise 6

+ + + + + + diff --git a/frontend-masters-exercises/exercises/ex6/ex6.js b/frontend-masters-exercises/exercises/ex6/ex6.js new file mode 100755 index 0000000..0d36482 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex6/ex6.js @@ -0,0 +1,49 @@ +function fakeAjax(url,cb) { + var fake_responses = { + "file1": "The first text", + "file2": "The middle text", + "file3": "The last text" + }; + var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000; + + console.log("Requesting: " + url); + + setTimeout(function(){ + cb(fake_responses[url]); + },randomDelay); +} + +function output(text) { + console.log(text); +} + +// ************************************** + +function getFile(file) { + return ASQ(function(done){ + fakeAjax(file,done); + }); +} + +// Request all files at once in +// "parallel" via `getFile(..)`. +// +// Render as each one finishes, +// but only once previous rendering +// is done. +ASQ() +.seq.apply(null, + ["file1","file2","file3"] + // Request all files at once in "parallel" + .map(getFile) + // Render output as each file finishes, but + // only once previous rendering is done + .map(function(sq){ + return function(){ + return sq.val(output); + }; + }) +) +.val(function(){ + output("Complete!"); +}); diff --git a/frontend-masters-exercises/exercises/ex7/README.md b/frontend-masters-exercises/exercises/ex7/README.md new file mode 100755 index 0000000..97ca804 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex7/README.md @@ -0,0 +1,9 @@ +# Instructions + +1. You'll do the same thing as the previous exercise(s), but now you should use asynquence and a generator. + +2. Expected behavior: + - Request all 3 files at the same time (in "parallel"). + - Render them ASAP (don't just blindly wait for all to finish loading) + - BUT, render them in proper (obvious) order: "file1", "file2", "file3". + - After all 3 are done, output "Complete!". diff --git a/frontend-masters-exercises/exercises/ex7/asq.bundle.js b/frontend-masters-exercises/exercises/ex7/asq.bundle.js new file mode 100755 index 0000000..93c9ada --- /dev/null +++ b/frontend-masters-exercises/exercises/ex7/asq.bundle.js @@ -0,0 +1,2333 @@ +/*! asynquence + v0.8.2 (c) Kyle Simpson + MIT License: http://getify.mit-license.org +*/ +!function UMD(e,n,t){"function"==typeof define&&define.amd?define(t):"undefined"!=typeof module&&module.exports?module.exports=t():n[e]=t(e,n)}("ASQ",this,function DEF(e,n){"use strict";function Queue(){function Item(e){this.fn=e,this.next=void 0}var e,n,r;return{add:function $$add(t){r=new Item(t),n?n.next=r:e=r,n=r,r=void 0},drain:function $$drain(){var r=e;for(e=n=t=null;r;)r.fn(),r=r.next}}}function schedule(e){r.add(e),t||(t=u(r.drain))}function tapSequence(e){function trigger(){e.seq=createSequence.apply(h,arguments).defer()}trigger.fail=function $$trigger$fail(){var n=f.call(arguments);e.seq=createSequence(function $$create$sequence(e){e.fail.apply(h,n)}).defer()},e.seq.val(function $$val(){return trigger.apply(h,arguments),c.apply(h,arguments)}).or(function $$or(){trigger.fail.apply(h,arguments)}),e.seq=createSequence(function $$create$sequence(e){trigger=e}).defer()}function createSequence(){function scheduleSequenceTick(){r?sequenceTick():e||(e=schedule(sequenceTick))}function throwSequenceErrors(){throw 1===$.length?$[0]:$}function sequenceTick(){var a,c;if(e=null,delete d.unpause,r)clearTimeout(e),e=null,s.length=p.length=g.length=$.length=0;else if(n)for(0!==p.length||t||(t=!0,throwSequenceErrors());p.length;){t=!0,a=p.shift();try{a.apply(h,$)}catch(i){l(i)?$=$.concat(i):($.push(i),i.stack&&$.push(i.stack)),0===p.length&&throwSequenceErrors()}}else if(u&&s.length>0){u=!1,a=s.shift(),c=g.slice(),g.length=0,c.unshift(createStepCompletion());try{a.apply(h,c)}catch(i){l(i)?$=$.concat(i):$.push(i),n=!0,scheduleSequenceTick()}}}function createStepCompletion(){function done(){n||r||u||(u=!0,g.push.apply(g,arguments),$.length=0,scheduleSequenceTick())}return done.fail=function $$step$fail(){n||r||u||(n=!0,g.length=0,$.push.apply($,arguments),scheduleSequenceTick())},done.abort=function $$step$abort(){n||r||(u=!1,r=!0,g.length=$.length=0,scheduleSequenceTick())},done.errfcb=function $$step$errfcb(e){e?done.fail(e):done.apply(h,f.call(arguments,1))},done}function createGate(e,t,u){function resetGate(){clearTimeout(s),s=d=m=o=null}function scheduleGateTick(){return g?gateTick():void(s||(s=schedule(gateTick)))}function gateTick(){if(!(n||r||$)){var t=[];s=null,p?(e.fail.apply(h,o),resetGate()):g?(e.abort(),resetGate()):checkGate()&&($=!0,d.forEach(function $$each(e,n){t.push(m["s"+n])}),e.apply(h,t),resetGate())}}function checkGate(){if(0!==d.length){var e=!0;return d.some(function $$some(n){return null===n?(e=!1,!0):void 0}),e}}function createSegmentCompletion(){function done(){if(!(n||r||p||g||$||d[e])){var t=c.apply(h,arguments);m["s"+e]=t.length>1?t:t[0],d[e]=!0,scheduleGateTick()}}var e=d.length;return done.fail=function $$segment$fail(){n||r||p||g||$||d[e]||(p=!0,o=f.call(arguments),scheduleGateTick())},done.abort=function $$segment$abort(){n||r||p||g||$||(g=!0,gateTick())},done.errfcb=function $$segment$errfcb(e){e?done.fail(e):done.apply(h,f.call(arguments,1))},d[e]=null,done}var a,i,o,s,p=!1,g=!1,$=!1,d=[],m={};t.some(function $$some(e){if(p||g)return!0;a=u.slice(),a.unshift(createSegmentCompletion());try{e.apply(h,a)}catch(n){return i=n,p=!0,!0}}),i&&(l(i)?e.fail.apply(h,i):e.fail(i))}function then(){return n||r||0===arguments.length?d:(wrapArgs(arguments,thenWrapper).forEach(function $$each(e){i(e)?seq(e):s.push(e)}),scheduleSequenceTick(),d)}function or(){return r||0===arguments.length?d:(p.push.apply(p,arguments),scheduleSequenceTick(),d)}function gate(){if(n||r||0===arguments.length)return d;var e=f.call(arguments).map(function $$map(e){var n;return i(e)?(n={seq:e},tapSequence(n),function $$segment(e){n.seq.pipe(e)}):e});return then(function $$then(n){var t=f.call(arguments,1);createGate(n,e,t)}),d}function pipe(){return r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){then(function $$then(n){e.apply(h,f.call(arguments,1)),n()}).or(e.fail)}),d)}function seq(){return n||r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){var n={seq:e};i(e)&&tapSequence(n),then(function $$then(e){var t=n.seq;i(t)||(t=n.seq.apply(h,f.call(arguments,1))),t.pipe(e)})}),d)}function val(){return n||r||0===arguments.length?d:(f.call(wrapArgs(arguments,valWrapper)).forEach(function $$each(e){then(function $$then(n){var t=e.apply(h,f.call(arguments,1));l(t)||(t=c(t)),n.apply(h,t)})}),d)}function promise(){function wrap(e){return function $$fn(){e.apply(h,l(arguments[0])?arguments[0]:arguments)}}return n||r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){then(function $$then(n){var t=e;"function"==typeof e&&"function"!=typeof e.then&&(t=e.apply(h,f.call(arguments,1))),t.then(wrap(n),wrap(n.fail))})}),d)}function fork(){var e;return val(function $$val(){return e?e.apply(h,arguments):e=createSequence.apply(h,arguments).defer(),c.apply(h,arguments)}),or(function $$or(){if(e)e.fail.apply(h,arguments);else{var n=f.call(arguments);e=createSequence().then(function $$then(e){e.fail.apply(h,n)}).defer()}}),createSequence().then(function $$then(n){e?e.pipe(n):e=n}).defer()}function abort(){return n?d:(r=!0,sequenceTick(),d)}function duplicate(){var e;return a={then_queue:s.slice(),or_queue:p.slice()},e=createSequence(),a=null,e}function unpause(){g.push.apply(g,arguments),e===!0&&(e=null),scheduleSequenceTick()}function defer(){return p.push(function ignored(){}),d}function internals(e,t){var a=arguments.length>1;switch(e){case"seq_error":if(!a)return n;n=t;break;case"seq_aborted":if(!a)return r;r=t;break;case"then_ready":if(!a)return u;u=t;break;case"then_queue":return s;case"or_queue":return p;case"sequence_messages":return g;case"sequence_errors":return $}}function includeExtensions(){Object.keys(o).forEach(function $$each(e){d[e]=o[e](d,internals)})}var e,n=!1,t=!1,r=!1,u=!0,s=[],p=[],g=[],$=[],d=brandIt({then:then,or:or,onerror:or,gate:gate,all:gate,pipe:pipe,seq:seq,val:val,promise:promise,fork:fork,abort:abort,duplicate:duplicate,defer:defer});return includeExtensions(),a&&(s=a.then_queue.slice(),p=a.or_queue.slice(),d.unpause=unpause,e=!0),d.then.apply(h,arguments),d}function brandIt(e){return Object.defineProperty(e,p,{enumerable:!1,value:!0})}function checkBranding(e){return!(null==e||"object"!=typeof e||!e[p])}function valWrapper(e){return c.apply(h,f.call(arguments).slice(1,e+1))}function thenWrapper(e){arguments[e+1].apply(h,f.call(arguments).slice(1,e+1))}function wrapArgs(e,n){var t,r;for(e=f.call(e),t=0;t 1 ? + ARRAY_SLICE.call(arguments,1) : + void 0 + ; + num = +num || 0; + + api.then(function $$then(done){ + var args = orig_args || ARRAY_SLICE.call(arguments,1); + + setTimeout(function $$set$timeout(){ + done.apply(ø,args); + },num); + }); + + return api; + }; +}); + +ASQ.after = function $$after() { + return ASQ().after.apply(ø,arguments); +}; +// "any" +ASQ.extend("any",function $$extend(api,internals){ + return function $$any() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages.length = 0; + } + + function complete(trigger) { + if (success_messages.length > 0) { + // any successful segment's message(s) sent + // to main sequence to proceed as success + success_messages.length = fns.length; + trigger.apply(ø,success_messages); + } + else { + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + success_messages = [], + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "errfcb" +ASQ.extend("errfcb",function $$extend(api,internals){ + return function $$errfcb() { + // create a fake sequence to extract the callbacks + var sq = { + val: function $$then(cb){ sq.val_cb = cb; return sq; }, + or: function $$or(cb){ sq.or_cb = cb; return sq; } + }; + + // trick `seq(..)`s checks for a sequence + sq[brand] = true; + + // immediately register our fake sequence on the + // main sequence + api.seq(sq); + + // provide the "error-first" callback + return function $$errorfirst$callback(err) { + if (err) { + sq.or_cb(err); + } + else { + sq.val_cb.apply(ø,ARRAY_SLICE.call(arguments,1)); + } + }; + }; +}); +// "failAfter" +ASQ.extend("failAfter",function $$extend(api,internals){ + return function $$failAfter(num) { + var args = arguments.length > 1 ? + ARRAY_SLICE.call(arguments,1) : + void 0 + ; + num = +num || 0; + + api.then(function $$then(done){ + setTimeout(function $$set$timeout(){ + done.fail.apply(ø,args); + },num); + }); + + return api; + }; +}); + +ASQ.failAfter = function $$fail$after() { + return ASQ().failAfter.apply(ø,arguments); +}; +// "first" +ASQ.extend("first",function $$extend(api,internals){ + return function $$first() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + error_messages.length = 0; + } + + function success(trigger,idx,args) { + if (!finished) { + finished = true; + + // first successful segment triggers + // main sequence to proceed as success + trigger( + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ); + + reset(); + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete without success? + if (completed === fns.length) { + finished = true; + + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + + reset(); + } + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "go-style CSP" +(function IIFE(){ + + // filter out already-resolved queue entries + function filterResolved(queue) { + return queue.filter(function $$filter(entry){ + return !entry.resolved; + }); + } + + function closeQueue(queue,finalValue) { + queue.forEach(function $$each(iter){ + if (!iter.resolved) { + iter.next(); + iter.next(finalValue); + } + }); + queue.length = 0; + } + + function channel(bufSize) { + var ch = { + close: function $$close(){ + ch.closed = true; + closeQueue(ch.put_queue,false); + closeQueue(ch.take_queue,ASQ.csp.CLOSED); + }, + closed: false, + messages: [], + put_queue: [], + take_queue: [], + buffer_size: +bufSize || 0 + }; + return ch; + } + + function unblock(iter) { + if (iter && !iter.resolved) { + iter.next(iter.next().value); + } + } + + function put(channel,value) { + var ret; + + if (channel.closed) { + return false; + } + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + // immediate put? + if (channel.messages.length < channel.buffer_size) { + channel.messages.push(value); + unblock(channel.take_queue.shift()); + return true; + } + // queued put + else { + channel.put_queue.push( + // make a notifiable iterable for 'put' blocking + ASQ.iterable() + .then(function $$then(){ + if (!channel.closed) { + channel.messages.push(value); + return true; + } + else { + return false; + } + }) + ); + + // wrap a sequence/promise around the iterable + ret = ASQ( + channel.put_queue[channel.put_queue.length - 1] + ); + + // take waiting on this queued put? + if (channel.take_queue.length > 0) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + + return ret; + } + } + + function putAsync(channel,value,cb) { + var ret = ASQ(put(channel,value)); + + if (cb && typeof cb == "function") { + ret.val(cb); + } + else { + return ret; + } + } + + function take(channel) { + var ret; + + try { + ret = takem(channel); + } + catch (err) { + ret = err; + } + + if (ASQ.isSequence(ret)) { + ret.pCatch(function $$pcatch(err){ + return err; + }); + } + + return ret; + } + + function takeAsync(channel,cb) { + var ret = ASQ(take(channel)); + + if (cb && typeof cb == "function") { + ret.val(cb); + } + else { + return ret; + } + } + + function takem(channel) { + var msg; + + if (channel.closed) { + return ASQ.csp.CLOSED; + } + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + // immediate take? + if (channel.messages.length > 0) { + msg = channel.messages.shift(); + unblock(channel.put_queue.shift()); + if (msg instanceof Error) { + throw msg; + } + return msg; + } + // queued take + else { + channel.take_queue.push( + // make a notifiable iterable for 'take' blocking + ASQ.iterable() + .then(function $$then(){ + if (!channel.closed) { + var v = channel.messages.shift(); + if (v instanceof Error) { + throw v; + } + return v; + } + else { + return ASQ.csp.CLOSED; + } + }) + ); + + // wrap a sequence/promise around the iterable + msg = ASQ( + channel.take_queue[channel.take_queue.length - 1] + ); + + // put waiting on this take? + if (channel.put_queue.length > 0) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + + return msg; + } + } + + function takemAsync(channel,cb) { + var ret = ASQ(takem(channel)); + + if (cb && typeof cb == "function") { + ret.pThen(cb,cb); + } + else { + return ret.val(function $$val(v){ + if (v instanceof Error) { + throw v; + } + return v; + }); + } + } + + function alts(actions) { + var closed, open, handlers, i, isq, ret, resolved = false; + + // used `alts(..)` incorrectly? + if (!Array.isArray(actions) || actions.length == 0) { + throw Error("Invalid usage"); + } + + closed = []; + open = []; + handlers = []; + + // separate actions by open/closed channel status + actions.forEach(function $$each(action){ + var channel = Array.isArray(action) ? action[0] : action; + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + if (channel.closed) { + closed.push(channel); + } + else { + open.push(action); + } + }); + + // if no channels are still open, we're done + if (open.length == 0) { + return { value: ASQ.csp.CLOSED, channel: closed }; + } + + // can any channel action be executed immediately? + for (i=0; i 0) { + return { value: take(open[i]), channel: open[i] }; + } + } + + isq = ASQ.iterable(); + var ret = ASQ(isq); + + // setup channel action handlers + for (i=0; i 0) { + schedule(function handleUnblocking(){ + if (!resolved) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + },0); + } + } + // take action? + else { + channel = action; + + // define take handler + handlers.push( + ASQ.iterable() + .then(function $$then(){ + resolved = true; + + // mark all handlers across this `alts(..)` as resolved now + handlers = handlers.filter(function $$filter(handler){ + return !(handler.resolved = true); + }); + + // channel still open? + if (!channel.closed) { + isq.next({ value: channel.messages.shift(), channel: channel }); + } + // channel already closed? + else { + isq.next({ value: ASQ.csp.CLOSED, channel: channel }); + } + }) + ); + + // queue up take handler + channel.take_queue.push(handlers[handlers.length-1]); + + // put waiting on this queued take? + if (channel.put_queue.length > 0) { + schedule(function handleUnblocking(){ + if (!resolved) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + }); + } + } + })(open[i]); + } + + return ret; + } + + function altsAsync(chans,cb) { + var ret = ASQ(alts(chans)); + + if (cb && typeof cb == "function") { + ret.pThen(cb,cb); + } + else { + return ret; + } + } + + function timeout(delay) { + var ch = channel(); + setTimeout(ch.close,delay); + return ch; + } + + function go(gen,args) { + // goroutine arguments passed? + if (arguments.length > 1) { + if (!args || !Array.isArray(args)) { + args = [args]; + } + } + else { + args = []; + } + + return function *$$go(token) { + + // unblock the overall goroutine handling + function unblock() { + token.unblock_count++; + + if (token.block && !token.block.marked) { + token.block.marked = true; + token.block.next(); + } + } + + var ret, msg, err, type, done = false, it; + + // keep track of how many requests for unblocking + // have occurred + token.unblock_count = (token.unblock_count || 0); + + // keep track of how many goroutines are running + // so we can infer when we're done go'ing + token.go_count = (token.go_count || 0) + 1; + + // need to initialize a set of goroutines? + if (token.go_count === 1) { + // create a default channel for these goroutines + token.channel = channel(); + token.channel.messages = token.messages; + token.channel.go = function $$go(){ + // unblock the goroutine handling for this + // new goroutine + unblock(); + // add the goroutine (called with any args) to + // the handling queue + token.add( go.apply(ø,arguments) ); + }; + // starting out with initial channel messages? + if (token.channel.messages.length > 0) { + // fake back-pressure blocking for each + token.channel.put_queue = token.channel.messages.map(function $$map(){ + // make a notifiable iterable for 'put' blocking + return ASQ.iterable() + .then(function $$then(){ + unblock(token.channel.take_queue.shift()); + return !token.channel.closed; + }); + }); + } + } + + // initialize the generator + it = gen.apply(ø,[token.channel].concat(args)); + + (function iterate(){ + + function next() { + // keep going with next step in goroutine? + if (!done) { + iterate(); + } + // unblock overall goroutine handling to + // continue with other goroutines + else { + unblock(); + } + } + + // has a resumption value been achieved yet? + if (!ret) { + // try to resume the goroutine + try { + // resume with injected exception? + if (err) { + ret = it.throw(err); + err = null; + } + // resume normally + else { + ret = it.next(msg); + } + } + // resumption failed, so bail + catch (e) { + done = true; + err = e; + msg = null; + unblock(); + return; + } + + // keep track of the result of the resumption + done = ret.done; + ret = ret.value; + type = typeof ret; + + // if this goroutine is complete, unblock the + // overall goroutine handling + if (done) { + unblock(); + } + + // received a thenable/promise back? + if (isPromise(ret)) { + ret = ASQ().promise(ret); + } + + // wait for the value? + if (ASQ.isSequence(ret)) { + ret.val(function $$val(){ + ret = null; + msg = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + next(); + }) + .or(function $$or(){ + ret = null; + msg = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + if (msg instanceof Error) { + err = msg; + msg = null; + } + next(); + }); + } + // immediate value, prepare it to go right back in + else { + msg = ret; + ret = null; + next(); + } + } + })(); + + // keep this goroutine alive until completion + while (!done) { + // transfer control to another goroutine + yield token; + + // need to block overall goroutine handling + // while idle? + if (!done && !token.block && token.unblock_count === 0) { + // wait here while idle + yield (token.block = ASQ.iterable()); + + token.block = false; + } + + if (token.unblock_count > 0) token.unblock_count--; + } + + // this goroutine is done now + token.go_count--; + + // all goroutines done? + if (token.go_count === 0) { + // any lingering blocking need to be cleaned up? + unblock(); + + // capture any untaken messages + msg = ASQ.messages.apply(ø,token.messages); + + // need to implicitly force-close channel? + if (token.channel && !token.channel.closed) { + token.channel.closed = true; + token.channel.put_queue.length = token.channel.take_queue.length = 0; + token.channel.close = token.channel.go = token.channel.messages = null; + } + token.channel = null; + } + + // make sure leftover error or message are + // passed along + if (err) { + throw err; + } + else if (token.go_count === 0) { + return msg; + } + else { + return token; + } + }; + } + + ASQ.csp = { + chan: channel, + put: put, + putAsync: putAsync, + take: take, + takeAsync: takeAsync, + takem: takem, + takemAsync: takemAsync, + alts: alts, + altsAsync: altsAsync, + timeout: timeout, + go: go, + CLOSED: {} + }; + +})(); +// "ASQ.iterable()" +(function IIFE(){ + var template; + + ASQ.iterable = function $$iterable() { + function throwSequenceErrors() { + throw (sequence_errors.length === 1 ? sequence_errors[0] : sequence_errors); + } + + function notifyErrors() { + var fn; + + seq_tick = null; + + if (seq_error) { + if (or_queue.length === 0 && !error_reported) { + error_reported = true; + throwSequenceErrors(); + } + + while (or_queue.length > 0) { + error_reported = true; + fn = or_queue.shift(); + try { + fn.apply(ø,sequence_errors); + } + catch (err) { + if (checkBranding(err)) { + sequence_errors = sequence_errors.concat(err); + } + else { + sequence_errors.push(err); + } + if (or_queue.length === 0) { + throwSequenceErrors(); + } + } + } + } + } + + function val() { + if (seq_error || seq_aborted || arguments.length === 0) { + return sequence_api; + } + + var args = ARRAY_SLICE.call(arguments).map(function mapper(arg){ + if (typeof arg != "function") return function $$val() { return arg; }; + else return arg; + }); + + val_queue.push.apply(val_queue,args); + + return sequence_api; + } + + function or() { + if (seq_aborted || arguments.length === 0) { + return sequence_api; + } + + or_queue.push.apply(or_queue,arguments); + + if (!seq_tick) { + seq_tick = schedule(notifyErrors); + } + + return sequence_api; + } + + function pipe() { + if (seq_aborted || arguments.length === 0) { + return sequence_api; + } + + ARRAY_SLICE.call(arguments) + .forEach(function $$each(fn){ + val(fn).or(fn.fail); + }); + + return sequence_api; + } + + function next() { + if (seq_error || seq_aborted || val_queue.length === 0) { + if (val_queue.length > 0) { + $throw$("Sequence cannot be iterated"); + } + return { done: true }; + } + + try { + return { value: val_queue.shift().apply(ø,arguments) }; + } + catch (err) { + if (ASQ.isMessageWrapper(err)) { + $throw$.apply(ø,err); + } + else { + $throw$(err); + } + + return {}; + } + } + + function $throw$() { + if (seq_error || seq_aborted) { + return sequence_api; + } + + sequence_errors.push.apply(sequence_errors,arguments); + seq_error = true; + if (!seq_tick) { + seq_tick = schedule(notifyErrors); + } + + return sequence_api; + } + + function $return$(val) { + if (seq_error || seq_aborted) { + val = void 0; + } + + abort(); + + return { done: true, value: val }; + } + + function abort() { + if (seq_error || seq_aborted) { + return; + } + + seq_aborted = true; + + clearTimeout(seq_tick); + seq_tick = null; + val_queue.length = or_queue.length = sequence_errors.length = 0; + } + + function duplicate() { + var isq; + + template = { + val_queue: val_queue.slice(), + or_queue: or_queue.slice() + }; + isq = ASQ.iterable(); + template = null; + + return isq; + } + + // opt-out of global error reporting for this sequence + function defer() { + or_queue.push(function $$ignored(){}); + return sequence_api; + } + + // *********************************************** + // Object branding utilities + // *********************************************** + function brandIt(obj) { + Object.defineProperty(obj,brand,{ + enumerable: false, + value: true + }); + + return obj; + } + + var sequence_api, + + seq_error = false, + error_reported = false, + seq_aborted = false, + + seq_tick, + + val_queue = [], + or_queue = [], + + sequence_errors = [] + ; + + // *********************************************** + // Setup the ASQ.iterable() public API + // *********************************************** + sequence_api = brandIt({ + val: val, + then: val, + or: or, + pipe: pipe, + next: next, + "throw": $throw$, + "return": $return$, + abort: abort, + duplicate: duplicate, + defer: defer + }); + + // useful for ES6 `for..of` loops, + // add `@@iterator` to simply hand back + // our iterable sequence itself! + sequence_api[(typeof Symbol == "function" && Symbol.iterator) || "@@iterator"] = function $$iter() { + return sequence_api; + }; + + // templating the iterable-sequence setup? + if (template) { + val_queue = template.val_queue.slice(0); + or_queue = template.or_queue.slice(0); + } + + // treat ASQ.iterable() constructor parameters as having been + // passed to `val()` + sequence_api.val.apply(ø,arguments); + + return sequence_api; + }; + +})(); +// "last" +ASQ.extend("last",function $$extend(api,internals){ + return function $$last() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages = null; + } + + function complete(trigger) { + if (success_messages != null) { + // last successful segment's message(s) sent + // to main sequence to proceed as success + trigger( + success_messages.length > 1 ? + ASQ.messages.apply(ø,success_messages) : + success_messages[0] + ); + } + else { + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages = args; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)), + success_messages + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "map" +ASQ.extend("map",function $$extend(api,internals){ + return function $$map(pArr,pEach) { + if (internals("seq_error") || internals("seq_aborted")) { + return api; + } + + api.seq(function $$seq(){ + var tmp, args = ARRAY_SLICE.call(arguments), + arr = pArr, each = pEach; + + // if missing `map(..)` args, use value-messages (if any) + if (!each) each = args.shift(); + if (!arr) arr = args.shift(); + + // if arg types in reverse order (each,arr), swap + if (typeof arr === "function" && Array.isArray(each)) { + tmp = arr; + arr = each; + each = tmp; + } + + return ASQ.apply(ø,args) + .gate.apply(ø,arr.map(function $$map(item){ + return function $$segment(){ + each.apply(ø,[item].concat(ARRAY_SLICE.call(arguments))); + }; + })); + }) + .val(function $$val(){ + // collect all gate segment output into one value-message + // Note: return a normal array here, not a message wrapper! + return ARRAY_SLICE.call(arguments); + }); + + return api; + }; +}); +// "none" +ASQ.extend("none",function $$extend(api,internals){ + return function $$none() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages.length = 0; + } + + function complete(trigger) { + if (success_messages.length > 0) { + // any successful segment's message(s) sent + // to main sequence to proceed as **error** + success_messages.length = fns.length; + trigger.fail.apply(ø,success_messages); + } + else { + // send errors as **success** to main sequence + error_messages.length = fns.length; + trigger.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)), + success_messages = [] + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "pThen" +ASQ.extend("pThen",function $$extend(api,internals){ + return function $$pthen(success,failure) { + if (internals("seq_aborted")) { + return api; + } + + var ignore_success_handler = false, ignore_failure_handler = false; + + if (typeof success === "function") { + api.then(function $$then(done){ + if (!ignore_success_handler) { + var ret, msgs = ASQ.messages.apply(ø,arguments); + msgs.shift(); + + if (msgs.length === 1) { + msgs = msgs[0]; + } + + ignore_failure_handler = true; + + try { + ret = success(msgs); + } + catch (err) { + if (!ASQ.isMessageWrapper(err)) { + err = [err]; + } + done.fail.apply(ø,err); + return; + } + + // returned a sequence? + if (ASQ.isSequence(ret)) { + ret.pipe(done); + } + // returned a message wrapper? + else if (ASQ.isMessageWrapper(ret)) { + done.apply(ø,ret); + } + // returned a promise/thenable? + else if (isPromise(ret)) { + ret.then(done,done.fail); + } + // just a normal value to pass along + else { + done(ret); + } + } + else { + done.apply(ø,ARRAY_SLICE.call(arguments,1)); + } + }); + } + if (typeof failure === "function") { + api.or(function $$or(){ + if (!ignore_failure_handler) { + var ret, msgs = ASQ.messages.apply(ø,arguments), smgs, + or_queue = ARRAY_SLICE.call(internals("or_queue")) + ; + + if (msgs.length === 1) { + msgs = msgs[0]; + } + + ignore_success_handler = true; + + // NOTE: if this call throws, that'll automatically + // be handled by core as we'd want it to be + ret = failure(msgs); + + // if we get this far: + // first, inject return value (if any) as + // next step's sequence messages + smgs = internals("sequence_messages"); + smgs.length = 0; + if (typeof ret !== "undefined") { + if (!ASQ.isMessageWrapper(ret)) { + ret = [ret]; + } + smgs.push.apply(smgs,ret); + } + + // reset internal error state, because we've exclusively + // handled any errors up to this point of the sequence + internals("sequence_errors").length = 0; + internals("seq_error",false); + internals("then_ready",true); + + // temporarily empty the or-queue + internals("or_queue").length = 0; + + // make sure to schedule success-procession on the chain + api.val(function $$val(){ + // pass thru messages + return ASQ.messages.apply(ø,arguments); + }); + + // at next cycle, reinstate the or-queue (if any) + if (or_queue.length > 0) { + schedule(function $$schedule(){ + api.or.apply(ø,or_queue); + }); + } + } + }); + } + return api; + }; +}); + +// "pCatch" +ASQ.extend("pCatch",function $$extend(api,internals){ + return function $$pcatch(failure) { + if (internals("seq_aborted")) { + return api; + } + + api.pThen(void 0,failure); + + return api; + }; +}); +// "race" +ASQ.extend("race",function $$extend(api,internals){ + return function $$race() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(v){ + var def; + // tap any directly-provided sequences immediately + if (ASQ.isSequence(v)) { + def = { seq: v }; + tapSequence(def); + return function $$fn(done) { + def.seq.pipe(done); + }; + } + else return v; + }); + + api.then(function $$then(done){ + var args = ARRAY_SLICE.call(arguments); + + fns.forEach(function $$each(fn){ + fn.apply(ø,args); + }); + }); + + return api; + }; +}); +// "react" (reactive sequences) +ASQ.react = function $$react(reactor) { + function next() { + if (!paused) { + if (template) { + var sq = template.duplicate(); + sq.unpause.apply(ø,arguments); + return sq; + } + return ASQ(function $$asq(){ throw "Disabled Sequence"; }); + } + } + + function registerTeardown(fn) { + if (template && typeof fn === "function") { + teardowns.push(fn); + } + } + + var template = ASQ().duplicate(), + teardowns = [], paused = false + ; + + // add reactive sequence kill switch + template.stop = function $$stop() { + if (template) { + template = null; + teardowns.forEach(Function.call,Function.call); + teardowns.length = 0; + } + }; + + template.pause = function $$pause() { + if (!paused && template) { + paused = true; + teardowns.forEach(Function.call,Function.call); + teardowns.length = 0; + } + }; + + template.resume = function $$resume() { + if (paused && template) { + paused = false; + reactor.call(template,next,registerTeardown); + } + }; + + template.push = next; + + next.onStream = function $$onStream() { + ARRAY_SLICE.call(arguments) + .forEach(function $$each(stream){ + stream.on("data",next); + stream.on("error",next); + }); + }; + + next.unStream = function $$unStream() { + ARRAY_SLICE.call(arguments) + .forEach(function $$each(stream){ + stream.removeListener("data",next); + stream.removeListener("error",next); + }); + }; + + // make sure `reactor(..)` is called async + ASQ.__schedule(function $$schedule(){ + reactor.call(template,next,registerTeardown); + }); + + return template; +}; +// "react" helpers +(function IIFE(){ + + var Ar = ASQ.react; + + Ar.of = function $$react$of() { + function reactor(next) { + if (!started) { + started = true; + if (args.length > 0) { + args.shift().val(function val(){ + next.apply(ø,arguments); + if (args.length > 0) { + args.shift().val(val); + } + }); + } + } + } + + var started, args = ARRAY_SLICE.call(arguments) + .map(function wrapper(arg){ + if (!ASQ.isSequence(arg)) arg = ASQ(arg); + return arg; + }); + + return Ar(reactor); + }; + + Ar.all = Ar.zip = makeReactOperator(/*buffer=*/true); + Ar.allLatest = makeReactOperator(/*buffer=false*/); + Ar.latest = Ar.combineLatest = makeReactOperator(/*buffer=*/false,/*keep=*/true); + + Ar.any = Ar.merge = function $$react$any(){ + function reactor(next,registerTeardown){ + function processSequence(def){ + function trigger(){ + var args = ASQ.messages.apply(ø,arguments); + // still observing sequence-streams? + if (seqs && seqs.length > 0) { + // fire off reactive sequence instance + next.apply(ø,args); + } + // keep sequence going + return args; + } + + // sequence-stream event listener + def.seq.val(trigger); + } + + // observe all sequence-streams + seqs.forEach(processSequence); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + seqs = null; + }); + } + + // observe all sequence-streams + var seqs = tapSequences.apply(null,arguments); + + if (seqs.length == 0) return; + + return Ar(reactor); + }; + + Ar.distinct = function $$react$distinct(seq){ + return Ar.filter(seq,makeDistinctFilterer(/*keepAll=*/true)); + }; + + Ar.distinctConsecutive = Ar.distinctUntilChanged = function $$react$distinct$consecutive(seq) { + return Ar.filter(seq,makeDistinctFilterer(/*keepAll=*/false)); + }; + + Ar.filter = function $$react$filter(seq,filterer){ + function reactor(next,registerTeardown) { + function trigger(){ + var messages = ASQ.messages.apply(ø,arguments); + + if (filterer && filterer.apply(ø,messages)) { + // fire off reactive sequence instance + next.apply(ø,messages); + } + + // keep sequence going + return messages; + } + + // sequence-stream event listener + def.seq.val(trigger); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + def = filterer = null; + }); + } + + // observe sequence-stream + var def = tapSequences(seq)[0]; + + if (!def) return; + + return Ar(reactor); + }; + + Ar.fromObservable = function $$react$from$observable(obsv){ + function reactor(next,registerTeardown){ + // process buffer (if any) + buffer.forEach(next); + buffer.length = 0; + + // start non-buffered notifications? + if (!buffer.complete) { + notify = next; + } + + registerTeardown(function $$teardown(){ + obsv.dispose(); + }); + } + + function notify(v) { + buffer.push(v); + } + + var buffer = []; + + obsv.subscribe( + function $$on$next(v){ + notify(v); + }, + function $$on$error(){}, + function $$on$complete(){ + buffer.complete = true; + obsv.dispose(); + } + ); + + return Ar(reactor); + }; + + ASQ.extend("toObservable",function $$extend(api,internals){ + return function $$to$observable(){ + function init(observer) { + function define(pair){ + function listen(){ + var args = ASQ.messages.apply(ø,arguments); + observer[pair[1]].apply(observer, + args.length == 1 ? [args[0]] : args + ); + return args; + } + + api[pair[0]](listen); + } + + [["val","onNext"],["or","onError"]] + .forEach(define); + } + + return Rx.Observable.create(init); + }; + }); + + function tapSequences() { + function tapSequence(seq) { + // temporary `trigger` which, if called before being replaced + // below, creates replacement proxy sequence with the + // event message(s) re-fired + function trigger() { + var args = ARRAY_SLICE.call(arguments); + def.seq = Ar(function $$react(next){ + next.apply(ø,args); + }); + } + + if (ASQ.isSequence(seq)) { + var def = { seq: seq }; + + // listen for events from the sequence-stream + seq.val(function $$val(){ + trigger.apply(ø,arguments); + return ASQ.messages.apply(ø,arguments); + }); + + // make a reactive sequence to act as a proxy to the original + // sequence + def.seq = Ar(function $$react(next){ + // replace the temporary trigger (created above) + // with this proxy's trigger + trigger = next; + }); + + return def; + } + } + + return ARRAY_SLICE.call(arguments) + .map(tapSequence) + .filter(Boolean); + } + + function makeReactOperator(buffer,keep) { + return function $$react$operator(){ + function reactor(next,registerTeardown){ + function processSequence(def) { + // sequence-stream event listener + function trigger() { + var args = ASQ.messages.apply(ø,arguments); + // still observing sequence-streams? + if (seqs && seqs.length > 0) { + // store event message(s), if any + seq_events[seq_id] = + (buffer ? seq_events[seq_id] : []).concat( + args.length > 0 ? (args.length > 1 ? [args] : args[0]) : undefined + ); + + // collect event message(s) across the + // sequence-stream sources + var messages = seq_events.reduce(function reducer(msgs,eventList,idx){ + if (eventList.length > 0) msgs.push(eventList[0]); + return msgs; + },[]); + + // did all sequence-streams get an event? + if (messages.length == seq_events.length) { + if (messages.length == 1) messages = messages[0]; + + // fire off reactive sequence instance + next.apply(ø,messages); + + // discard stored event message(s)? + if (!keep) { + seq_events.forEach(function $$each(eventList){ + eventList.shift(); + }); + } + } + } + // keep sequence going + return args; + } + + var seq_id = seq_events.length; + seq_events.push([]); + def.seq.val(trigger); + } + + // process all sequence-streams + seqs.forEach(processSequence); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + seqs = seq_events = null; + }); + } + + var seq_events = [], + // observe all sequence-streams + seqs = tapSequences.apply(null,arguments) + ; + + if (seqs.length == 0) return; + + return Ar(reactor); + }; + } + + function makeDistinctFilterer(keepAll) { + function filterer() { + function isDuplicate(msgSet) { + return ( + msgSet.length == message_set.length && + msgSet.every(function $$every(val,idx){ + return val === message_set[idx]; + }) + ); + } + + var message_set = ASQ.messages.apply(ø,arguments); + + // any messages in message-set to check against? + if (message_set.length > 0) { + // duplicate message-set? + if (msg_sets.some(isDuplicate)) { + return false; + } + + // remember all message-sets for future distinct checking? + if (keepAll) { + msg_sets.push(message_set); + } + // only keep the last message-set for distinct-consecutive + // checking + else { + msg_sets[0] = message_set; + } + } + + // allow distinct non-duplicate value through + return true; + } + + var msg_sets = []; + + return filterer; + } + +})(); +// "runner" +ASQ.extend("runner",function $$extend(api,internals){ + + return function $$runner() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var args = ARRAY_SLICE.call(arguments); + + api + .then(function $$then(mainDone){ + + function wrap(v) { + // function? expected to produce an iterator + // (like a generator) or a promise + if (typeof v === "function") { + // call function passing in the control token + // note: neutralize `this` in call to prevent + // unexpected behavior + v = v.call(ø,token); + + // promise returned (ie, from async function)? + if (isPromise(v)) { + // wrap it in iterable sequence + v = ASQ.iterable(v); + } + } + // an iterable sequence? duplicate it (in case of multiple runs) + else if (ASQ.isSequence(v) && "next" in v) { + v = v.duplicate(); + } + // wrap anything else in iterable sequence + else { + v = ASQ.iterable(v); + } + + // a sequence to tap for errors? + if (ASQ.isSequence(v)) { + // listen for any sequence failures + v.or(function $$or(){ + // signal iteration-error + mainDone.fail.apply(ø,arguments); + }); + } + + return v; + } + + function addWrapped() { + iterators.push.apply( + iterators, + ARRAY_SLICE.call(arguments).map(wrap) + ); + } + + function iterateOrQuit(iterFn,now) { + // still have some co-routine runs to process? + if (iterators.length > 0) { + if (now) iterFn(); + else schedule(iterFn); + } + // all done! + else { + // previous value message? + if (typeof next_val !== "undefined") { + // not a message wrapper array? + if (!ASQ.isMessageWrapper(next_val)) { + // wrap value for the subsequent `apply(..)` + next_val = [next_val]; + } + } + else { + // nothing to affirmatively pass along + next_val = []; + } + + // signal done with all co-routine runs + mainDone.apply(ø,next_val); + } + } + + var iterators = args, + token = { + messages: ARRAY_SLICE.call(arguments,1), + add: addWrapped + }, + iter, ret, next_val = token + ; + + // map co-routines to round-robin list of iterators + iterators = iterators.map(wrap); + + // async iteration of round-robin list + (function iterate(){ + // get next co-routine in list + iter = iterators.shift(); + + // process the iteration + try { + // multiple messages to send to an iterable + // sequence? + if (ASQ.isMessageWrapper(next_val) && + ASQ.isSequence(iter) + ) { + ret = iter.next.apply(iter,next_val); + } + else { + ret = iter.next(next_val); + } + } + catch (err) { + return mainDone.fail(err); + } + + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + // was the control token yielded? + if (ret.value === token) { + // round-robin: put co-routine back into the list + // at the end where it was so it can be processed + // again on next loop-iteration + if (!ret.done) { + iterators.push(iter); + } + next_val = token; + iterateOrQuit(iterate,/*now=*/false); + } + else { + // not a recognized ASQ instance returned? + if (!ASQ.isSequence(ret.value)) { + // received a thenable/promise back? + if (isPromise(ret.value)) { + // wrap in a sequence + ret.value = ASQ().promise(ret.value); + } + // thunk yielded? + else if (typeof ret.value === "function") { + // wrap thunk call in a sequence + var fn = ret.value; + ret.value = ASQ(function $$ASQ(done){ + fn(done.errfcb); + }); + } + // message wrapper returned? + else if (ASQ.isMessageWrapper(ret.value)) { + // wrap message(s) in a sequence + ret.value = ASQ.apply(ø, + // don't let `apply(..)` discard an empty message + // wrapper! instead, pass it along as its own value + // itself. + ret.value.length > 0 ? ret.value : ASQ.messages(undefined) + ); + } + // non-undefined value returned? + else if (typeof ret.value !== "undefined") { + // wrap the value in a sequence + ret.value = ASQ(ret.value); + } + else { + // make an empty sequence + ret.value = ASQ(); + } + } + + ret.value + .val(function $$val(){ + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + if (arguments.length > 0) { + // save any return messages for input + // to next iteration + next_val = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + } + + // still more to iterate? + if (!ret.done) { + // was the control token passed along? + if (next_val === token) { + // round-robin: put co-routine back into the list + // at the end, so that the the next iterator can be + // processed on next loop-iteration + iterators.push(iter); + } + else { + // put co-routine back in where it just + // was so it can be processed again on + // next loop-iteration + iterators.unshift(iter); + } + } + + iterateOrQuit(iterate,/*now=*/true); + }) + .or(function $$or(){ + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + try { + // if an error occurs in the step-continuation + // promise or sequence, throw it back into the + // generator or iterable-sequence + iter["throw"].apply(iter,arguments); + } + catch (err) { + // if an error comes back out of after the throw, + // pass it out to the main sequence, as iteration + // must now be complete + mainDone.fail(err); + } + }); + } + })(); + }); + + return api; + }; +}); +// "toPromise" +ASQ.extend("toPromise",function $$extend(api,internals){ + return function $$to$promise() { + return new Promise(function $$executor(resolve,reject){ + api + .val(function $$val(){ + var args = ARRAY_SLICE.call(arguments); + resolve.call(ø,args.length > 1 ? args : args[0]); + return ASQ.messages.apply(ø,args); + }) + .or(function $$or(){ + var args = ARRAY_SLICE.call(arguments); + reject.call(ø,args.length > 1 ? args : args[0]); + }); + }); + }; +}); +// "try" +ASQ.extend("try",function $$extend(api,internals){ + return function $$try() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(fn){ + return function $$then(mainDone) { + var main_args = ARRAY_SLICE.call(arguments), + sq = ASQ.apply(ø,main_args.slice(1)) + ; + + sq + .then(function $$inner$then(){ + fn.apply(ø,arguments); + }) + .val(function $$val(){ + mainDone.apply(ø,arguments); + }) + .or(function $$inner$or(){ + var msgs = ASQ.messages.apply(ø,arguments); + // failed, so map error(s) as `catch` + mainDone({ + "catch": msgs.length > 1 ? msgs : msgs[0] + }); + }); + }; + }); + + api.then.apply(ø,fns); + + return api; + }; +}); +// "until" +ASQ.extend("until",function $$extend(api,internals){ + return function $$until() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(fn){ + return function $$then(mainDone) { + var main_args = ARRAY_SLICE.call(arguments), + sq = ASQ.apply(ø,main_args.slice(1)) + ; + + sq + .then(function $$inner$then(){ + var args = ARRAY_SLICE.call(arguments); + args[0]["break"] = function $$break(){ + mainDone.fail.apply(ø,arguments); + sq.abort(); + }; + + fn.apply(ø,args); + }) + .val(function $$val(){ + mainDone.apply(ø,arguments); + }) + .or(function $$inner$or(){ + // failed, retry + $$then.apply(ø,main_args); + }); + }; + }); + + api.then.apply(ø,fns); + + return api; + }; +}); +// "waterfall" +ASQ.extend("waterfall",function $$extend(api,internals){ + return function $$waterfall() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + var msgs = ASQ.messages(), + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + fns.forEach(function $$each(fn){ + sq.then(fn) + .val(function $$val(){ + var args = ASQ.messages.apply(ø,arguments); + msgs.push(args.length > 1 ? args : args[0]); + return msgs; + }); + }); + + sq.pipe(done); + }); + + return api; + }; +}); +// "wrap" +ASQ.wrap = function $$wrap(fn,opts) { + function checkThis(t,o) { + return (!t || + (typeof window != "undefined" && t === window) || + (typeof global != "undefined" && t === global) + ) ? o : t; + } + + function paramSpread(gen) { + return function *paramSpread(token) { + yield *gen.apply(this,token.messages); + }; + } + + var errfcb, params_first, act, this_obj; + + opts = (opts && typeof opts == "object") ? opts : {}; + + if ( + (opts.errfcb && opts.splitcb) || + (opts.errfcb && opts.simplecb) || + (opts.splitcb && opts.simplecb) || + ("errfcb" in opts && !opts.errfcb && !opts.splitcb && !opts.simplecb) || + (opts.params_first && opts.params_last) || + (opts.spread && !opts.gen) + ) { + throw Error("Invalid options"); + } + + // initialize default flags + this_obj = (opts["this"] && typeof opts["this"] == "object") ? opts["this"] : ø; + errfcb = opts.errfcb || !(opts.splitcb || opts.simplecb); + params_first = !!opts.params_first || + (!opts.params_last && !("params_first" in opts || opts.params_first)) || + ("params_last" in opts && !opts.params_first && !opts.params_last) + ; + + if (params_first) { + act = "push"; + } + else { + act = "unshift"; + } + + if (opts.gen) { + if (opts.spread) { + fn = paramSpread(fn); + } + return function $$wrapped$gen() { + return ASQ.apply(ø,arguments).runner(fn); + }; + } + if (errfcb) { + return function $$wrapped$errfcb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done.errfcb); + fn.apply(_this,args); + }); + }; + } + if (opts.splitcb) { + return function $$wrapped$splitcb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done,done.fail); + fn.apply(_this,args); + }); + }; + } + if (opts.simplecb) { + return function $$wrapped$simplecb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done); + fn.apply(_this,args); + }); + }; + } +}; + + + // just return `ASQ` itself for convenience sake + return ASQ; +}); diff --git a/frontend-masters-exercises/exercises/ex7/ex7-fixed.html b/frontend-masters-exercises/exercises/ex7/ex7-fixed.html new file mode 100755 index 0000000..b740d48 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex7/ex7-fixed.html @@ -0,0 +1,15 @@ + + + + +Exercise 7 - Fixed + + +

Exercise 7 - Fixed

+ + + + + + + diff --git a/frontend-masters-exercises/exercises/ex7/ex7-fixed.js b/frontend-masters-exercises/exercises/ex7/ex7-fixed.js new file mode 100755 index 0000000..00ff999 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex7/ex7-fixed.js @@ -0,0 +1,51 @@ +function fakeAjax(url,cb) { + var fake_responses = { + "file1": "The first text", + "file2": "The middle text", + "file3": "The last text" + }; + var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000; + + console.log("Requesting: " + url); + + setTimeout(function(){ + cb(fake_responses[url]); + },randomDelay); +} + +function output(text) { + console.log(text); +} + +// ************************************** + +function getFile(file) { + return ASQ(function(done){ + fakeAjax(file,done); + }); +} + +// function getFile(file) { +// return new Promise(function(resolve){ +// fakeAjax(file,resolve); +// }); +// } + +ASQ() +.runner(function *loadFiles(){ + // Request all files at once in + // "parallel" via `getFile(..)`. + var p1 = getFile("file1"); + var p2 = getFile("file2"); + var p3 = getFile("file3"); + + // Render as each one finishes, + // but only once previous rendering + // is done. + output( yield p1 ); + output( yield p2 ); + output( yield p3 ); +}) +.val(function(){ + output("Complete!"); +}); diff --git a/frontend-masters-exercises/exercises/ex7/ex7.html b/frontend-masters-exercises/exercises/ex7/ex7.html new file mode 100755 index 0000000..9f98a79 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex7/ex7.html @@ -0,0 +1,15 @@ + + + + +Exercise 7 + + +

Exercise 7

+ + + + + + + diff --git a/frontend-masters-exercises/exercises/ex7/ex7.js b/frontend-masters-exercises/exercises/ex7/ex7.js new file mode 100755 index 0000000..a76785a --- /dev/null +++ b/frontend-masters-exercises/exercises/ex7/ex7.js @@ -0,0 +1,35 @@ +function fakeAjax(url,cb) { + var fake_responses = { + "file1": "The first text", + "file2": "The middle text", + "file3": "The last text" + }; + var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000; + + console.log("Requesting: " + url); + + setTimeout(function(){ + cb(fake_responses[url]); + },randomDelay); +} + +function output(text) { + console.log(text); +} + +// ************************************** + +function getFile(file) { + return ASQ(function(done){ + fakeAjax(file,done); + }); +} + +// Request all files at once in +// "parallel" via `getFile(..)`. +// +// Render as each one finishes, +// but only once previous rendering +// is done. + +// ??? diff --git a/frontend-masters-exercises/exercises/ex7/npo.js b/frontend-masters-exercises/exercises/ex7/npo.js new file mode 100755 index 0000000..c363ed4 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex7/npo.js @@ -0,0 +1,5 @@ +/*! Native Promise Only + v0.8.1 (c) Kyle Simpson + MIT License: http://getify.mit-license.org +*/ +!function(t,n,e){n[t]=n[t]||e(),"undefined"!=typeof module&&module.exports?module.exports=n[t]:"function"==typeof define&&define.amd&&define(function(){return n[t]})}("Promise","undefined"!=typeof global?global:this,function(){"use strict";function t(t,n){l.add(t,n),h||(h=y(l.drain))}function n(t){var n,e=typeof t;return null==t||"object"!=e&&"function"!=e||(n=t.then),"function"==typeof n?n:!1}function e(){for(var t=0;t0&&t(e,u))}catch(a){i.call(new f(u),a)}}}function i(n){var o=this;o.triggered||(o.triggered=!0,o.def&&(o=o.def),o.msg=n,o.state=2,o.chain.length>0&&t(e,o))}function c(t,n,e,o){for(var r=0;r0){u=!1,a=s.shift(),c=g.slice(),g.length=0,c.unshift(createStepCompletion());try{a.apply(h,c)}catch(i){l(i)?$=$.concat(i):$.push(i),n=!0,scheduleSequenceTick()}}}function createStepCompletion(){function done(){n||r||u||(u=!0,g.push.apply(g,arguments),$.length=0,scheduleSequenceTick())}return done.fail=function $$step$fail(){n||r||u||(n=!0,g.length=0,$.push.apply($,arguments),scheduleSequenceTick())},done.abort=function $$step$abort(){n||r||(u=!1,r=!0,g.length=$.length=0,scheduleSequenceTick())},done.errfcb=function $$step$errfcb(e){e?done.fail(e):done.apply(h,f.call(arguments,1))},done}function createGate(e,t,u){function resetGate(){clearTimeout(s),s=d=m=o=null}function scheduleGateTick(){return g?gateTick():void(s||(s=schedule(gateTick)))}function gateTick(){if(!(n||r||$)){var t=[];s=null,p?(e.fail.apply(h,o),resetGate()):g?(e.abort(),resetGate()):checkGate()&&($=!0,d.forEach(function $$each(e,n){t.push(m["s"+n])}),e.apply(h,t),resetGate())}}function checkGate(){if(0!==d.length){var e=!0;return d.some(function $$some(n){return null===n?(e=!1,!0):void 0}),e}}function createSegmentCompletion(){function done(){if(!(n||r||p||g||$||d[e])){var t=c.apply(h,arguments);m["s"+e]=t.length>1?t:t[0],d[e]=!0,scheduleGateTick()}}var e=d.length;return done.fail=function $$segment$fail(){n||r||p||g||$||d[e]||(p=!0,o=f.call(arguments),scheduleGateTick())},done.abort=function $$segment$abort(){n||r||p||g||$||(g=!0,gateTick())},done.errfcb=function $$segment$errfcb(e){e?done.fail(e):done.apply(h,f.call(arguments,1))},d[e]=null,done}var a,i,o,s,p=!1,g=!1,$=!1,d=[],m={};t.some(function $$some(e){if(p||g)return!0;a=u.slice(),a.unshift(createSegmentCompletion());try{e.apply(h,a)}catch(n){return i=n,p=!0,!0}}),i&&(l(i)?e.fail.apply(h,i):e.fail(i))}function then(){return n||r||0===arguments.length?d:(wrapArgs(arguments,thenWrapper).forEach(function $$each(e){i(e)?seq(e):s.push(e)}),scheduleSequenceTick(),d)}function or(){return r||0===arguments.length?d:(p.push.apply(p,arguments),scheduleSequenceTick(),d)}function gate(){if(n||r||0===arguments.length)return d;var e=f.call(arguments).map(function $$map(e){var n;return i(e)?(n={seq:e},tapSequence(n),function $$segment(e){n.seq.pipe(e)}):e});return then(function $$then(n){var t=f.call(arguments,1);createGate(n,e,t)}),d}function pipe(){return r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){then(function $$then(n){e.apply(h,f.call(arguments,1)),n()}).or(e.fail)}),d)}function seq(){return n||r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){var n={seq:e};i(e)&&tapSequence(n),then(function $$then(e){var t=n.seq;i(t)||(t=n.seq.apply(h,f.call(arguments,1))),t.pipe(e)})}),d)}function val(){return n||r||0===arguments.length?d:(f.call(wrapArgs(arguments,valWrapper)).forEach(function $$each(e){then(function $$then(n){var t=e.apply(h,f.call(arguments,1));l(t)||(t=c(t)),n.apply(h,t)})}),d)}function promise(){function wrap(e){return function $$fn(){e.apply(h,l(arguments[0])?arguments[0]:arguments)}}return n||r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){then(function $$then(n){var t=e;"function"==typeof e&&"function"!=typeof e.then&&(t=e.apply(h,f.call(arguments,1))),t.then(wrap(n),wrap(n.fail))})}),d)}function fork(){var e;return val(function $$val(){return e?e.apply(h,arguments):e=createSequence.apply(h,arguments).defer(),c.apply(h,arguments)}),or(function $$or(){if(e)e.fail.apply(h,arguments);else{var n=f.call(arguments);e=createSequence().then(function $$then(e){e.fail.apply(h,n)}).defer()}}),createSequence().then(function $$then(n){e?e.pipe(n):e=n}).defer()}function abort(){return n?d:(r=!0,sequenceTick(),d)}function duplicate(){var e;return a={then_queue:s.slice(),or_queue:p.slice()},e=createSequence(),a=null,e}function unpause(){g.push.apply(g,arguments),e===!0&&(e=null),scheduleSequenceTick()}function defer(){return p.push(function ignored(){}),d}function internals(e,t){var a=arguments.length>1;switch(e){case"seq_error":if(!a)return n;n=t;break;case"seq_aborted":if(!a)return r;r=t;break;case"then_ready":if(!a)return u;u=t;break;case"then_queue":return s;case"or_queue":return p;case"sequence_messages":return g;case"sequence_errors":return $}}function includeExtensions(){Object.keys(o).forEach(function $$each(e){d[e]=o[e](d,internals)})}var e,n=!1,t=!1,r=!1,u=!0,s=[],p=[],g=[],$=[],d=brandIt({then:then,or:or,onerror:or,gate:gate,all:gate,pipe:pipe,seq:seq,val:val,promise:promise,fork:fork,abort:abort,duplicate:duplicate,defer:defer});return includeExtensions(),a&&(s=a.then_queue.slice(),p=a.or_queue.slice(),d.unpause=unpause,e=!0),d.then.apply(h,arguments),d}function brandIt(e){return Object.defineProperty(e,p,{enumerable:!1,value:!0})}function checkBranding(e){return!(null==e||"object"!=typeof e||!e[p])}function valWrapper(e){return c.apply(h,f.call(arguments).slice(1,e+1))}function thenWrapper(e){arguments[e+1].apply(h,f.call(arguments).slice(1,e+1))}function wrapArgs(e,n){var t,r;for(e=f.call(e),t=0;t 1 ? + ARRAY_SLICE.call(arguments,1) : + void 0 + ; + num = +num || 0; + + api.then(function $$then(done){ + var args = orig_args || ARRAY_SLICE.call(arguments,1); + + setTimeout(function $$set$timeout(){ + done.apply(ø,args); + },num); + }); + + return api; + }; +}); + +ASQ.after = function $$after() { + return ASQ().after.apply(ø,arguments); +}; +// "any" +ASQ.extend("any",function $$extend(api,internals){ + return function $$any() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages.length = 0; + } + + function complete(trigger) { + if (success_messages.length > 0) { + // any successful segment's message(s) sent + // to main sequence to proceed as success + success_messages.length = fns.length; + trigger.apply(ø,success_messages); + } + else { + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + success_messages = [], + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "errfcb" +ASQ.extend("errfcb",function $$extend(api,internals){ + return function $$errfcb() { + // create a fake sequence to extract the callbacks + var sq = { + val: function $$then(cb){ sq.val_cb = cb; return sq; }, + or: function $$or(cb){ sq.or_cb = cb; return sq; } + }; + + // trick `seq(..)`s checks for a sequence + sq[brand] = true; + + // immediately register our fake sequence on the + // main sequence + api.seq(sq); + + // provide the "error-first" callback + return function $$errorfirst$callback(err) { + if (err) { + sq.or_cb(err); + } + else { + sq.val_cb.apply(ø,ARRAY_SLICE.call(arguments,1)); + } + }; + }; +}); +// "failAfter" +ASQ.extend("failAfter",function $$extend(api,internals){ + return function $$failAfter(num) { + var args = arguments.length > 1 ? + ARRAY_SLICE.call(arguments,1) : + void 0 + ; + num = +num || 0; + + api.then(function $$then(done){ + setTimeout(function $$set$timeout(){ + done.fail.apply(ø,args); + },num); + }); + + return api; + }; +}); + +ASQ.failAfter = function $$fail$after() { + return ASQ().failAfter.apply(ø,arguments); +}; +// "first" +ASQ.extend("first",function $$extend(api,internals){ + return function $$first() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + error_messages.length = 0; + } + + function success(trigger,idx,args) { + if (!finished) { + finished = true; + + // first successful segment triggers + // main sequence to proceed as success + trigger( + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ); + + reset(); + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete without success? + if (completed === fns.length) { + finished = true; + + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + + reset(); + } + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "go-style CSP" +(function IIFE(){ + + // filter out already-resolved queue entries + function filterResolved(queue) { + return queue.filter(function $$filter(entry){ + return !entry.resolved; + }); + } + + function closeQueue(queue,finalValue) { + queue.forEach(function $$each(iter){ + if (!iter.resolved) { + iter.next(); + iter.next(finalValue); + } + }); + queue.length = 0; + } + + function channel(bufSize) { + var ch = { + close: function $$close(){ + ch.closed = true; + closeQueue(ch.put_queue,false); + closeQueue(ch.take_queue,ASQ.csp.CLOSED); + }, + closed: false, + messages: [], + put_queue: [], + take_queue: [], + buffer_size: +bufSize || 0 + }; + return ch; + } + + function unblock(iter) { + if (iter && !iter.resolved) { + iter.next(iter.next().value); + } + } + + function put(channel,value) { + var ret; + + if (channel.closed) { + return false; + } + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + // immediate put? + if (channel.messages.length < channel.buffer_size) { + channel.messages.push(value); + unblock(channel.take_queue.shift()); + return true; + } + // queued put + else { + channel.put_queue.push( + // make a notifiable iterable for 'put' blocking + ASQ.iterable() + .then(function $$then(){ + if (!channel.closed) { + channel.messages.push(value); + return true; + } + else { + return false; + } + }) + ); + + // wrap a sequence/promise around the iterable + ret = ASQ( + channel.put_queue[channel.put_queue.length - 1] + ); + + // take waiting on this queued put? + if (channel.take_queue.length > 0) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + + return ret; + } + } + + function putAsync(channel,value,cb) { + var ret = ASQ(put(channel,value)); + + if (cb && typeof cb == "function") { + ret.val(cb); + } + else { + return ret; + } + } + + function take(channel) { + var ret; + + try { + ret = takem(channel); + } + catch (err) { + ret = err; + } + + if (ASQ.isSequence(ret)) { + ret.pCatch(function $$pcatch(err){ + return err; + }); + } + + return ret; + } + + function takeAsync(channel,cb) { + var ret = ASQ(take(channel)); + + if (cb && typeof cb == "function") { + ret.val(cb); + } + else { + return ret; + } + } + + function takem(channel) { + var msg; + + if (channel.closed) { + return ASQ.csp.CLOSED; + } + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + // immediate take? + if (channel.messages.length > 0) { + msg = channel.messages.shift(); + unblock(channel.put_queue.shift()); + if (msg instanceof Error) { + throw msg; + } + return msg; + } + // queued take + else { + channel.take_queue.push( + // make a notifiable iterable for 'take' blocking + ASQ.iterable() + .then(function $$then(){ + if (!channel.closed) { + var v = channel.messages.shift(); + if (v instanceof Error) { + throw v; + } + return v; + } + else { + return ASQ.csp.CLOSED; + } + }) + ); + + // wrap a sequence/promise around the iterable + msg = ASQ( + channel.take_queue[channel.take_queue.length - 1] + ); + + // put waiting on this take? + if (channel.put_queue.length > 0) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + + return msg; + } + } + + function takemAsync(channel,cb) { + var ret = ASQ(takem(channel)); + + if (cb && typeof cb == "function") { + ret.pThen(cb,cb); + } + else { + return ret.val(function $$val(v){ + if (v instanceof Error) { + throw v; + } + return v; + }); + } + } + + function alts(actions) { + var closed, open, handlers, i, isq, ret, resolved = false; + + // used `alts(..)` incorrectly? + if (!Array.isArray(actions) || actions.length == 0) { + throw Error("Invalid usage"); + } + + closed = []; + open = []; + handlers = []; + + // separate actions by open/closed channel status + actions.forEach(function $$each(action){ + var channel = Array.isArray(action) ? action[0] : action; + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + if (channel.closed) { + closed.push(channel); + } + else { + open.push(action); + } + }); + + // if no channels are still open, we're done + if (open.length == 0) { + return { value: ASQ.csp.CLOSED, channel: closed }; + } + + // can any channel action be executed immediately? + for (i=0; i 0) { + return { value: take(open[i]), channel: open[i] }; + } + } + + isq = ASQ.iterable(); + var ret = ASQ(isq); + + // setup channel action handlers + for (i=0; i 0) { + schedule(function handleUnblocking(){ + if (!resolved) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + },0); + } + } + // take action? + else { + channel = action; + + // define take handler + handlers.push( + ASQ.iterable() + .then(function $$then(){ + resolved = true; + + // mark all handlers across this `alts(..)` as resolved now + handlers = handlers.filter(function $$filter(handler){ + return !(handler.resolved = true); + }); + + // channel still open? + if (!channel.closed) { + isq.next({ value: channel.messages.shift(), channel: channel }); + } + // channel already closed? + else { + isq.next({ value: ASQ.csp.CLOSED, channel: channel }); + } + }) + ); + + // queue up take handler + channel.take_queue.push(handlers[handlers.length-1]); + + // put waiting on this queued take? + if (channel.put_queue.length > 0) { + schedule(function handleUnblocking(){ + if (!resolved) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + }); + } + } + })(open[i]); + } + + return ret; + } + + function altsAsync(chans,cb) { + var ret = ASQ(alts(chans)); + + if (cb && typeof cb == "function") { + ret.pThen(cb,cb); + } + else { + return ret; + } + } + + function timeout(delay) { + var ch = channel(); + setTimeout(ch.close,delay); + return ch; + } + + function go(gen,args) { + // goroutine arguments passed? + if (arguments.length > 1) { + if (!args || !Array.isArray(args)) { + args = [args]; + } + } + else { + args = []; + } + + return function *$$go(token) { + + // unblock the overall goroutine handling + function unblock() { + token.unblock_count++; + + if (token.block && !token.block.marked) { + token.block.marked = true; + token.block.next(); + } + } + + var ret, msg, err, type, done = false, it; + + // keep track of how many requests for unblocking + // have occurred + token.unblock_count = (token.unblock_count || 0); + + // keep track of how many goroutines are running + // so we can infer when we're done go'ing + token.go_count = (token.go_count || 0) + 1; + + // need to initialize a set of goroutines? + if (token.go_count === 1) { + // create a default channel for these goroutines + token.channel = channel(); + token.channel.messages = token.messages; + token.channel.go = function $$go(){ + // unblock the goroutine handling for this + // new goroutine + unblock(); + // add the goroutine (called with any args) to + // the handling queue + token.add( go.apply(ø,arguments) ); + }; + // starting out with initial channel messages? + if (token.channel.messages.length > 0) { + // fake back-pressure blocking for each + token.channel.put_queue = token.channel.messages.map(function $$map(){ + // make a notifiable iterable for 'put' blocking + return ASQ.iterable() + .then(function $$then(){ + unblock(token.channel.take_queue.shift()); + return !token.channel.closed; + }); + }); + } + } + + // initialize the generator + it = gen.apply(ø,[token.channel].concat(args)); + + (function iterate(){ + + function next() { + // keep going with next step in goroutine? + if (!done) { + iterate(); + } + // unblock overall goroutine handling to + // continue with other goroutines + else { + unblock(); + } + } + + // has a resumption value been achieved yet? + if (!ret) { + // try to resume the goroutine + try { + // resume with injected exception? + if (err) { + ret = it.throw(err); + err = null; + } + // resume normally + else { + ret = it.next(msg); + } + } + // resumption failed, so bail + catch (e) { + done = true; + err = e; + msg = null; + unblock(); + return; + } + + // keep track of the result of the resumption + done = ret.done; + ret = ret.value; + type = typeof ret; + + // if this goroutine is complete, unblock the + // overall goroutine handling + if (done) { + unblock(); + } + + // received a thenable/promise back? + if (isPromise(ret)) { + ret = ASQ().promise(ret); + } + + // wait for the value? + if (ASQ.isSequence(ret)) { + ret.val(function $$val(){ + ret = null; + msg = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + next(); + }) + .or(function $$or(){ + ret = null; + msg = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + if (msg instanceof Error) { + err = msg; + msg = null; + } + next(); + }); + } + // immediate value, prepare it to go right back in + else { + msg = ret; + ret = null; + next(); + } + } + })(); + + // keep this goroutine alive until completion + while (!done) { + // transfer control to another goroutine + yield token; + + // need to block overall goroutine handling + // while idle? + if (!done && !token.block && token.unblock_count === 0) { + // wait here while idle + yield (token.block = ASQ.iterable()); + + token.block = false; + } + + if (token.unblock_count > 0) token.unblock_count--; + } + + // this goroutine is done now + token.go_count--; + + // all goroutines done? + if (token.go_count === 0) { + // any lingering blocking need to be cleaned up? + unblock(); + + // capture any untaken messages + msg = ASQ.messages.apply(ø,token.messages); + + // need to implicitly force-close channel? + if (token.channel && !token.channel.closed) { + token.channel.closed = true; + token.channel.put_queue.length = token.channel.take_queue.length = 0; + token.channel.close = token.channel.go = token.channel.messages = null; + } + token.channel = null; + } + + // make sure leftover error or message are + // passed along + if (err) { + throw err; + } + else if (token.go_count === 0) { + return msg; + } + else { + return token; + } + }; + } + + ASQ.csp = { + chan: channel, + put: put, + putAsync: putAsync, + take: take, + takeAsync: takeAsync, + takem: takem, + takemAsync: takemAsync, + alts: alts, + altsAsync: altsAsync, + timeout: timeout, + go: go, + CLOSED: {} + }; + +})(); +// "ASQ.iterable()" +(function IIFE(){ + var template; + + ASQ.iterable = function $$iterable() { + function throwSequenceErrors() { + throw (sequence_errors.length === 1 ? sequence_errors[0] : sequence_errors); + } + + function notifyErrors() { + var fn; + + seq_tick = null; + + if (seq_error) { + if (or_queue.length === 0 && !error_reported) { + error_reported = true; + throwSequenceErrors(); + } + + while (or_queue.length > 0) { + error_reported = true; + fn = or_queue.shift(); + try { + fn.apply(ø,sequence_errors); + } + catch (err) { + if (checkBranding(err)) { + sequence_errors = sequence_errors.concat(err); + } + else { + sequence_errors.push(err); + } + if (or_queue.length === 0) { + throwSequenceErrors(); + } + } + } + } + } + + function val() { + if (seq_error || seq_aborted || arguments.length === 0) { + return sequence_api; + } + + var args = ARRAY_SLICE.call(arguments).map(function mapper(arg){ + if (typeof arg != "function") return function $$val() { return arg; }; + else return arg; + }); + + val_queue.push.apply(val_queue,args); + + return sequence_api; + } + + function or() { + if (seq_aborted || arguments.length === 0) { + return sequence_api; + } + + or_queue.push.apply(or_queue,arguments); + + if (!seq_tick) { + seq_tick = schedule(notifyErrors); + } + + return sequence_api; + } + + function pipe() { + if (seq_aborted || arguments.length === 0) { + return sequence_api; + } + + ARRAY_SLICE.call(arguments) + .forEach(function $$each(fn){ + val(fn).or(fn.fail); + }); + + return sequence_api; + } + + function next() { + if (seq_error || seq_aborted || val_queue.length === 0) { + if (val_queue.length > 0) { + $throw$("Sequence cannot be iterated"); + } + return { done: true }; + } + + try { + return { value: val_queue.shift().apply(ø,arguments) }; + } + catch (err) { + if (ASQ.isMessageWrapper(err)) { + $throw$.apply(ø,err); + } + else { + $throw$(err); + } + + return {}; + } + } + + function $throw$() { + if (seq_error || seq_aborted) { + return sequence_api; + } + + sequence_errors.push.apply(sequence_errors,arguments); + seq_error = true; + if (!seq_tick) { + seq_tick = schedule(notifyErrors); + } + + return sequence_api; + } + + function $return$(val) { + if (seq_error || seq_aborted) { + val = void 0; + } + + abort(); + + return { done: true, value: val }; + } + + function abort() { + if (seq_error || seq_aborted) { + return; + } + + seq_aborted = true; + + clearTimeout(seq_tick); + seq_tick = null; + val_queue.length = or_queue.length = sequence_errors.length = 0; + } + + function duplicate() { + var isq; + + template = { + val_queue: val_queue.slice(), + or_queue: or_queue.slice() + }; + isq = ASQ.iterable(); + template = null; + + return isq; + } + + // opt-out of global error reporting for this sequence + function defer() { + or_queue.push(function $$ignored(){}); + return sequence_api; + } + + // *********************************************** + // Object branding utilities + // *********************************************** + function brandIt(obj) { + Object.defineProperty(obj,brand,{ + enumerable: false, + value: true + }); + + return obj; + } + + var sequence_api, + + seq_error = false, + error_reported = false, + seq_aborted = false, + + seq_tick, + + val_queue = [], + or_queue = [], + + sequence_errors = [] + ; + + // *********************************************** + // Setup the ASQ.iterable() public API + // *********************************************** + sequence_api = brandIt({ + val: val, + then: val, + or: or, + pipe: pipe, + next: next, + "throw": $throw$, + "return": $return$, + abort: abort, + duplicate: duplicate, + defer: defer + }); + + // useful for ES6 `for..of` loops, + // add `@@iterator` to simply hand back + // our iterable sequence itself! + sequence_api[(typeof Symbol == "function" && Symbol.iterator) || "@@iterator"] = function $$iter() { + return sequence_api; + }; + + // templating the iterable-sequence setup? + if (template) { + val_queue = template.val_queue.slice(0); + or_queue = template.or_queue.slice(0); + } + + // treat ASQ.iterable() constructor parameters as having been + // passed to `val()` + sequence_api.val.apply(ø,arguments); + + return sequence_api; + }; + +})(); +// "last" +ASQ.extend("last",function $$extend(api,internals){ + return function $$last() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages = null; + } + + function complete(trigger) { + if (success_messages != null) { + // last successful segment's message(s) sent + // to main sequence to proceed as success + trigger( + success_messages.length > 1 ? + ASQ.messages.apply(ø,success_messages) : + success_messages[0] + ); + } + else { + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages = args; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)), + success_messages + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "map" +ASQ.extend("map",function $$extend(api,internals){ + return function $$map(pArr,pEach) { + if (internals("seq_error") || internals("seq_aborted")) { + return api; + } + + api.seq(function $$seq(){ + var tmp, args = ARRAY_SLICE.call(arguments), + arr = pArr, each = pEach; + + // if missing `map(..)` args, use value-messages (if any) + if (!each) each = args.shift(); + if (!arr) arr = args.shift(); + + // if arg types in reverse order (each,arr), swap + if (typeof arr === "function" && Array.isArray(each)) { + tmp = arr; + arr = each; + each = tmp; + } + + return ASQ.apply(ø,args) + .gate.apply(ø,arr.map(function $$map(item){ + return function $$segment(){ + each.apply(ø,[item].concat(ARRAY_SLICE.call(arguments))); + }; + })); + }) + .val(function $$val(){ + // collect all gate segment output into one value-message + // Note: return a normal array here, not a message wrapper! + return ARRAY_SLICE.call(arguments); + }); + + return api; + }; +}); +// "none" +ASQ.extend("none",function $$extend(api,internals){ + return function $$none() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages.length = 0; + } + + function complete(trigger) { + if (success_messages.length > 0) { + // any successful segment's message(s) sent + // to main sequence to proceed as **error** + success_messages.length = fns.length; + trigger.fail.apply(ø,success_messages); + } + else { + // send errors as **success** to main sequence + error_messages.length = fns.length; + trigger.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)), + success_messages = [] + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "pThen" +ASQ.extend("pThen",function $$extend(api,internals){ + return function $$pthen(success,failure) { + if (internals("seq_aborted")) { + return api; + } + + var ignore_success_handler = false, ignore_failure_handler = false; + + if (typeof success === "function") { + api.then(function $$then(done){ + if (!ignore_success_handler) { + var ret, msgs = ASQ.messages.apply(ø,arguments); + msgs.shift(); + + if (msgs.length === 1) { + msgs = msgs[0]; + } + + ignore_failure_handler = true; + + try { + ret = success(msgs); + } + catch (err) { + if (!ASQ.isMessageWrapper(err)) { + err = [err]; + } + done.fail.apply(ø,err); + return; + } + + // returned a sequence? + if (ASQ.isSequence(ret)) { + ret.pipe(done); + } + // returned a message wrapper? + else if (ASQ.isMessageWrapper(ret)) { + done.apply(ø,ret); + } + // returned a promise/thenable? + else if (isPromise(ret)) { + ret.then(done,done.fail); + } + // just a normal value to pass along + else { + done(ret); + } + } + else { + done.apply(ø,ARRAY_SLICE.call(arguments,1)); + } + }); + } + if (typeof failure === "function") { + api.or(function $$or(){ + if (!ignore_failure_handler) { + var ret, msgs = ASQ.messages.apply(ø,arguments), smgs, + or_queue = ARRAY_SLICE.call(internals("or_queue")) + ; + + if (msgs.length === 1) { + msgs = msgs[0]; + } + + ignore_success_handler = true; + + // NOTE: if this call throws, that'll automatically + // be handled by core as we'd want it to be + ret = failure(msgs); + + // if we get this far: + // first, inject return value (if any) as + // next step's sequence messages + smgs = internals("sequence_messages"); + smgs.length = 0; + if (typeof ret !== "undefined") { + if (!ASQ.isMessageWrapper(ret)) { + ret = [ret]; + } + smgs.push.apply(smgs,ret); + } + + // reset internal error state, because we've exclusively + // handled any errors up to this point of the sequence + internals("sequence_errors").length = 0; + internals("seq_error",false); + internals("then_ready",true); + + // temporarily empty the or-queue + internals("or_queue").length = 0; + + // make sure to schedule success-procession on the chain + api.val(function $$val(){ + // pass thru messages + return ASQ.messages.apply(ø,arguments); + }); + + // at next cycle, reinstate the or-queue (if any) + if (or_queue.length > 0) { + schedule(function $$schedule(){ + api.or.apply(ø,or_queue); + }); + } + } + }); + } + return api; + }; +}); + +// "pCatch" +ASQ.extend("pCatch",function $$extend(api,internals){ + return function $$pcatch(failure) { + if (internals("seq_aborted")) { + return api; + } + + api.pThen(void 0,failure); + + return api; + }; +}); +// "race" +ASQ.extend("race",function $$extend(api,internals){ + return function $$race() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(v){ + var def; + // tap any directly-provided sequences immediately + if (ASQ.isSequence(v)) { + def = { seq: v }; + tapSequence(def); + return function $$fn(done) { + def.seq.pipe(done); + }; + } + else return v; + }); + + api.then(function $$then(done){ + var args = ARRAY_SLICE.call(arguments); + + fns.forEach(function $$each(fn){ + fn.apply(ø,args); + }); + }); + + return api; + }; +}); +// "react" (reactive sequences) +ASQ.react = function $$react(reactor) { + function next() { + if (!paused) { + if (template) { + var sq = template.duplicate(); + sq.unpause.apply(ø,arguments); + return sq; + } + return ASQ(function $$asq(){ throw "Disabled Sequence"; }); + } + } + + function registerTeardown(fn) { + if (template && typeof fn === "function") { + teardowns.push(fn); + } + } + + var template = ASQ().duplicate(), + teardowns = [], paused = false + ; + + // add reactive sequence kill switch + template.stop = function $$stop() { + if (template) { + template = null; + teardowns.forEach(Function.call,Function.call); + teardowns.length = 0; + } + }; + + template.pause = function $$pause() { + if (!paused && template) { + paused = true; + teardowns.forEach(Function.call,Function.call); + teardowns.length = 0; + } + }; + + template.resume = function $$resume() { + if (paused && template) { + paused = false; + reactor.call(template,next,registerTeardown); + } + }; + + template.push = next; + + next.onStream = function $$onStream() { + ARRAY_SLICE.call(arguments) + .forEach(function $$each(stream){ + stream.on("data",next); + stream.on("error",next); + }); + }; + + next.unStream = function $$unStream() { + ARRAY_SLICE.call(arguments) + .forEach(function $$each(stream){ + stream.removeListener("data",next); + stream.removeListener("error",next); + }); + }; + + // make sure `reactor(..)` is called async + ASQ.__schedule(function $$schedule(){ + reactor.call(template,next,registerTeardown); + }); + + return template; +}; +// "react" helpers +(function IIFE(){ + + var Ar = ASQ.react; + + Ar.of = function $$react$of() { + function reactor(next) { + if (!started) { + started = true; + if (args.length > 0) { + args.shift().val(function val(){ + next.apply(ø,arguments); + if (args.length > 0) { + args.shift().val(val); + } + }); + } + } + } + + var started, args = ARRAY_SLICE.call(arguments) + .map(function wrapper(arg){ + if (!ASQ.isSequence(arg)) arg = ASQ(arg); + return arg; + }); + + return Ar(reactor); + }; + + Ar.all = Ar.zip = makeReactOperator(/*buffer=*/true); + Ar.allLatest = makeReactOperator(/*buffer=false*/); + Ar.latest = Ar.combineLatest = makeReactOperator(/*buffer=*/false,/*keep=*/true); + + Ar.any = Ar.merge = function $$react$any(){ + function reactor(next,registerTeardown){ + function processSequence(def){ + function trigger(){ + var args = ASQ.messages.apply(ø,arguments); + // still observing sequence-streams? + if (seqs && seqs.length > 0) { + // fire off reactive sequence instance + next.apply(ø,args); + } + // keep sequence going + return args; + } + + // sequence-stream event listener + def.seq.val(trigger); + } + + // observe all sequence-streams + seqs.forEach(processSequence); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + seqs = null; + }); + } + + // observe all sequence-streams + var seqs = tapSequences.apply(null,arguments); + + if (seqs.length == 0) return; + + return Ar(reactor); + }; + + Ar.distinct = function $$react$distinct(seq){ + return Ar.filter(seq,makeDistinctFilterer(/*keepAll=*/true)); + }; + + Ar.distinctConsecutive = Ar.distinctUntilChanged = function $$react$distinct$consecutive(seq) { + return Ar.filter(seq,makeDistinctFilterer(/*keepAll=*/false)); + }; + + Ar.filter = function $$react$filter(seq,filterer){ + function reactor(next,registerTeardown) { + function trigger(){ + var messages = ASQ.messages.apply(ø,arguments); + + if (filterer && filterer.apply(ø,messages)) { + // fire off reactive sequence instance + next.apply(ø,messages); + } + + // keep sequence going + return messages; + } + + // sequence-stream event listener + def.seq.val(trigger); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + def = filterer = null; + }); + } + + // observe sequence-stream + var def = tapSequences(seq)[0]; + + if (!def) return; + + return Ar(reactor); + }; + + Ar.fromObservable = function $$react$from$observable(obsv){ + function reactor(next,registerTeardown){ + // process buffer (if any) + buffer.forEach(next); + buffer.length = 0; + + // start non-buffered notifications? + if (!buffer.complete) { + notify = next; + } + + registerTeardown(function $$teardown(){ + obsv.dispose(); + }); + } + + function notify(v) { + buffer.push(v); + } + + var buffer = []; + + obsv.subscribe( + function $$on$next(v){ + notify(v); + }, + function $$on$error(){}, + function $$on$complete(){ + buffer.complete = true; + obsv.dispose(); + } + ); + + return Ar(reactor); + }; + + ASQ.extend("toObservable",function $$extend(api,internals){ + return function $$to$observable(){ + function init(observer) { + function define(pair){ + function listen(){ + var args = ASQ.messages.apply(ø,arguments); + observer[pair[1]].apply(observer, + args.length == 1 ? [args[0]] : args + ); + return args; + } + + api[pair[0]](listen); + } + + [["val","onNext"],["or","onError"]] + .forEach(define); + } + + return Rx.Observable.create(init); + }; + }); + + function tapSequences() { + function tapSequence(seq) { + // temporary `trigger` which, if called before being replaced + // below, creates replacement proxy sequence with the + // event message(s) re-fired + function trigger() { + var args = ARRAY_SLICE.call(arguments); + def.seq = Ar(function $$react(next){ + next.apply(ø,args); + }); + } + + if (ASQ.isSequence(seq)) { + var def = { seq: seq }; + + // listen for events from the sequence-stream + seq.val(function $$val(){ + trigger.apply(ø,arguments); + return ASQ.messages.apply(ø,arguments); + }); + + // make a reactive sequence to act as a proxy to the original + // sequence + def.seq = Ar(function $$react(next){ + // replace the temporary trigger (created above) + // with this proxy's trigger + trigger = next; + }); + + return def; + } + } + + return ARRAY_SLICE.call(arguments) + .map(tapSequence) + .filter(Boolean); + } + + function makeReactOperator(buffer,keep) { + return function $$react$operator(){ + function reactor(next,registerTeardown){ + function processSequence(def) { + // sequence-stream event listener + function trigger() { + var args = ASQ.messages.apply(ø,arguments); + // still observing sequence-streams? + if (seqs && seqs.length > 0) { + // store event message(s), if any + seq_events[seq_id] = + (buffer ? seq_events[seq_id] : []).concat( + args.length > 0 ? (args.length > 1 ? [args] : args[0]) : undefined + ); + + // collect event message(s) across the + // sequence-stream sources + var messages = seq_events.reduce(function reducer(msgs,eventList,idx){ + if (eventList.length > 0) msgs.push(eventList[0]); + return msgs; + },[]); + + // did all sequence-streams get an event? + if (messages.length == seq_events.length) { + if (messages.length == 1) messages = messages[0]; + + // fire off reactive sequence instance + next.apply(ø,messages); + + // discard stored event message(s)? + if (!keep) { + seq_events.forEach(function $$each(eventList){ + eventList.shift(); + }); + } + } + } + // keep sequence going + return args; + } + + var seq_id = seq_events.length; + seq_events.push([]); + def.seq.val(trigger); + } + + // process all sequence-streams + seqs.forEach(processSequence); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + seqs = seq_events = null; + }); + } + + var seq_events = [], + // observe all sequence-streams + seqs = tapSequences.apply(null,arguments) + ; + + if (seqs.length == 0) return; + + return Ar(reactor); + }; + } + + function makeDistinctFilterer(keepAll) { + function filterer() { + function isDuplicate(msgSet) { + return ( + msgSet.length == message_set.length && + msgSet.every(function $$every(val,idx){ + return val === message_set[idx]; + }) + ); + } + + var message_set = ASQ.messages.apply(ø,arguments); + + // any messages in message-set to check against? + if (message_set.length > 0) { + // duplicate message-set? + if (msg_sets.some(isDuplicate)) { + return false; + } + + // remember all message-sets for future distinct checking? + if (keepAll) { + msg_sets.push(message_set); + } + // only keep the last message-set for distinct-consecutive + // checking + else { + msg_sets[0] = message_set; + } + } + + // allow distinct non-duplicate value through + return true; + } + + var msg_sets = []; + + return filterer; + } + +})(); +// "runner" +ASQ.extend("runner",function $$extend(api,internals){ + + return function $$runner() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var args = ARRAY_SLICE.call(arguments); + + api + .then(function $$then(mainDone){ + + function wrap(v) { + // function? expected to produce an iterator + // (like a generator) or a promise + if (typeof v === "function") { + // call function passing in the control token + // note: neutralize `this` in call to prevent + // unexpected behavior + v = v.call(ø,token); + + // promise returned (ie, from async function)? + if (isPromise(v)) { + // wrap it in iterable sequence + v = ASQ.iterable(v); + } + } + // an iterable sequence? duplicate it (in case of multiple runs) + else if (ASQ.isSequence(v) && "next" in v) { + v = v.duplicate(); + } + // wrap anything else in iterable sequence + else { + v = ASQ.iterable(v); + } + + // a sequence to tap for errors? + if (ASQ.isSequence(v)) { + // listen for any sequence failures + v.or(function $$or(){ + // signal iteration-error + mainDone.fail.apply(ø,arguments); + }); + } + + return v; + } + + function addWrapped() { + iterators.push.apply( + iterators, + ARRAY_SLICE.call(arguments).map(wrap) + ); + } + + function iterateOrQuit(iterFn,now) { + // still have some co-routine runs to process? + if (iterators.length > 0) { + if (now) iterFn(); + else schedule(iterFn); + } + // all done! + else { + // previous value message? + if (typeof next_val !== "undefined") { + // not a message wrapper array? + if (!ASQ.isMessageWrapper(next_val)) { + // wrap value for the subsequent `apply(..)` + next_val = [next_val]; + } + } + else { + // nothing to affirmatively pass along + next_val = []; + } + + // signal done with all co-routine runs + mainDone.apply(ø,next_val); + } + } + + var iterators = args, + token = { + messages: ARRAY_SLICE.call(arguments,1), + add: addWrapped + }, + iter, ret, next_val = token + ; + + // map co-routines to round-robin list of iterators + iterators = iterators.map(wrap); + + // async iteration of round-robin list + (function iterate(){ + // get next co-routine in list + iter = iterators.shift(); + + // process the iteration + try { + // multiple messages to send to an iterable + // sequence? + if (ASQ.isMessageWrapper(next_val) && + ASQ.isSequence(iter) + ) { + ret = iter.next.apply(iter,next_val); + } + else { + ret = iter.next(next_val); + } + } + catch (err) { + return mainDone.fail(err); + } + + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + // was the control token yielded? + if (ret.value === token) { + // round-robin: put co-routine back into the list + // at the end where it was so it can be processed + // again on next loop-iteration + if (!ret.done) { + iterators.push(iter); + } + next_val = token; + iterateOrQuit(iterate,/*now=*/false); + } + else { + // not a recognized ASQ instance returned? + if (!ASQ.isSequence(ret.value)) { + // received a thenable/promise back? + if (isPromise(ret.value)) { + // wrap in a sequence + ret.value = ASQ().promise(ret.value); + } + // thunk yielded? + else if (typeof ret.value === "function") { + // wrap thunk call in a sequence + var fn = ret.value; + ret.value = ASQ(function $$ASQ(done){ + fn(done.errfcb); + }); + } + // message wrapper returned? + else if (ASQ.isMessageWrapper(ret.value)) { + // wrap message(s) in a sequence + ret.value = ASQ.apply(ø, + // don't let `apply(..)` discard an empty message + // wrapper! instead, pass it along as its own value + // itself. + ret.value.length > 0 ? ret.value : ASQ.messages(undefined) + ); + } + // non-undefined value returned? + else if (typeof ret.value !== "undefined") { + // wrap the value in a sequence + ret.value = ASQ(ret.value); + } + else { + // make an empty sequence + ret.value = ASQ(); + } + } + + ret.value + .val(function $$val(){ + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + if (arguments.length > 0) { + // save any return messages for input + // to next iteration + next_val = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + } + + // still more to iterate? + if (!ret.done) { + // was the control token passed along? + if (next_val === token) { + // round-robin: put co-routine back into the list + // at the end, so that the the next iterator can be + // processed on next loop-iteration + iterators.push(iter); + } + else { + // put co-routine back in where it just + // was so it can be processed again on + // next loop-iteration + iterators.unshift(iter); + } + } + + iterateOrQuit(iterate,/*now=*/true); + }) + .or(function $$or(){ + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + try { + // if an error occurs in the step-continuation + // promise or sequence, throw it back into the + // generator or iterable-sequence + iter["throw"].apply(iter,arguments); + } + catch (err) { + // if an error comes back out of after the throw, + // pass it out to the main sequence, as iteration + // must now be complete + mainDone.fail(err); + } + }); + } + })(); + }); + + return api; + }; +}); +// "toPromise" +ASQ.extend("toPromise",function $$extend(api,internals){ + return function $$to$promise() { + return new Promise(function $$executor(resolve,reject){ + api + .val(function $$val(){ + var args = ARRAY_SLICE.call(arguments); + resolve.call(ø,args.length > 1 ? args : args[0]); + return ASQ.messages.apply(ø,args); + }) + .or(function $$or(){ + var args = ARRAY_SLICE.call(arguments); + reject.call(ø,args.length > 1 ? args : args[0]); + }); + }); + }; +}); +// "try" +ASQ.extend("try",function $$extend(api,internals){ + return function $$try() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(fn){ + return function $$then(mainDone) { + var main_args = ARRAY_SLICE.call(arguments), + sq = ASQ.apply(ø,main_args.slice(1)) + ; + + sq + .then(function $$inner$then(){ + fn.apply(ø,arguments); + }) + .val(function $$val(){ + mainDone.apply(ø,arguments); + }) + .or(function $$inner$or(){ + var msgs = ASQ.messages.apply(ø,arguments); + // failed, so map error(s) as `catch` + mainDone({ + "catch": msgs.length > 1 ? msgs : msgs[0] + }); + }); + }; + }); + + api.then.apply(ø,fns); + + return api; + }; +}); +// "until" +ASQ.extend("until",function $$extend(api,internals){ + return function $$until() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(fn){ + return function $$then(mainDone) { + var main_args = ARRAY_SLICE.call(arguments), + sq = ASQ.apply(ø,main_args.slice(1)) + ; + + sq + .then(function $$inner$then(){ + var args = ARRAY_SLICE.call(arguments); + args[0]["break"] = function $$break(){ + mainDone.fail.apply(ø,arguments); + sq.abort(); + }; + + fn.apply(ø,args); + }) + .val(function $$val(){ + mainDone.apply(ø,arguments); + }) + .or(function $$inner$or(){ + // failed, retry + $$then.apply(ø,main_args); + }); + }; + }); + + api.then.apply(ø,fns); + + return api; + }; +}); +// "waterfall" +ASQ.extend("waterfall",function $$extend(api,internals){ + return function $$waterfall() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + var msgs = ASQ.messages(), + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + fns.forEach(function $$each(fn){ + sq.then(fn) + .val(function $$val(){ + var args = ASQ.messages.apply(ø,arguments); + msgs.push(args.length > 1 ? args : args[0]); + return msgs; + }); + }); + + sq.pipe(done); + }); + + return api; + }; +}); +// "wrap" +ASQ.wrap = function $$wrap(fn,opts) { + function checkThis(t,o) { + return (!t || + (typeof window != "undefined" && t === window) || + (typeof global != "undefined" && t === global) + ) ? o : t; + } + + function paramSpread(gen) { + return function *paramSpread(token) { + yield *gen.apply(this,token.messages); + }; + } + + var errfcb, params_first, act, this_obj; + + opts = (opts && typeof opts == "object") ? opts : {}; + + if ( + (opts.errfcb && opts.splitcb) || + (opts.errfcb && opts.simplecb) || + (opts.splitcb && opts.simplecb) || + ("errfcb" in opts && !opts.errfcb && !opts.splitcb && !opts.simplecb) || + (opts.params_first && opts.params_last) || + (opts.spread && !opts.gen) + ) { + throw Error("Invalid options"); + } + + // initialize default flags + this_obj = (opts["this"] && typeof opts["this"] == "object") ? opts["this"] : ø; + errfcb = opts.errfcb || !(opts.splitcb || opts.simplecb); + params_first = !!opts.params_first || + (!opts.params_last && !("params_first" in opts || opts.params_first)) || + ("params_last" in opts && !opts.params_first && !opts.params_last) + ; + + if (params_first) { + act = "push"; + } + else { + act = "unshift"; + } + + if (opts.gen) { + if (opts.spread) { + fn = paramSpread(fn); + } + return function $$wrapped$gen() { + return ASQ.apply(ø,arguments).runner(fn); + }; + } + if (errfcb) { + return function $$wrapped$errfcb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done.errfcb); + fn.apply(_this,args); + }); + }; + } + if (opts.splitcb) { + return function $$wrapped$splitcb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done,done.fail); + fn.apply(_this,args); + }); + }; + } + if (opts.simplecb) { + return function $$wrapped$simplecb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done); + fn.apply(_this,args); + }); + }; + } +}; + + + // just return `ASQ` itself for convenience sake + return ASQ; +}); diff --git a/frontend-masters-exercises/exercises/ex8/ex8-fixed.html b/frontend-masters-exercises/exercises/ex8/ex8-fixed.html new file mode 100755 index 0000000..be423fb --- /dev/null +++ b/frontend-masters-exercises/exercises/ex8/ex8-fixed.html @@ -0,0 +1,18 @@ + + + + +Exercise 8 - Fixed + + +

Exercise 8 - Fixed

+ +

+
+ + + + + + + diff --git a/frontend-masters-exercises/exercises/ex8/ex8-fixed.js b/frontend-masters-exercises/exercises/ex8/ex8-fixed.js new file mode 100755 index 0000000..5ef75cd --- /dev/null +++ b/frontend-masters-exercises/exercises/ex8/ex8-fixed.js @@ -0,0 +1,30 @@ +$(document).ready(function(){ + var $btn = $("#btn"), + $list = $("#list"), + clicks = ASQ.react.of(), + msgs = ASQ.react.of(), + latest; + + $btn.click(function(evt){ + // push click event messages into stream + clicks.push(evt); + }); + + // sample clicks stream + setInterval(function(){ + if (latest) { + msgs.push("clicked!"); + latest = null; + } + },1000); + + // subscribe to click stream + clicks.val(function(evt){ + latest = evt; + }); + + // subscribe to sampled message stream + msgs.val(function(msg){ + $list.append($("
" + msg + "
")); + }); +}); diff --git a/frontend-masters-exercises/exercises/ex8/ex8.html b/frontend-masters-exercises/exercises/ex8/ex8.html new file mode 100755 index 0000000..55b403a --- /dev/null +++ b/frontend-masters-exercises/exercises/ex8/ex8.html @@ -0,0 +1,18 @@ + + + + +Exercise 8 + + +

Exercise 8

+ +

+
+ + + + + + + diff --git a/frontend-masters-exercises/exercises/ex8/ex8.js b/frontend-masters-exercises/exercises/ex8/ex8.js new file mode 100755 index 0000000..3335f25 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex8/ex8.js @@ -0,0 +1,10 @@ +$(document).ready(function(){ + var $btn = $("#btn"), + $list = $("#list"); + + $btn.click(function(evt){ + // TODO + }); + + // TODO: setup sampled sequence, populate $list +}); diff --git a/frontend-masters-exercises/exercises/ex8/jquery.js b/frontend-masters-exercises/exercises/ex8/jquery.js new file mode 100755 index 0000000..3883779 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex8/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v1.8.3 jquery.com | jquery.org/license */ +(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write(""),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t
a",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="
t
",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="
",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;ti.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="
",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="

",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t0)for(i=r;i=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*\s*$/g,Nt={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X
","
"]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1>");try{for(;r1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]===""&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("
").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window); \ No newline at end of file diff --git a/frontend-masters-exercises/exercises/ex9/README.md b/frontend-masters-exercises/exercises/ex9/README.md new file mode 100755 index 0000000..33c7284 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex9/README.md @@ -0,0 +1,9 @@ +# Instructions + +1. In this exercise, we're going to practice with CSP channel concurrency using asynquence. + +2. Monitor the stream of click events from the button and publish them to a channel if the channel is ready for a message. Hint: `ASQ.csp.putAsync(..)`, which returns a promise + +3. Set up go-routine that samples the channel from (2) once per second. In other words, if you click the button multiple times in a second, you only get one channel message. Hint: `ASQ.csp.take( ASQ.csp.timeout(..) )` + +4. The sampled channel go-routine should add a "clicked!" message to the list. diff --git a/frontend-masters-exercises/exercises/ex9/asq.bundle-es5.js b/frontend-masters-exercises/exercises/ex9/asq.bundle-es5.js new file mode 100755 index 0000000..08c503a --- /dev/null +++ b/frontend-masters-exercises/exercises/ex9/asq.bundle-es5.js @@ -0,0 +1,10 @@ +/*! asynquence + v0.8.2 (c) Kyle Simpson + MIT License: http://getify.mit-license.org +*/ +!function UMD(e,n,t){"function"==typeof define&&define.amd?define(t):"undefined"!=typeof module&&module.exports?module.exports=t():n[e]=t(e,n)}("ASQ",this,function DEF(e,n){"use strict";function Queue(){function Item(e){this.fn=e,this.next=void 0}var e,n,r;return{add:function $$add(t){r=new Item(t),n?n.next=r:e=r,n=r,r=void 0},drain:function $$drain(){var r=e;for(e=n=t=null;r;)r.fn(),r=r.next}}}function schedule(e){r.add(e),t||(t=u(r.drain))}function tapSequence(e){function trigger(){e.seq=createSequence.apply(h,arguments).defer()}trigger.fail=function $$trigger$fail(){var n=f.call(arguments);e.seq=createSequence(function $$create$sequence(e){e.fail.apply(h,n)}).defer()},e.seq.val(function $$val(){return trigger.apply(h,arguments),c.apply(h,arguments)}).or(function $$or(){trigger.fail.apply(h,arguments)}),e.seq=createSequence(function $$create$sequence(e){trigger=e}).defer()}function createSequence(){function scheduleSequenceTick(){r?sequenceTick():e||(e=schedule(sequenceTick))}function throwSequenceErrors(){throw 1===$.length?$[0]:$}function sequenceTick(){var a,c;if(e=null,delete d.unpause,r)clearTimeout(e),e=null,s.length=p.length=g.length=$.length=0;else if(n)for(0!==p.length||t||(t=!0,throwSequenceErrors());p.length;){t=!0,a=p.shift();try{a.apply(h,$)}catch(i){l(i)?$=$.concat(i):($.push(i),i.stack&&$.push(i.stack)),0===p.length&&throwSequenceErrors()}}else if(u&&s.length>0){u=!1,a=s.shift(),c=g.slice(),g.length=0,c.unshift(createStepCompletion());try{a.apply(h,c)}catch(i){l(i)?$=$.concat(i):$.push(i),n=!0,scheduleSequenceTick()}}}function createStepCompletion(){function done(){n||r||u||(u=!0,g.push.apply(g,arguments),$.length=0,scheduleSequenceTick())}return done.fail=function $$step$fail(){n||r||u||(n=!0,g.length=0,$.push.apply($,arguments),scheduleSequenceTick())},done.abort=function $$step$abort(){n||r||(u=!1,r=!0,g.length=$.length=0,scheduleSequenceTick())},done.errfcb=function $$step$errfcb(e){e?done.fail(e):done.apply(h,f.call(arguments,1))},done}function createGate(e,t,u){function resetGate(){clearTimeout(s),s=d=m=o=null}function scheduleGateTick(){return g?gateTick():void(s||(s=schedule(gateTick)))}function gateTick(){if(!(n||r||$)){var t=[];s=null,p?(e.fail.apply(h,o),resetGate()):g?(e.abort(),resetGate()):checkGate()&&($=!0,d.forEach(function $$each(e,n){t.push(m["s"+n])}),e.apply(h,t),resetGate())}}function checkGate(){if(0!==d.length){var e=!0;return d.some(function $$some(n){return null===n?(e=!1,!0):void 0}),e}}function createSegmentCompletion(){function done(){if(!(n||r||p||g||$||d[e])){var t=c.apply(h,arguments);m["s"+e]=t.length>1?t:t[0],d[e]=!0,scheduleGateTick()}}var e=d.length;return done.fail=function $$segment$fail(){n||r||p||g||$||d[e]||(p=!0,o=f.call(arguments),scheduleGateTick())},done.abort=function $$segment$abort(){n||r||p||g||$||(g=!0,gateTick())},done.errfcb=function $$segment$errfcb(e){e?done.fail(e):done.apply(h,f.call(arguments,1))},d[e]=null,done}var a,i,o,s,p=!1,g=!1,$=!1,d=[],m={};t.some(function $$some(e){if(p||g)return!0;a=u.slice(),a.unshift(createSegmentCompletion());try{e.apply(h,a)}catch(n){return i=n,p=!0,!0}}),i&&(l(i)?e.fail.apply(h,i):e.fail(i))}function then(){return n||r||0===arguments.length?d:(wrapArgs(arguments,thenWrapper).forEach(function $$each(e){i(e)?seq(e):s.push(e)}),scheduleSequenceTick(),d)}function or(){return r||0===arguments.length?d:(p.push.apply(p,arguments),scheduleSequenceTick(),d)}function gate(){if(n||r||0===arguments.length)return d;var e=f.call(arguments).map(function $$map(e){var n;return i(e)?(n={seq:e},tapSequence(n),function $$segment(e){n.seq.pipe(e)}):e});return then(function $$then(n){var t=f.call(arguments,1);createGate(n,e,t)}),d}function pipe(){return r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){then(function $$then(n){e.apply(h,f.call(arguments,1)),n()}).or(e.fail)}),d)}function seq(){return n||r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){var n={seq:e};i(e)&&tapSequence(n),then(function $$then(e){var t=n.seq;i(t)||(t=n.seq.apply(h,f.call(arguments,1))),t.pipe(e)})}),d)}function val(){return n||r||0===arguments.length?d:(f.call(wrapArgs(arguments,valWrapper)).forEach(function $$each(e){then(function $$then(n){var t=e.apply(h,f.call(arguments,1));l(t)||(t=c(t)),n.apply(h,t)})}),d)}function promise(){function wrap(e){return function $$fn(){e.apply(h,l(arguments[0])?arguments[0]:arguments)}}return n||r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){then(function $$then(n){var t=e;"function"==typeof e&&"function"!=typeof e.then&&(t=e.apply(h,f.call(arguments,1))),t.then(wrap(n),wrap(n.fail))})}),d)}function fork(){var e;return val(function $$val(){return e?e.apply(h,arguments):e=createSequence.apply(h,arguments).defer(),c.apply(h,arguments)}),or(function $$or(){if(e)e.fail.apply(h,arguments);else{var n=f.call(arguments);e=createSequence().then(function $$then(e){e.fail.apply(h,n)}).defer()}}),createSequence().then(function $$then(n){e?e.pipe(n):e=n}).defer()}function abort(){return n?d:(r=!0,sequenceTick(),d)}function duplicate(){var e;return a={then_queue:s.slice(),or_queue:p.slice()},e=createSequence(),a=null,e}function unpause(){g.push.apply(g,arguments),e===!0&&(e=null),scheduleSequenceTick()}function defer(){return p.push(function ignored(){}),d}function internals(e,t){var a=arguments.length>1;switch(e){case"seq_error":if(!a)return n;n=t;break;case"seq_aborted":if(!a)return r;r=t;break;case"then_ready":if(!a)return u;u=t;break;case"then_queue":return s;case"or_queue":return p;case"sequence_messages":return g;case"sequence_errors":return $}}function includeExtensions(){Object.keys(o).forEach(function $$each(e){d[e]=o[e](d,internals)})}var e,n=!1,t=!1,r=!1,u=!0,s=[],p=[],g=[],$=[],d=brandIt({then:then,or:or,onerror:or,gate:gate,all:gate,pipe:pipe,seq:seq,val:val,promise:promise,fork:fork,abort:abort,duplicate:duplicate,defer:defer});return includeExtensions(),a&&(s=a.then_queue.slice(),p=a.or_queue.slice(),d.unpause=unpause,e=!0),d.then.apply(h,arguments),d}function brandIt(e){return Object.defineProperty(e,p,{enumerable:!1,value:!0})}function checkBranding(e){return!(null==e||"object"!=typeof e||!e[p])}function valWrapper(e){return c.apply(h,f.call(arguments).slice(1,e+1))}function thenWrapper(e){arguments[e+1].apply(h,f.call(arguments).slice(1,e+1))}function wrapArgs(e,n){var t,r;for(e=f.call(e),t=0;t1?n.call(arguments,1):void 0;return r=+r||0,e.then(function $$then(e){var u=a||n.call(arguments,1);setTimeout(function $$set$timeout(){e.apply(t,u)},r)}),e}}),e.after=function $$after(){return e().after.apply(t,arguments)},e.extend("any",function $$extend(r,a){return function $$any(){if(a("seq_error")||a("seq_aborted")||0===arguments.length)return r;var u=n.call(arguments);return r.then(function $$then(r){function reset(){c=!0,l.length=0,s.length=0}function complete(e){s.length>0?(s.length=u.length,e.apply(t,s)):(l.length=u.length,e.fail.apply(t,l)),reset()}function success(n,r,l){c||(a++,s[r]=l.length>1?e.messages.apply(t,l):l[0],a===u.length&&(c=!0,complete(n)))}function failure(n,r,s){c||r in l||(a++,l[r]=s.length>1?e.messages.apply(t,s):s[0]),c||a!==u.length||(c=!0,complete(n))}var a=0,l=[],c=!1,s=[],o=e.apply(t,n.call(arguments,1));wrapGate(o,u,success,failure,reset),o.pipe(r)}),r}}),e.extend("errfcb",function $$extend(e,a){return function $$errfcb(){var a={val:function $$then(e){return a.val_cb=e,a},or:function $$or(e){return a.or_cb=e,a}};return a[r]=!0,e.seq(a),function $$errorfirst$callback(e){e?a.or_cb(e):a.val_cb.apply(t,n.call(arguments,1))}}}),e.extend("failAfter",function $$extend(e,r){return function $$failAfter(r){var a=arguments.length>1?n.call(arguments,1):void 0;return r=+r||0,e.then(function $$then(e){setTimeout(function $$set$timeout(){e.fail.apply(t,a)},r)}),e}}),e.failAfter=function $$fail$after(){return e().failAfter.apply(t,arguments)},e.extend("first",function $$extend(r,a){return function $$first(){if(a("seq_error")||a("seq_aborted")||0===arguments.length)return r;var u=n.call(arguments);return r.then(function $$then(r){function reset(){l.length=0}function success(n,r,a){c||(c=!0,n(a.length>1?e.messages.apply(t,a):a[0]),reset())}function failure(n,r,s){c||r in l||(a++,l[r]=s.length>1?e.messages.apply(t,s):s[0],a===u.length&&(c=!0,l.length=u.length,n.fail.apply(t,l),reset()))}var a=0,l=[],c=!1,s=e.apply(t,n.call(arguments,1));wrapGate(s,u,success,failure,reset),s.pipe(r)}),r}}),function IIFE(){function filterResolved(e){return e.filter(function $$filter(e){return!e.resolved})}function closeQueue(e,n){e.forEach(function $$each(e){e.resolved||(e.next(),e.next(n))}),e.length=0}function channel(n){var t={close:function $$close(){t.closed=!0,closeQueue(t.put_queue,!1),closeQueue(t.take_queue,e.csp.CLOSED)},closed:!1,messages:[],put_queue:[],take_queue:[],buffer_size:+n||0};return t}function unblock(e){e&&!e.resolved&&e.next(e.next().value)}function put(n,t){var r;return n.closed?!1:(n.put_queue=filterResolved(n.put_queue),n.take_queue=filterResolved(n.take_queue),n.messages.length0&&(unblock(n.put_queue.shift()),unblock(n.take_queue.shift())),r))}function putAsync(n,t,r){var a=e(put(n,t));return r&&"function"==typeof r?void a.val(r):a}function take(n){var t;try{t=takem(n)}catch(r){t=r}return e.isSequence(t)&&t.pCatch(function $$pcatch(e){return e}),t}function takeAsync(n,t){var r=e(take(n));return t&&"function"==typeof t?void r.val(t):r}function takem(n){var t;if(n.closed)return e.csp.CLOSED;if(n.put_queue=filterResolved(n.put_queue),n.take_queue=filterResolved(n.take_queue),n.messages.length>0){if(t=n.messages.shift(),unblock(n.put_queue.shift()),t instanceof Error)throw t;return t}return n.take_queue.push(e.iterable().then(function $$then(){if(n.closed)return e.csp.CLOSED;var t=n.messages.shift();if(t instanceof Error)throw t;return t})),t=e(n.take_queue[n.take_queue.length-1]),n.put_queue.length>0&&(unblock(n.put_queue.shift()),unblock(n.take_queue.shift())),t}function takemAsync(n,t){var r=e(takem(n));return t&&"function"==typeof t?void r.pThen(t,t):r.val(function $$val(e){if(e instanceof Error)throw e;return e})}function alts(n){var t,r,u,l,c,s,o=!1;if(!Array.isArray(n)||0==n.length)throw Error("Invalid usage");if(t=[],r=[],u=[],n.forEach(function $$each(e){var n=Array.isArray(e)?e[0]:e;n.put_queue=filterResolved(n.put_queue),n.take_queue=filterResolved(n.take_queue),n.closed?t.push(n):r.push(e)}),0==r.length)return{value:e.csp.CLOSED,channel:t};for(l=0;l0)return{value:take(r[l]),channel:r[l]};c=e.iterable();var s=e(c);for(l=0;l0&&a(function handleUnblocking(){o||(unblock(t.put_queue.shift()),unblock(t.take_queue.shift()))},0)):(t=n,u.push(e.iterable().then(function $$then(){o=!0,u=u.filter(function $$filter(e){return!(e.resolved=!0)}),t.closed?c.next({value:e.csp.CLOSED,channel:t}):c.next({value:t.messages.shift(),channel:t})})),t.take_queue.push(u[u.length-1]),t.put_queue.length>0&&a(function handleUnblocking(){o||(unblock(t.put_queue.shift()),unblock(t.take_queue.shift()))}))}(r[l]);return s}function altsAsync(n,t){var r=e(alts(n));return t&&"function"==typeof t?void r.pThen(t,t):r}function timeout(e){var n=channel();return setTimeout(n.close,e),n}function go(n,r){return arguments.length>1?r&&Array.isArray(r)||(r=[r]):r=[],regeneratorRuntime.mark(function $$go(a){var u,l,c,s,o,i,f;return regeneratorRuntime.wrap(function $$go$(p){for(;;)switch(p.prev=p.next){case 0:u=function unblock(){a.unblock_count++,a.block&&!a.block.marked&&(a.block.marked=!0,a.block.next())},i=!1,a.unblock_count=a.unblock_count||0,a.go_count=(a.go_count||0)+1,1===a.go_count&&(a.channel=channel(),a.channel.messages=a.messages,a.channel.go=function $$go(){u(),a.add(go.apply(t,arguments))},a.channel.messages.length>0&&(a.channel.put_queue=a.channel.messages.map(function $$map(){return e.iterable().then(function $$then(){return u(a.channel.take_queue.shift()),!a.channel.closed})}))),f=n.apply(t,[a.channel].concat(r)),function iterate(){function next(){i?u():iterate()}if(!l){try{s?(l=f["throw"](s),s=null):l=f.next(c)}catch(n){return i=!0,s=n,c=null,void u()}i=l.done,l=l.value,o=typeof l,i&&u(),isPromise(l)&&(l=e().promise(l)),e.isSequence(l)?l.val(function $$val(){l=null,c=arguments.length>1?e.messages.apply(t,arguments):arguments[0],next()}).or(function $$or(){l=null,c=arguments.length>1?e.messages.apply(t,arguments):arguments[0],c instanceof Error&&(s=c,c=null),next()}):(c=l,l=null,next())}}();case 7:if(i){p.next=17;break}return p.next=10,a;case 10:if(i||a.block||0!==a.unblock_count){p.next=14;break}return p.next=13,a.block=e.iterable();case 13:a.block=!1;case 14:a.unblock_count>0&&a.unblock_count--,p.next=7;break;case 17:if(a.go_count--,0===a.go_count&&(u(),c=e.messages.apply(t,a.messages),a.channel&&!a.channel.closed&&(a.channel.closed=!0,a.channel.put_queue.length=a.channel.take_queue.length=0,a.channel.close=a.channel.go=a.channel.messages=null),a.channel=null),!s){p.next=23;break}throw s;case 23:if(0!==a.go_count){p.next=27;break}return p.abrupt("return",c);case 27:return p.abrupt("return",a);case 28:case"end":return p.stop()}},$$go,this)})}e.csp={chan:channel,put:put,putAsync:putAsync,take:take,takeAsync:takeAsync,takem:takem,takemAsync:takemAsync,alts:alts,altsAsync:altsAsync,timeout:timeout,go:go,CLOSED:{}}}(),function IIFE(){var u;e.iterable=function $$iterable(){function throwSequenceErrors(){throw 1===$.length?$[0]:$}function notifyErrors(){var e;if(c=null,s)for(0!==p.length||o||(o=!0,throwSequenceErrors());p.length>0;){o=!0,e=p.shift();try{e.apply(t,$)}catch(n){checkBranding(n)?$=$.concat(n):$.push(n),0===p.length&&throwSequenceErrors()}}}function val(){if(s||i||0===arguments.length)return l;var e=n.call(arguments).map(function mapper(e){return"function"!=typeof e?function $$val(){return e}:e});return f.push.apply(f,e),l}function or(){return i||0===arguments.length?l:(p.push.apply(p,arguments),c||(c=a(notifyErrors)),l)}function pipe(){return i||0===arguments.length?l:(n.call(arguments).forEach(function $$each(e){val(e).or(e.fail)}),l)}function next(){if(s||i||0===f.length)return f.length>0&&$throw$("Sequence cannot be iterated"),{done:!0};try{return{value:f.shift().apply(t,arguments)}}catch(n){return e.isMessageWrapper(n)?$throw$.apply(t,n):$throw$(n),{}}}function $throw$(){return s||i?l:($.push.apply($,arguments),s=!0,c||(c=a(notifyErrors)),l)}function $return$(e){return(s||i)&&(e=void 0),abort(),{done:!0,value:e}}function abort(){s||i||(i=!0,clearTimeout(c),c=null,f.length=p.length=$.length=0)}function duplicate(){var n;return u={val_queue:f.slice(),or_queue:p.slice()},n=e.iterable(),u=null,n}function defer(){return p.push(function $$ignored(){}),l}function brandIt(e){return Object.defineProperty(e,r,{enumerable:!1,value:!0}),e}var l,c,s=!1,o=!1,i=!1,f=[],p=[],$=[];return l=brandIt({val:val,then:val,or:or,pipe:pipe,next:next,"throw":$throw$,"return":$return$,abort:abort,duplicate:duplicate,defer:defer}),l["function"==typeof Symbol&&Symbol.iterator||"@@iterator"]=function $$iter(){return l},u&&(f=u.val_queue.slice(0),p=u.or_queue.slice(0)),l.val.apply(t,arguments),l}}(),e.extend("last",function $$extend(r,a){return function $$last(){if(a("seq_error")||a("seq_aborted")||0===arguments.length)return r;var u=n.call(arguments);return r.then(function $$then(r){function reset(){s=!0,c.length=0,a=null}function complete(n){null!=a?n(a.length>1?e.messages.apply(t,a):a[0]):(c.length=u.length,n.fail.apply(t,c)),reset()}function success(e,n,t){s||(l++,a=t,l===u.length&&(s=!0,complete(e)))}function failure(n,r,a){s||r in c||(l++,c[r]=a.length>1?e.messages.apply(t,a):a[0]),s||l!==u.length||(s=!0,complete(n))}var a,l=0,c=[],s=!1,o=e.apply(t,n.call(arguments,1));wrapGate(o,u,success,failure,reset),o.pipe(r)}),r}}),e.extend("map",function $$extend(r,a){return function $$map(u,l){return a("seq_error")||a("seq_aborted")?r:(r.seq(function $$seq(){var r,a=n.call(arguments),c=u,s=l;return s||(s=a.shift()),c||(c=a.shift()),"function"==typeof c&&Array.isArray(s)&&(r=c,c=s,s=r),e.apply(t,a).gate.apply(t,c.map(function $$map(e){return function $$segment(){s.apply(t,[e].concat(n.call(arguments)))}}))}).val(function $$val(){return n.call(arguments)}),r)}}),e.extend("none",function $$extend(r,a){return function $$none(){if(a("seq_error")||a("seq_aborted")||0===arguments.length)return r;var u=n.call(arguments);return r.then(function $$then(r){function reset(){c=!0,l.length=0,o.length=0}function complete(e){o.length>0?(o.length=u.length,e.fail.apply(t,o)):(l.length=u.length,e.apply(t,l)),reset()}function success(n,r,l){c||(a++,o[r]=l.length>1?e.messages.apply(t,l):l[0],a===u.length&&(c=!0,complete(n)))}function failure(n,r,s){c||r in l||(a++,l[r]=s.length>1?e.messages.apply(t,s):s[0]),c||a!==u.length||(c=!0,complete(n))}var a=0,l=[],c=!1,s=e.apply(t,n.call(arguments,1)),o=[];wrapGate(s,u,success,failure,reset),s.pipe(r)}),r}}),e.extend("pThen",function $$extend(r,u){return function $$pthen(l,c){if(u("seq_aborted"))return r;var s=!1,o=!1;return"function"==typeof l&&r.then(function $$then(r){if(s)r.apply(t,n.call(arguments,1));else{var a,u=e.messages.apply(t,arguments);u.shift(),1===u.length&&(u=u[0]),o=!0;try{a=l(u)}catch(c){return e.isMessageWrapper(c)||(c=[c]),void r.fail.apply(t,c)}e.isSequence(a)?a.pipe(r):e.isMessageWrapper(a)?r.apply(t,a):isPromise(a)?a.then(r,r.fail):r(a)}}),"function"==typeof c&&r.or(function $$or(){if(!o){var l,i,f=e.messages.apply(t,arguments),p=n.call(u("or_queue"));1===f.length&&(f=f[0]),s=!0,l=c(f),i=u("sequence_messages"),i.length=0,"undefined"!=typeof l&&(e.isMessageWrapper(l)||(l=[l]),i.push.apply(i,l)),u("sequence_errors").length=0,u("seq_error",!1),u("then_ready",!0),u("or_queue").length=0,r.val(function $$val(){return e.messages.apply(t,arguments)}),p.length>0&&a(function $$schedule(){r.or.apply(t,p)})}}),r}}),e.extend("pCatch",function $$extend(e,n){return function $$pcatch(t){return n("seq_aborted")?e:(e.pThen(void 0,t),e)}}),e.extend("race",function $$extend(r,a){return function $$race(){if(a("seq_error")||a("seq_aborted")||0===arguments.length)return r;var l=n.call(arguments).map(function $$map(n){var t;return e.isSequence(n)?(t={seq:n},u(t),function $$fn(e){t.seq.pipe(e)}):n});return r.then(function $$then(e){var r=n.call(arguments);l.forEach(function $$each(e){e.apply(t,r)})}),r}}),e.react=function $$react(r){function next(){if(!l){if(a){var n=a.duplicate();return n.unpause.apply(t,arguments),n}return e(function $$asq(){throw"Disabled Sequence"})}}function registerTeardown(e){a&&"function"==typeof e&&u.push(e)}var a=e().duplicate(),u=[],l=!1;return a.stop=function $$stop(){a&&(a=null,u.forEach(Function.call,Function.call),u.length=0)},a.pause=function $$pause(){!l&&a&&(l=!0,u.forEach(Function.call,Function.call),u.length=0)},a.resume=function $$resume(){l&&a&&(l=!1,r.call(a,next,registerTeardown))},a.push=next,next.onStream=function $$onStream(){n.call(arguments).forEach(function $$each(e){e.on("data",next),e.on("error",next)})},next.unStream=function $$unStream(){n.call(arguments).forEach(function $$each(e){e.removeListener("data",next),e.removeListener("error",next)})},e.__schedule(function $$schedule(){r.call(a,next,registerTeardown)}),a},function IIFE(){function tapSequences(){function tapSequence(a){function trigger(){var e=n.call(arguments);u.seq=r(function $$react(n){n.apply(t,e)})}if(e.isSequence(a)){var u={seq:a};return a.val(function $$val(){return trigger.apply(t,arguments),e.messages.apply(t,arguments)}),u.seq=r(function $$react(e){trigger=e}),u}}return n.call(arguments).map(tapSequence).filter(Boolean)}function makeReactOperator(n,a){return function $$react$operator(){function reactor(r,c){function processSequence(c){function trigger(){var c=e.messages.apply(t,arguments);if(l&&l.length>0){u[s]=(n?u[s]:[]).concat(c.length>0?c.length>1?[c]:c[0]:void 0);var o=u.reduce(function reducer(e,n,t){return n.length>0&&e.push(n[0]),e},[]);o.length==u.length&&(1==o.length&&(o=o[0]),r.apply(t,o),a||u.forEach(function $$each(e){e.shift()}))}return c}var s=u.length;u.push([]),c.seq.val(trigger)}l.forEach(processSequence),c(function $$teardown(){l=u=null})}var u=[],l=tapSequences.apply(null,arguments);if(0!=l.length)return r(reactor)}}function makeDistinctFilterer(n){function filterer(){function isDuplicate(e){return e.length==a.length&&e.every(function $$every(e,n){return e===a[n]})}var a=e.messages.apply(t,arguments);if(a.length>0){if(r.some(isDuplicate))return!1;n?r.push(a):r[0]=a}return!0}var r=[];return filterer}var r=e.react;r.of=function $$react$of(){function reactor(e){a||(a=!0,u.length>0&&u.shift().val(function val(){e.apply(t,arguments),u.length>0&&u.shift().val(val)}))}var a,u=n.call(arguments).map(function wrapper(n){return e.isSequence(n)||(n=e(n)),n});return r(reactor)},r.all=r.zip=makeReactOperator(!0),r.allLatest=makeReactOperator(),r.latest=r.combineLatest=makeReactOperator(!1,!0),r.any=r.merge=function $$react$any(){function reactor(r,a){function processSequence(a){function trigger(){var a=e.messages.apply(t,arguments);return n&&n.length>0&&r.apply(t,a),a}a.seq.val(trigger)}n.forEach(processSequence),a(function $$teardown(){n=null})}var n=tapSequences.apply(null,arguments);if(0!=n.length)return r(reactor)},r.distinct=function $$react$distinct(e){return r.filter(e,makeDistinctFilterer(!0))},r.distinctConsecutive=r.distinctUntilChanged=function $$react$distinct$consecutive(e){return r.filter(e,makeDistinctFilterer(!1))},r.filter=function $$react$filter(n,a){function reactor(n,r){function trigger(){var r=e.messages.apply(t,arguments);return a&&a.apply(t,r)&&n.apply(t,r),r}u.seq.val(trigger),r(function $$teardown(){u=a=null})}var u=tapSequences(n)[0];if(u)return r(reactor)},r.fromObservable=function $$react$from$observable(e){function reactor(t,r){n.forEach(t),n.length=0,n.complete||(notify=t),r(function $$teardown(){e.dispose()})}function notify(e){n.push(e)}var n=[];return e.subscribe(function $$on$next(e){notify(e)},function $$on$error(){},function $$on$complete(){n.complete=!0,e.dispose()}),r(reactor)},e.extend("toObservable",function $$extend(n,r){return function $$to$observable(){function init(r){function define(a){function listen(){var n=e.messages.apply(t,arguments);return r[a[1]].apply(r,1==n.length?[n[0]]:n),n}n[a[0]](listen)}[["val","onNext"],["or","onError"]].forEach(define)}return Rx.Observable.create(init)}})}(),e.extend("runner",function $$extend(r,u){return function $$runner(){if(u("seq_error")||u("seq_aborted")||0===arguments.length)return r;var l=n.call(arguments);return r.then(function $$then(r){function wrap(n){return"function"==typeof n?(n=n.call(t,i),isPromise(n)&&(n=e.iterable(n))):n=e.isSequence(n)&&"next"in n?n.duplicate():e.iterable(n),e.isSequence(n)&&n.or(function $$or(){r.fail.apply(t,arguments)}),n}function addWrapped(){o.push.apply(o,n.call(arguments).map(wrap))}function iterateOrQuit(n,u){o.length>0?u?n():a(n):("undefined"!=typeof f?e.isMessageWrapper(f)||(f=[f]):f=[],r.apply(t,f))}var c,s,o=l,i={messages:n.call(arguments,1),add:addWrapped},f=i;o=o.map(wrap),function iterate(){c=o.shift();try{s=e.isMessageWrapper(f)&&e.isSequence(c)?c.next.apply(c,f):c.next(f)}catch(n){return r.fail(n)}if(!u("seq_aborted"))if(s.value===i)s.done||o.push(c),f=i,iterateOrQuit(iterate,!1);else{if(!e.isSequence(s.value))if(isPromise(s.value))s.value=e().promise(s.value);else if("function"==typeof s.value){var a=s.value;s.value=e(function $$ASQ(e){a(e.errfcb)})}else e.isMessageWrapper(s.value)?s.value=e.apply(t,s.value.length>0?s.value:e.messages(void 0)):"undefined"!=typeof s.value?s.value=e(s.value):s.value=e();s.value.val(function $$val(){u("seq_aborted")||(arguments.length>0&&(f=arguments.length>1?e.messages.apply(t,arguments):arguments[0]),s.done||(f===i?o.push(c):o.unshift(c)),iterateOrQuit(iterate,!0))}).or(function $$or(){if(!u("seq_aborted"))try{c["throw"].apply(c,arguments)}catch(e){r.fail(e)}})}}()}),r}}),e.extend("toPromise",function $$extend(r,a){return function $$to$promise(){return new Promise(function $$executor(a,u){r.val(function $$val(){var r=n.call(arguments);return a.call(t,r.length>1?r:r[0]),e.messages.apply(t,r)}).or(function $$or(){var e=n.call(arguments);u.call(t,e.length>1?e:e[0])})})}}),e.extend("try",function $$extend(r,a){return function $$try(){if(a("seq_error")||a("seq_aborted")||0===arguments.length)return r;var u=n.call(arguments).map(function $$map(r){return function $$then(a){var u=n.call(arguments),l=e.apply(t,u.slice(1));l.then(function $$inner$then(){r.apply(t,arguments)}).val(function $$val(){a.apply(t,arguments)}).or(function $$inner$or(){var n=e.messages.apply(t,arguments);a({"catch":n.length>1?n:n[0]})})}});return r.then.apply(t,u),r}}),e.extend("until",function $$extend(r,a){return function $$until(){if(a("seq_error")||a("seq_aborted")||0===arguments.length)return r;var u=n.call(arguments).map(function $$map(r){return function $$then(a){var u=n.call(arguments),l=e.apply(t,u.slice(1));l.then(function $$inner$then(){var e=n.call(arguments);e[0]["break"]=function $$break(){a.fail.apply(t,arguments),l.abort()},r.apply(t,e)}).val(function $$val(){a.apply(t,arguments)}).or(function $$inner$or(){$$then.apply(t,u)})}});return r.then.apply(t,u),r}}),e.extend("waterfall",function $$extend(r,a){return function $$waterfall(){if(a("seq_error")||a("seq_aborted")||0===arguments.length)return r;var u=n.call(arguments);return r.then(function $$then(r){var a=e.messages(),l=e.apply(t,n.call(arguments,1));u.forEach(function $$each(n){l.then(n).val(function $$val(){var n=e.messages.apply(t,arguments);return a.push(n.length>1?n:n[0]),a})}),l.pipe(r)}),r}}),e.wrap=function $$wrap(r,a){function checkThis(e,n){return!e||"undefined"!=typeof window&&e===window||"undefined"!=typeof global&&e===global?n:e}function paramSpread(e){return regeneratorRuntime.mark(function paramSpread(n){return regeneratorRuntime.wrap(function paramSpread$(t){for(;;)switch(t.prev=t.next){case 0:return t.delegateYield(e.apply(this,n.messages),"t0",1);case 1:case"end":return t.stop()}},paramSpread,this)})}var u,l,c,s;if(a=a&&"object"==typeof a?a:{},a.errfcb&&a.splitcb||a.errfcb&&a.simplecb||a.splitcb&&a.simplecb||"errfcb"in a&&!a.errfcb&&!a.splitcb&&!a.simplecb||a.params_first&&a.params_last||a.spread&&!a.gen)throw Error("Invalid options");return s=a["this"]&&"object"==typeof a["this"]?a["this"]:t,u=a.errfcb||!(a.splitcb||a.simplecb),l=!!a.params_first||!a.params_last&&!("params_first"in a||a.params_first)||"params_last"in a&&!a.params_first&&!a.params_last,c=l?"push":"unshift",a.gen?(a.spread&&(r=paramSpread(r)),function $$wrapped$gen(){return e.apply(t,arguments).runner(r)}):u?function $$wrapped$errfcb(){var t=n.call(arguments),a=checkThis(this,s);return e(function $$asq(e){t[c](e.errfcb),r.apply(a,t)})}:a.splitcb?function $$wrapped$splitcb(){var t=n.call(arguments),a=checkThis(this,s);return e(function $$asq(e){t[c](e,e.fail),r.apply(a,t)})}:a.simplecb?function $$wrapped$simplecb(){var t=n.call(arguments),a=checkThis(this,s);return e(function $$asq(e){t[c](e),r.apply(a,t)})}:void 0},e}); diff --git a/frontend-masters-exercises/exercises/ex9/asq.bundle.js b/frontend-masters-exercises/exercises/ex9/asq.bundle.js new file mode 100755 index 0000000..93c9ada --- /dev/null +++ b/frontend-masters-exercises/exercises/ex9/asq.bundle.js @@ -0,0 +1,2333 @@ +/*! asynquence + v0.8.2 (c) Kyle Simpson + MIT License: http://getify.mit-license.org +*/ +!function UMD(e,n,t){"function"==typeof define&&define.amd?define(t):"undefined"!=typeof module&&module.exports?module.exports=t():n[e]=t(e,n)}("ASQ",this,function DEF(e,n){"use strict";function Queue(){function Item(e){this.fn=e,this.next=void 0}var e,n,r;return{add:function $$add(t){r=new Item(t),n?n.next=r:e=r,n=r,r=void 0},drain:function $$drain(){var r=e;for(e=n=t=null;r;)r.fn(),r=r.next}}}function schedule(e){r.add(e),t||(t=u(r.drain))}function tapSequence(e){function trigger(){e.seq=createSequence.apply(h,arguments).defer()}trigger.fail=function $$trigger$fail(){var n=f.call(arguments);e.seq=createSequence(function $$create$sequence(e){e.fail.apply(h,n)}).defer()},e.seq.val(function $$val(){return trigger.apply(h,arguments),c.apply(h,arguments)}).or(function $$or(){trigger.fail.apply(h,arguments)}),e.seq=createSequence(function $$create$sequence(e){trigger=e}).defer()}function createSequence(){function scheduleSequenceTick(){r?sequenceTick():e||(e=schedule(sequenceTick))}function throwSequenceErrors(){throw 1===$.length?$[0]:$}function sequenceTick(){var a,c;if(e=null,delete d.unpause,r)clearTimeout(e),e=null,s.length=p.length=g.length=$.length=0;else if(n)for(0!==p.length||t||(t=!0,throwSequenceErrors());p.length;){t=!0,a=p.shift();try{a.apply(h,$)}catch(i){l(i)?$=$.concat(i):($.push(i),i.stack&&$.push(i.stack)),0===p.length&&throwSequenceErrors()}}else if(u&&s.length>0){u=!1,a=s.shift(),c=g.slice(),g.length=0,c.unshift(createStepCompletion());try{a.apply(h,c)}catch(i){l(i)?$=$.concat(i):$.push(i),n=!0,scheduleSequenceTick()}}}function createStepCompletion(){function done(){n||r||u||(u=!0,g.push.apply(g,arguments),$.length=0,scheduleSequenceTick())}return done.fail=function $$step$fail(){n||r||u||(n=!0,g.length=0,$.push.apply($,arguments),scheduleSequenceTick())},done.abort=function $$step$abort(){n||r||(u=!1,r=!0,g.length=$.length=0,scheduleSequenceTick())},done.errfcb=function $$step$errfcb(e){e?done.fail(e):done.apply(h,f.call(arguments,1))},done}function createGate(e,t,u){function resetGate(){clearTimeout(s),s=d=m=o=null}function scheduleGateTick(){return g?gateTick():void(s||(s=schedule(gateTick)))}function gateTick(){if(!(n||r||$)){var t=[];s=null,p?(e.fail.apply(h,o),resetGate()):g?(e.abort(),resetGate()):checkGate()&&($=!0,d.forEach(function $$each(e,n){t.push(m["s"+n])}),e.apply(h,t),resetGate())}}function checkGate(){if(0!==d.length){var e=!0;return d.some(function $$some(n){return null===n?(e=!1,!0):void 0}),e}}function createSegmentCompletion(){function done(){if(!(n||r||p||g||$||d[e])){var t=c.apply(h,arguments);m["s"+e]=t.length>1?t:t[0],d[e]=!0,scheduleGateTick()}}var e=d.length;return done.fail=function $$segment$fail(){n||r||p||g||$||d[e]||(p=!0,o=f.call(arguments),scheduleGateTick())},done.abort=function $$segment$abort(){n||r||p||g||$||(g=!0,gateTick())},done.errfcb=function $$segment$errfcb(e){e?done.fail(e):done.apply(h,f.call(arguments,1))},d[e]=null,done}var a,i,o,s,p=!1,g=!1,$=!1,d=[],m={};t.some(function $$some(e){if(p||g)return!0;a=u.slice(),a.unshift(createSegmentCompletion());try{e.apply(h,a)}catch(n){return i=n,p=!0,!0}}),i&&(l(i)?e.fail.apply(h,i):e.fail(i))}function then(){return n||r||0===arguments.length?d:(wrapArgs(arguments,thenWrapper).forEach(function $$each(e){i(e)?seq(e):s.push(e)}),scheduleSequenceTick(),d)}function or(){return r||0===arguments.length?d:(p.push.apply(p,arguments),scheduleSequenceTick(),d)}function gate(){if(n||r||0===arguments.length)return d;var e=f.call(arguments).map(function $$map(e){var n;return i(e)?(n={seq:e},tapSequence(n),function $$segment(e){n.seq.pipe(e)}):e});return then(function $$then(n){var t=f.call(arguments,1);createGate(n,e,t)}),d}function pipe(){return r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){then(function $$then(n){e.apply(h,f.call(arguments,1)),n()}).or(e.fail)}),d)}function seq(){return n||r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){var n={seq:e};i(e)&&tapSequence(n),then(function $$then(e){var t=n.seq;i(t)||(t=n.seq.apply(h,f.call(arguments,1))),t.pipe(e)})}),d)}function val(){return n||r||0===arguments.length?d:(f.call(wrapArgs(arguments,valWrapper)).forEach(function $$each(e){then(function $$then(n){var t=e.apply(h,f.call(arguments,1));l(t)||(t=c(t)),n.apply(h,t)})}),d)}function promise(){function wrap(e){return function $$fn(){e.apply(h,l(arguments[0])?arguments[0]:arguments)}}return n||r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){then(function $$then(n){var t=e;"function"==typeof e&&"function"!=typeof e.then&&(t=e.apply(h,f.call(arguments,1))),t.then(wrap(n),wrap(n.fail))})}),d)}function fork(){var e;return val(function $$val(){return e?e.apply(h,arguments):e=createSequence.apply(h,arguments).defer(),c.apply(h,arguments)}),or(function $$or(){if(e)e.fail.apply(h,arguments);else{var n=f.call(arguments);e=createSequence().then(function $$then(e){e.fail.apply(h,n)}).defer()}}),createSequence().then(function $$then(n){e?e.pipe(n):e=n}).defer()}function abort(){return n?d:(r=!0,sequenceTick(),d)}function duplicate(){var e;return a={then_queue:s.slice(),or_queue:p.slice()},e=createSequence(),a=null,e}function unpause(){g.push.apply(g,arguments),e===!0&&(e=null),scheduleSequenceTick()}function defer(){return p.push(function ignored(){}),d}function internals(e,t){var a=arguments.length>1;switch(e){case"seq_error":if(!a)return n;n=t;break;case"seq_aborted":if(!a)return r;r=t;break;case"then_ready":if(!a)return u;u=t;break;case"then_queue":return s;case"or_queue":return p;case"sequence_messages":return g;case"sequence_errors":return $}}function includeExtensions(){Object.keys(o).forEach(function $$each(e){d[e]=o[e](d,internals)})}var e,n=!1,t=!1,r=!1,u=!0,s=[],p=[],g=[],$=[],d=brandIt({then:then,or:or,onerror:or,gate:gate,all:gate,pipe:pipe,seq:seq,val:val,promise:promise,fork:fork,abort:abort,duplicate:duplicate,defer:defer});return includeExtensions(),a&&(s=a.then_queue.slice(),p=a.or_queue.slice(),d.unpause=unpause,e=!0),d.then.apply(h,arguments),d}function brandIt(e){return Object.defineProperty(e,p,{enumerable:!1,value:!0})}function checkBranding(e){return!(null==e||"object"!=typeof e||!e[p])}function valWrapper(e){return c.apply(h,f.call(arguments).slice(1,e+1))}function thenWrapper(e){arguments[e+1].apply(h,f.call(arguments).slice(1,e+1))}function wrapArgs(e,n){var t,r;for(e=f.call(e),t=0;t 1 ? + ARRAY_SLICE.call(arguments,1) : + void 0 + ; + num = +num || 0; + + api.then(function $$then(done){ + var args = orig_args || ARRAY_SLICE.call(arguments,1); + + setTimeout(function $$set$timeout(){ + done.apply(ø,args); + },num); + }); + + return api; + }; +}); + +ASQ.after = function $$after() { + return ASQ().after.apply(ø,arguments); +}; +// "any" +ASQ.extend("any",function $$extend(api,internals){ + return function $$any() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages.length = 0; + } + + function complete(trigger) { + if (success_messages.length > 0) { + // any successful segment's message(s) sent + // to main sequence to proceed as success + success_messages.length = fns.length; + trigger.apply(ø,success_messages); + } + else { + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + success_messages = [], + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "errfcb" +ASQ.extend("errfcb",function $$extend(api,internals){ + return function $$errfcb() { + // create a fake sequence to extract the callbacks + var sq = { + val: function $$then(cb){ sq.val_cb = cb; return sq; }, + or: function $$or(cb){ sq.or_cb = cb; return sq; } + }; + + // trick `seq(..)`s checks for a sequence + sq[brand] = true; + + // immediately register our fake sequence on the + // main sequence + api.seq(sq); + + // provide the "error-first" callback + return function $$errorfirst$callback(err) { + if (err) { + sq.or_cb(err); + } + else { + sq.val_cb.apply(ø,ARRAY_SLICE.call(arguments,1)); + } + }; + }; +}); +// "failAfter" +ASQ.extend("failAfter",function $$extend(api,internals){ + return function $$failAfter(num) { + var args = arguments.length > 1 ? + ARRAY_SLICE.call(arguments,1) : + void 0 + ; + num = +num || 0; + + api.then(function $$then(done){ + setTimeout(function $$set$timeout(){ + done.fail.apply(ø,args); + },num); + }); + + return api; + }; +}); + +ASQ.failAfter = function $$fail$after() { + return ASQ().failAfter.apply(ø,arguments); +}; +// "first" +ASQ.extend("first",function $$extend(api,internals){ + return function $$first() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + error_messages.length = 0; + } + + function success(trigger,idx,args) { + if (!finished) { + finished = true; + + // first successful segment triggers + // main sequence to proceed as success + trigger( + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ); + + reset(); + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete without success? + if (completed === fns.length) { + finished = true; + + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + + reset(); + } + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "go-style CSP" +(function IIFE(){ + + // filter out already-resolved queue entries + function filterResolved(queue) { + return queue.filter(function $$filter(entry){ + return !entry.resolved; + }); + } + + function closeQueue(queue,finalValue) { + queue.forEach(function $$each(iter){ + if (!iter.resolved) { + iter.next(); + iter.next(finalValue); + } + }); + queue.length = 0; + } + + function channel(bufSize) { + var ch = { + close: function $$close(){ + ch.closed = true; + closeQueue(ch.put_queue,false); + closeQueue(ch.take_queue,ASQ.csp.CLOSED); + }, + closed: false, + messages: [], + put_queue: [], + take_queue: [], + buffer_size: +bufSize || 0 + }; + return ch; + } + + function unblock(iter) { + if (iter && !iter.resolved) { + iter.next(iter.next().value); + } + } + + function put(channel,value) { + var ret; + + if (channel.closed) { + return false; + } + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + // immediate put? + if (channel.messages.length < channel.buffer_size) { + channel.messages.push(value); + unblock(channel.take_queue.shift()); + return true; + } + // queued put + else { + channel.put_queue.push( + // make a notifiable iterable for 'put' blocking + ASQ.iterable() + .then(function $$then(){ + if (!channel.closed) { + channel.messages.push(value); + return true; + } + else { + return false; + } + }) + ); + + // wrap a sequence/promise around the iterable + ret = ASQ( + channel.put_queue[channel.put_queue.length - 1] + ); + + // take waiting on this queued put? + if (channel.take_queue.length > 0) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + + return ret; + } + } + + function putAsync(channel,value,cb) { + var ret = ASQ(put(channel,value)); + + if (cb && typeof cb == "function") { + ret.val(cb); + } + else { + return ret; + } + } + + function take(channel) { + var ret; + + try { + ret = takem(channel); + } + catch (err) { + ret = err; + } + + if (ASQ.isSequence(ret)) { + ret.pCatch(function $$pcatch(err){ + return err; + }); + } + + return ret; + } + + function takeAsync(channel,cb) { + var ret = ASQ(take(channel)); + + if (cb && typeof cb == "function") { + ret.val(cb); + } + else { + return ret; + } + } + + function takem(channel) { + var msg; + + if (channel.closed) { + return ASQ.csp.CLOSED; + } + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + // immediate take? + if (channel.messages.length > 0) { + msg = channel.messages.shift(); + unblock(channel.put_queue.shift()); + if (msg instanceof Error) { + throw msg; + } + return msg; + } + // queued take + else { + channel.take_queue.push( + // make a notifiable iterable for 'take' blocking + ASQ.iterable() + .then(function $$then(){ + if (!channel.closed) { + var v = channel.messages.shift(); + if (v instanceof Error) { + throw v; + } + return v; + } + else { + return ASQ.csp.CLOSED; + } + }) + ); + + // wrap a sequence/promise around the iterable + msg = ASQ( + channel.take_queue[channel.take_queue.length - 1] + ); + + // put waiting on this take? + if (channel.put_queue.length > 0) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + + return msg; + } + } + + function takemAsync(channel,cb) { + var ret = ASQ(takem(channel)); + + if (cb && typeof cb == "function") { + ret.pThen(cb,cb); + } + else { + return ret.val(function $$val(v){ + if (v instanceof Error) { + throw v; + } + return v; + }); + } + } + + function alts(actions) { + var closed, open, handlers, i, isq, ret, resolved = false; + + // used `alts(..)` incorrectly? + if (!Array.isArray(actions) || actions.length == 0) { + throw Error("Invalid usage"); + } + + closed = []; + open = []; + handlers = []; + + // separate actions by open/closed channel status + actions.forEach(function $$each(action){ + var channel = Array.isArray(action) ? action[0] : action; + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + if (channel.closed) { + closed.push(channel); + } + else { + open.push(action); + } + }); + + // if no channels are still open, we're done + if (open.length == 0) { + return { value: ASQ.csp.CLOSED, channel: closed }; + } + + // can any channel action be executed immediately? + for (i=0; i 0) { + return { value: take(open[i]), channel: open[i] }; + } + } + + isq = ASQ.iterable(); + var ret = ASQ(isq); + + // setup channel action handlers + for (i=0; i 0) { + schedule(function handleUnblocking(){ + if (!resolved) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + },0); + } + } + // take action? + else { + channel = action; + + // define take handler + handlers.push( + ASQ.iterable() + .then(function $$then(){ + resolved = true; + + // mark all handlers across this `alts(..)` as resolved now + handlers = handlers.filter(function $$filter(handler){ + return !(handler.resolved = true); + }); + + // channel still open? + if (!channel.closed) { + isq.next({ value: channel.messages.shift(), channel: channel }); + } + // channel already closed? + else { + isq.next({ value: ASQ.csp.CLOSED, channel: channel }); + } + }) + ); + + // queue up take handler + channel.take_queue.push(handlers[handlers.length-1]); + + // put waiting on this queued take? + if (channel.put_queue.length > 0) { + schedule(function handleUnblocking(){ + if (!resolved) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + }); + } + } + })(open[i]); + } + + return ret; + } + + function altsAsync(chans,cb) { + var ret = ASQ(alts(chans)); + + if (cb && typeof cb == "function") { + ret.pThen(cb,cb); + } + else { + return ret; + } + } + + function timeout(delay) { + var ch = channel(); + setTimeout(ch.close,delay); + return ch; + } + + function go(gen,args) { + // goroutine arguments passed? + if (arguments.length > 1) { + if (!args || !Array.isArray(args)) { + args = [args]; + } + } + else { + args = []; + } + + return function *$$go(token) { + + // unblock the overall goroutine handling + function unblock() { + token.unblock_count++; + + if (token.block && !token.block.marked) { + token.block.marked = true; + token.block.next(); + } + } + + var ret, msg, err, type, done = false, it; + + // keep track of how many requests for unblocking + // have occurred + token.unblock_count = (token.unblock_count || 0); + + // keep track of how many goroutines are running + // so we can infer when we're done go'ing + token.go_count = (token.go_count || 0) + 1; + + // need to initialize a set of goroutines? + if (token.go_count === 1) { + // create a default channel for these goroutines + token.channel = channel(); + token.channel.messages = token.messages; + token.channel.go = function $$go(){ + // unblock the goroutine handling for this + // new goroutine + unblock(); + // add the goroutine (called with any args) to + // the handling queue + token.add( go.apply(ø,arguments) ); + }; + // starting out with initial channel messages? + if (token.channel.messages.length > 0) { + // fake back-pressure blocking for each + token.channel.put_queue = token.channel.messages.map(function $$map(){ + // make a notifiable iterable for 'put' blocking + return ASQ.iterable() + .then(function $$then(){ + unblock(token.channel.take_queue.shift()); + return !token.channel.closed; + }); + }); + } + } + + // initialize the generator + it = gen.apply(ø,[token.channel].concat(args)); + + (function iterate(){ + + function next() { + // keep going with next step in goroutine? + if (!done) { + iterate(); + } + // unblock overall goroutine handling to + // continue with other goroutines + else { + unblock(); + } + } + + // has a resumption value been achieved yet? + if (!ret) { + // try to resume the goroutine + try { + // resume with injected exception? + if (err) { + ret = it.throw(err); + err = null; + } + // resume normally + else { + ret = it.next(msg); + } + } + // resumption failed, so bail + catch (e) { + done = true; + err = e; + msg = null; + unblock(); + return; + } + + // keep track of the result of the resumption + done = ret.done; + ret = ret.value; + type = typeof ret; + + // if this goroutine is complete, unblock the + // overall goroutine handling + if (done) { + unblock(); + } + + // received a thenable/promise back? + if (isPromise(ret)) { + ret = ASQ().promise(ret); + } + + // wait for the value? + if (ASQ.isSequence(ret)) { + ret.val(function $$val(){ + ret = null; + msg = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + next(); + }) + .or(function $$or(){ + ret = null; + msg = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + if (msg instanceof Error) { + err = msg; + msg = null; + } + next(); + }); + } + // immediate value, prepare it to go right back in + else { + msg = ret; + ret = null; + next(); + } + } + })(); + + // keep this goroutine alive until completion + while (!done) { + // transfer control to another goroutine + yield token; + + // need to block overall goroutine handling + // while idle? + if (!done && !token.block && token.unblock_count === 0) { + // wait here while idle + yield (token.block = ASQ.iterable()); + + token.block = false; + } + + if (token.unblock_count > 0) token.unblock_count--; + } + + // this goroutine is done now + token.go_count--; + + // all goroutines done? + if (token.go_count === 0) { + // any lingering blocking need to be cleaned up? + unblock(); + + // capture any untaken messages + msg = ASQ.messages.apply(ø,token.messages); + + // need to implicitly force-close channel? + if (token.channel && !token.channel.closed) { + token.channel.closed = true; + token.channel.put_queue.length = token.channel.take_queue.length = 0; + token.channel.close = token.channel.go = token.channel.messages = null; + } + token.channel = null; + } + + // make sure leftover error or message are + // passed along + if (err) { + throw err; + } + else if (token.go_count === 0) { + return msg; + } + else { + return token; + } + }; + } + + ASQ.csp = { + chan: channel, + put: put, + putAsync: putAsync, + take: take, + takeAsync: takeAsync, + takem: takem, + takemAsync: takemAsync, + alts: alts, + altsAsync: altsAsync, + timeout: timeout, + go: go, + CLOSED: {} + }; + +})(); +// "ASQ.iterable()" +(function IIFE(){ + var template; + + ASQ.iterable = function $$iterable() { + function throwSequenceErrors() { + throw (sequence_errors.length === 1 ? sequence_errors[0] : sequence_errors); + } + + function notifyErrors() { + var fn; + + seq_tick = null; + + if (seq_error) { + if (or_queue.length === 0 && !error_reported) { + error_reported = true; + throwSequenceErrors(); + } + + while (or_queue.length > 0) { + error_reported = true; + fn = or_queue.shift(); + try { + fn.apply(ø,sequence_errors); + } + catch (err) { + if (checkBranding(err)) { + sequence_errors = sequence_errors.concat(err); + } + else { + sequence_errors.push(err); + } + if (or_queue.length === 0) { + throwSequenceErrors(); + } + } + } + } + } + + function val() { + if (seq_error || seq_aborted || arguments.length === 0) { + return sequence_api; + } + + var args = ARRAY_SLICE.call(arguments).map(function mapper(arg){ + if (typeof arg != "function") return function $$val() { return arg; }; + else return arg; + }); + + val_queue.push.apply(val_queue,args); + + return sequence_api; + } + + function or() { + if (seq_aborted || arguments.length === 0) { + return sequence_api; + } + + or_queue.push.apply(or_queue,arguments); + + if (!seq_tick) { + seq_tick = schedule(notifyErrors); + } + + return sequence_api; + } + + function pipe() { + if (seq_aborted || arguments.length === 0) { + return sequence_api; + } + + ARRAY_SLICE.call(arguments) + .forEach(function $$each(fn){ + val(fn).or(fn.fail); + }); + + return sequence_api; + } + + function next() { + if (seq_error || seq_aborted || val_queue.length === 0) { + if (val_queue.length > 0) { + $throw$("Sequence cannot be iterated"); + } + return { done: true }; + } + + try { + return { value: val_queue.shift().apply(ø,arguments) }; + } + catch (err) { + if (ASQ.isMessageWrapper(err)) { + $throw$.apply(ø,err); + } + else { + $throw$(err); + } + + return {}; + } + } + + function $throw$() { + if (seq_error || seq_aborted) { + return sequence_api; + } + + sequence_errors.push.apply(sequence_errors,arguments); + seq_error = true; + if (!seq_tick) { + seq_tick = schedule(notifyErrors); + } + + return sequence_api; + } + + function $return$(val) { + if (seq_error || seq_aborted) { + val = void 0; + } + + abort(); + + return { done: true, value: val }; + } + + function abort() { + if (seq_error || seq_aborted) { + return; + } + + seq_aborted = true; + + clearTimeout(seq_tick); + seq_tick = null; + val_queue.length = or_queue.length = sequence_errors.length = 0; + } + + function duplicate() { + var isq; + + template = { + val_queue: val_queue.slice(), + or_queue: or_queue.slice() + }; + isq = ASQ.iterable(); + template = null; + + return isq; + } + + // opt-out of global error reporting for this sequence + function defer() { + or_queue.push(function $$ignored(){}); + return sequence_api; + } + + // *********************************************** + // Object branding utilities + // *********************************************** + function brandIt(obj) { + Object.defineProperty(obj,brand,{ + enumerable: false, + value: true + }); + + return obj; + } + + var sequence_api, + + seq_error = false, + error_reported = false, + seq_aborted = false, + + seq_tick, + + val_queue = [], + or_queue = [], + + sequence_errors = [] + ; + + // *********************************************** + // Setup the ASQ.iterable() public API + // *********************************************** + sequence_api = brandIt({ + val: val, + then: val, + or: or, + pipe: pipe, + next: next, + "throw": $throw$, + "return": $return$, + abort: abort, + duplicate: duplicate, + defer: defer + }); + + // useful for ES6 `for..of` loops, + // add `@@iterator` to simply hand back + // our iterable sequence itself! + sequence_api[(typeof Symbol == "function" && Symbol.iterator) || "@@iterator"] = function $$iter() { + return sequence_api; + }; + + // templating the iterable-sequence setup? + if (template) { + val_queue = template.val_queue.slice(0); + or_queue = template.or_queue.slice(0); + } + + // treat ASQ.iterable() constructor parameters as having been + // passed to `val()` + sequence_api.val.apply(ø,arguments); + + return sequence_api; + }; + +})(); +// "last" +ASQ.extend("last",function $$extend(api,internals){ + return function $$last() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages = null; + } + + function complete(trigger) { + if (success_messages != null) { + // last successful segment's message(s) sent + // to main sequence to proceed as success + trigger( + success_messages.length > 1 ? + ASQ.messages.apply(ø,success_messages) : + success_messages[0] + ); + } + else { + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages = args; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)), + success_messages + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "map" +ASQ.extend("map",function $$extend(api,internals){ + return function $$map(pArr,pEach) { + if (internals("seq_error") || internals("seq_aborted")) { + return api; + } + + api.seq(function $$seq(){ + var tmp, args = ARRAY_SLICE.call(arguments), + arr = pArr, each = pEach; + + // if missing `map(..)` args, use value-messages (if any) + if (!each) each = args.shift(); + if (!arr) arr = args.shift(); + + // if arg types in reverse order (each,arr), swap + if (typeof arr === "function" && Array.isArray(each)) { + tmp = arr; + arr = each; + each = tmp; + } + + return ASQ.apply(ø,args) + .gate.apply(ø,arr.map(function $$map(item){ + return function $$segment(){ + each.apply(ø,[item].concat(ARRAY_SLICE.call(arguments))); + }; + })); + }) + .val(function $$val(){ + // collect all gate segment output into one value-message + // Note: return a normal array here, not a message wrapper! + return ARRAY_SLICE.call(arguments); + }); + + return api; + }; +}); +// "none" +ASQ.extend("none",function $$extend(api,internals){ + return function $$none() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages.length = 0; + } + + function complete(trigger) { + if (success_messages.length > 0) { + // any successful segment's message(s) sent + // to main sequence to proceed as **error** + success_messages.length = fns.length; + trigger.fail.apply(ø,success_messages); + } + else { + // send errors as **success** to main sequence + error_messages.length = fns.length; + trigger.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)), + success_messages = [] + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "pThen" +ASQ.extend("pThen",function $$extend(api,internals){ + return function $$pthen(success,failure) { + if (internals("seq_aborted")) { + return api; + } + + var ignore_success_handler = false, ignore_failure_handler = false; + + if (typeof success === "function") { + api.then(function $$then(done){ + if (!ignore_success_handler) { + var ret, msgs = ASQ.messages.apply(ø,arguments); + msgs.shift(); + + if (msgs.length === 1) { + msgs = msgs[0]; + } + + ignore_failure_handler = true; + + try { + ret = success(msgs); + } + catch (err) { + if (!ASQ.isMessageWrapper(err)) { + err = [err]; + } + done.fail.apply(ø,err); + return; + } + + // returned a sequence? + if (ASQ.isSequence(ret)) { + ret.pipe(done); + } + // returned a message wrapper? + else if (ASQ.isMessageWrapper(ret)) { + done.apply(ø,ret); + } + // returned a promise/thenable? + else if (isPromise(ret)) { + ret.then(done,done.fail); + } + // just a normal value to pass along + else { + done(ret); + } + } + else { + done.apply(ø,ARRAY_SLICE.call(arguments,1)); + } + }); + } + if (typeof failure === "function") { + api.or(function $$or(){ + if (!ignore_failure_handler) { + var ret, msgs = ASQ.messages.apply(ø,arguments), smgs, + or_queue = ARRAY_SLICE.call(internals("or_queue")) + ; + + if (msgs.length === 1) { + msgs = msgs[0]; + } + + ignore_success_handler = true; + + // NOTE: if this call throws, that'll automatically + // be handled by core as we'd want it to be + ret = failure(msgs); + + // if we get this far: + // first, inject return value (if any) as + // next step's sequence messages + smgs = internals("sequence_messages"); + smgs.length = 0; + if (typeof ret !== "undefined") { + if (!ASQ.isMessageWrapper(ret)) { + ret = [ret]; + } + smgs.push.apply(smgs,ret); + } + + // reset internal error state, because we've exclusively + // handled any errors up to this point of the sequence + internals("sequence_errors").length = 0; + internals("seq_error",false); + internals("then_ready",true); + + // temporarily empty the or-queue + internals("or_queue").length = 0; + + // make sure to schedule success-procession on the chain + api.val(function $$val(){ + // pass thru messages + return ASQ.messages.apply(ø,arguments); + }); + + // at next cycle, reinstate the or-queue (if any) + if (or_queue.length > 0) { + schedule(function $$schedule(){ + api.or.apply(ø,or_queue); + }); + } + } + }); + } + return api; + }; +}); + +// "pCatch" +ASQ.extend("pCatch",function $$extend(api,internals){ + return function $$pcatch(failure) { + if (internals("seq_aborted")) { + return api; + } + + api.pThen(void 0,failure); + + return api; + }; +}); +// "race" +ASQ.extend("race",function $$extend(api,internals){ + return function $$race() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(v){ + var def; + // tap any directly-provided sequences immediately + if (ASQ.isSequence(v)) { + def = { seq: v }; + tapSequence(def); + return function $$fn(done) { + def.seq.pipe(done); + }; + } + else return v; + }); + + api.then(function $$then(done){ + var args = ARRAY_SLICE.call(arguments); + + fns.forEach(function $$each(fn){ + fn.apply(ø,args); + }); + }); + + return api; + }; +}); +// "react" (reactive sequences) +ASQ.react = function $$react(reactor) { + function next() { + if (!paused) { + if (template) { + var sq = template.duplicate(); + sq.unpause.apply(ø,arguments); + return sq; + } + return ASQ(function $$asq(){ throw "Disabled Sequence"; }); + } + } + + function registerTeardown(fn) { + if (template && typeof fn === "function") { + teardowns.push(fn); + } + } + + var template = ASQ().duplicate(), + teardowns = [], paused = false + ; + + // add reactive sequence kill switch + template.stop = function $$stop() { + if (template) { + template = null; + teardowns.forEach(Function.call,Function.call); + teardowns.length = 0; + } + }; + + template.pause = function $$pause() { + if (!paused && template) { + paused = true; + teardowns.forEach(Function.call,Function.call); + teardowns.length = 0; + } + }; + + template.resume = function $$resume() { + if (paused && template) { + paused = false; + reactor.call(template,next,registerTeardown); + } + }; + + template.push = next; + + next.onStream = function $$onStream() { + ARRAY_SLICE.call(arguments) + .forEach(function $$each(stream){ + stream.on("data",next); + stream.on("error",next); + }); + }; + + next.unStream = function $$unStream() { + ARRAY_SLICE.call(arguments) + .forEach(function $$each(stream){ + stream.removeListener("data",next); + stream.removeListener("error",next); + }); + }; + + // make sure `reactor(..)` is called async + ASQ.__schedule(function $$schedule(){ + reactor.call(template,next,registerTeardown); + }); + + return template; +}; +// "react" helpers +(function IIFE(){ + + var Ar = ASQ.react; + + Ar.of = function $$react$of() { + function reactor(next) { + if (!started) { + started = true; + if (args.length > 0) { + args.shift().val(function val(){ + next.apply(ø,arguments); + if (args.length > 0) { + args.shift().val(val); + } + }); + } + } + } + + var started, args = ARRAY_SLICE.call(arguments) + .map(function wrapper(arg){ + if (!ASQ.isSequence(arg)) arg = ASQ(arg); + return arg; + }); + + return Ar(reactor); + }; + + Ar.all = Ar.zip = makeReactOperator(/*buffer=*/true); + Ar.allLatest = makeReactOperator(/*buffer=false*/); + Ar.latest = Ar.combineLatest = makeReactOperator(/*buffer=*/false,/*keep=*/true); + + Ar.any = Ar.merge = function $$react$any(){ + function reactor(next,registerTeardown){ + function processSequence(def){ + function trigger(){ + var args = ASQ.messages.apply(ø,arguments); + // still observing sequence-streams? + if (seqs && seqs.length > 0) { + // fire off reactive sequence instance + next.apply(ø,args); + } + // keep sequence going + return args; + } + + // sequence-stream event listener + def.seq.val(trigger); + } + + // observe all sequence-streams + seqs.forEach(processSequence); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + seqs = null; + }); + } + + // observe all sequence-streams + var seqs = tapSequences.apply(null,arguments); + + if (seqs.length == 0) return; + + return Ar(reactor); + }; + + Ar.distinct = function $$react$distinct(seq){ + return Ar.filter(seq,makeDistinctFilterer(/*keepAll=*/true)); + }; + + Ar.distinctConsecutive = Ar.distinctUntilChanged = function $$react$distinct$consecutive(seq) { + return Ar.filter(seq,makeDistinctFilterer(/*keepAll=*/false)); + }; + + Ar.filter = function $$react$filter(seq,filterer){ + function reactor(next,registerTeardown) { + function trigger(){ + var messages = ASQ.messages.apply(ø,arguments); + + if (filterer && filterer.apply(ø,messages)) { + // fire off reactive sequence instance + next.apply(ø,messages); + } + + // keep sequence going + return messages; + } + + // sequence-stream event listener + def.seq.val(trigger); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + def = filterer = null; + }); + } + + // observe sequence-stream + var def = tapSequences(seq)[0]; + + if (!def) return; + + return Ar(reactor); + }; + + Ar.fromObservable = function $$react$from$observable(obsv){ + function reactor(next,registerTeardown){ + // process buffer (if any) + buffer.forEach(next); + buffer.length = 0; + + // start non-buffered notifications? + if (!buffer.complete) { + notify = next; + } + + registerTeardown(function $$teardown(){ + obsv.dispose(); + }); + } + + function notify(v) { + buffer.push(v); + } + + var buffer = []; + + obsv.subscribe( + function $$on$next(v){ + notify(v); + }, + function $$on$error(){}, + function $$on$complete(){ + buffer.complete = true; + obsv.dispose(); + } + ); + + return Ar(reactor); + }; + + ASQ.extend("toObservable",function $$extend(api,internals){ + return function $$to$observable(){ + function init(observer) { + function define(pair){ + function listen(){ + var args = ASQ.messages.apply(ø,arguments); + observer[pair[1]].apply(observer, + args.length == 1 ? [args[0]] : args + ); + return args; + } + + api[pair[0]](listen); + } + + [["val","onNext"],["or","onError"]] + .forEach(define); + } + + return Rx.Observable.create(init); + }; + }); + + function tapSequences() { + function tapSequence(seq) { + // temporary `trigger` which, if called before being replaced + // below, creates replacement proxy sequence with the + // event message(s) re-fired + function trigger() { + var args = ARRAY_SLICE.call(arguments); + def.seq = Ar(function $$react(next){ + next.apply(ø,args); + }); + } + + if (ASQ.isSequence(seq)) { + var def = { seq: seq }; + + // listen for events from the sequence-stream + seq.val(function $$val(){ + trigger.apply(ø,arguments); + return ASQ.messages.apply(ø,arguments); + }); + + // make a reactive sequence to act as a proxy to the original + // sequence + def.seq = Ar(function $$react(next){ + // replace the temporary trigger (created above) + // with this proxy's trigger + trigger = next; + }); + + return def; + } + } + + return ARRAY_SLICE.call(arguments) + .map(tapSequence) + .filter(Boolean); + } + + function makeReactOperator(buffer,keep) { + return function $$react$operator(){ + function reactor(next,registerTeardown){ + function processSequence(def) { + // sequence-stream event listener + function trigger() { + var args = ASQ.messages.apply(ø,arguments); + // still observing sequence-streams? + if (seqs && seqs.length > 0) { + // store event message(s), if any + seq_events[seq_id] = + (buffer ? seq_events[seq_id] : []).concat( + args.length > 0 ? (args.length > 1 ? [args] : args[0]) : undefined + ); + + // collect event message(s) across the + // sequence-stream sources + var messages = seq_events.reduce(function reducer(msgs,eventList,idx){ + if (eventList.length > 0) msgs.push(eventList[0]); + return msgs; + },[]); + + // did all sequence-streams get an event? + if (messages.length == seq_events.length) { + if (messages.length == 1) messages = messages[0]; + + // fire off reactive sequence instance + next.apply(ø,messages); + + // discard stored event message(s)? + if (!keep) { + seq_events.forEach(function $$each(eventList){ + eventList.shift(); + }); + } + } + } + // keep sequence going + return args; + } + + var seq_id = seq_events.length; + seq_events.push([]); + def.seq.val(trigger); + } + + // process all sequence-streams + seqs.forEach(processSequence); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + seqs = seq_events = null; + }); + } + + var seq_events = [], + // observe all sequence-streams + seqs = tapSequences.apply(null,arguments) + ; + + if (seqs.length == 0) return; + + return Ar(reactor); + }; + } + + function makeDistinctFilterer(keepAll) { + function filterer() { + function isDuplicate(msgSet) { + return ( + msgSet.length == message_set.length && + msgSet.every(function $$every(val,idx){ + return val === message_set[idx]; + }) + ); + } + + var message_set = ASQ.messages.apply(ø,arguments); + + // any messages in message-set to check against? + if (message_set.length > 0) { + // duplicate message-set? + if (msg_sets.some(isDuplicate)) { + return false; + } + + // remember all message-sets for future distinct checking? + if (keepAll) { + msg_sets.push(message_set); + } + // only keep the last message-set for distinct-consecutive + // checking + else { + msg_sets[0] = message_set; + } + } + + // allow distinct non-duplicate value through + return true; + } + + var msg_sets = []; + + return filterer; + } + +})(); +// "runner" +ASQ.extend("runner",function $$extend(api,internals){ + + return function $$runner() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var args = ARRAY_SLICE.call(arguments); + + api + .then(function $$then(mainDone){ + + function wrap(v) { + // function? expected to produce an iterator + // (like a generator) or a promise + if (typeof v === "function") { + // call function passing in the control token + // note: neutralize `this` in call to prevent + // unexpected behavior + v = v.call(ø,token); + + // promise returned (ie, from async function)? + if (isPromise(v)) { + // wrap it in iterable sequence + v = ASQ.iterable(v); + } + } + // an iterable sequence? duplicate it (in case of multiple runs) + else if (ASQ.isSequence(v) && "next" in v) { + v = v.duplicate(); + } + // wrap anything else in iterable sequence + else { + v = ASQ.iterable(v); + } + + // a sequence to tap for errors? + if (ASQ.isSequence(v)) { + // listen for any sequence failures + v.or(function $$or(){ + // signal iteration-error + mainDone.fail.apply(ø,arguments); + }); + } + + return v; + } + + function addWrapped() { + iterators.push.apply( + iterators, + ARRAY_SLICE.call(arguments).map(wrap) + ); + } + + function iterateOrQuit(iterFn,now) { + // still have some co-routine runs to process? + if (iterators.length > 0) { + if (now) iterFn(); + else schedule(iterFn); + } + // all done! + else { + // previous value message? + if (typeof next_val !== "undefined") { + // not a message wrapper array? + if (!ASQ.isMessageWrapper(next_val)) { + // wrap value for the subsequent `apply(..)` + next_val = [next_val]; + } + } + else { + // nothing to affirmatively pass along + next_val = []; + } + + // signal done with all co-routine runs + mainDone.apply(ø,next_val); + } + } + + var iterators = args, + token = { + messages: ARRAY_SLICE.call(arguments,1), + add: addWrapped + }, + iter, ret, next_val = token + ; + + // map co-routines to round-robin list of iterators + iterators = iterators.map(wrap); + + // async iteration of round-robin list + (function iterate(){ + // get next co-routine in list + iter = iterators.shift(); + + // process the iteration + try { + // multiple messages to send to an iterable + // sequence? + if (ASQ.isMessageWrapper(next_val) && + ASQ.isSequence(iter) + ) { + ret = iter.next.apply(iter,next_val); + } + else { + ret = iter.next(next_val); + } + } + catch (err) { + return mainDone.fail(err); + } + + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + // was the control token yielded? + if (ret.value === token) { + // round-robin: put co-routine back into the list + // at the end where it was so it can be processed + // again on next loop-iteration + if (!ret.done) { + iterators.push(iter); + } + next_val = token; + iterateOrQuit(iterate,/*now=*/false); + } + else { + // not a recognized ASQ instance returned? + if (!ASQ.isSequence(ret.value)) { + // received a thenable/promise back? + if (isPromise(ret.value)) { + // wrap in a sequence + ret.value = ASQ().promise(ret.value); + } + // thunk yielded? + else if (typeof ret.value === "function") { + // wrap thunk call in a sequence + var fn = ret.value; + ret.value = ASQ(function $$ASQ(done){ + fn(done.errfcb); + }); + } + // message wrapper returned? + else if (ASQ.isMessageWrapper(ret.value)) { + // wrap message(s) in a sequence + ret.value = ASQ.apply(ø, + // don't let `apply(..)` discard an empty message + // wrapper! instead, pass it along as its own value + // itself. + ret.value.length > 0 ? ret.value : ASQ.messages(undefined) + ); + } + // non-undefined value returned? + else if (typeof ret.value !== "undefined") { + // wrap the value in a sequence + ret.value = ASQ(ret.value); + } + else { + // make an empty sequence + ret.value = ASQ(); + } + } + + ret.value + .val(function $$val(){ + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + if (arguments.length > 0) { + // save any return messages for input + // to next iteration + next_val = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + } + + // still more to iterate? + if (!ret.done) { + // was the control token passed along? + if (next_val === token) { + // round-robin: put co-routine back into the list + // at the end, so that the the next iterator can be + // processed on next loop-iteration + iterators.push(iter); + } + else { + // put co-routine back in where it just + // was so it can be processed again on + // next loop-iteration + iterators.unshift(iter); + } + } + + iterateOrQuit(iterate,/*now=*/true); + }) + .or(function $$or(){ + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + try { + // if an error occurs in the step-continuation + // promise or sequence, throw it back into the + // generator or iterable-sequence + iter["throw"].apply(iter,arguments); + } + catch (err) { + // if an error comes back out of after the throw, + // pass it out to the main sequence, as iteration + // must now be complete + mainDone.fail(err); + } + }); + } + })(); + }); + + return api; + }; +}); +// "toPromise" +ASQ.extend("toPromise",function $$extend(api,internals){ + return function $$to$promise() { + return new Promise(function $$executor(resolve,reject){ + api + .val(function $$val(){ + var args = ARRAY_SLICE.call(arguments); + resolve.call(ø,args.length > 1 ? args : args[0]); + return ASQ.messages.apply(ø,args); + }) + .or(function $$or(){ + var args = ARRAY_SLICE.call(arguments); + reject.call(ø,args.length > 1 ? args : args[0]); + }); + }); + }; +}); +// "try" +ASQ.extend("try",function $$extend(api,internals){ + return function $$try() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(fn){ + return function $$then(mainDone) { + var main_args = ARRAY_SLICE.call(arguments), + sq = ASQ.apply(ø,main_args.slice(1)) + ; + + sq + .then(function $$inner$then(){ + fn.apply(ø,arguments); + }) + .val(function $$val(){ + mainDone.apply(ø,arguments); + }) + .or(function $$inner$or(){ + var msgs = ASQ.messages.apply(ø,arguments); + // failed, so map error(s) as `catch` + mainDone({ + "catch": msgs.length > 1 ? msgs : msgs[0] + }); + }); + }; + }); + + api.then.apply(ø,fns); + + return api; + }; +}); +// "until" +ASQ.extend("until",function $$extend(api,internals){ + return function $$until() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(fn){ + return function $$then(mainDone) { + var main_args = ARRAY_SLICE.call(arguments), + sq = ASQ.apply(ø,main_args.slice(1)) + ; + + sq + .then(function $$inner$then(){ + var args = ARRAY_SLICE.call(arguments); + args[0]["break"] = function $$break(){ + mainDone.fail.apply(ø,arguments); + sq.abort(); + }; + + fn.apply(ø,args); + }) + .val(function $$val(){ + mainDone.apply(ø,arguments); + }) + .or(function $$inner$or(){ + // failed, retry + $$then.apply(ø,main_args); + }); + }; + }); + + api.then.apply(ø,fns); + + return api; + }; +}); +// "waterfall" +ASQ.extend("waterfall",function $$extend(api,internals){ + return function $$waterfall() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + var msgs = ASQ.messages(), + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + fns.forEach(function $$each(fn){ + sq.then(fn) + .val(function $$val(){ + var args = ASQ.messages.apply(ø,arguments); + msgs.push(args.length > 1 ? args : args[0]); + return msgs; + }); + }); + + sq.pipe(done); + }); + + return api; + }; +}); +// "wrap" +ASQ.wrap = function $$wrap(fn,opts) { + function checkThis(t,o) { + return (!t || + (typeof window != "undefined" && t === window) || + (typeof global != "undefined" && t === global) + ) ? o : t; + } + + function paramSpread(gen) { + return function *paramSpread(token) { + yield *gen.apply(this,token.messages); + }; + } + + var errfcb, params_first, act, this_obj; + + opts = (opts && typeof opts == "object") ? opts : {}; + + if ( + (opts.errfcb && opts.splitcb) || + (opts.errfcb && opts.simplecb) || + (opts.splitcb && opts.simplecb) || + ("errfcb" in opts && !opts.errfcb && !opts.splitcb && !opts.simplecb) || + (opts.params_first && opts.params_last) || + (opts.spread && !opts.gen) + ) { + throw Error("Invalid options"); + } + + // initialize default flags + this_obj = (opts["this"] && typeof opts["this"] == "object") ? opts["this"] : ø; + errfcb = opts.errfcb || !(opts.splitcb || opts.simplecb); + params_first = !!opts.params_first || + (!opts.params_last && !("params_first" in opts || opts.params_first)) || + ("params_last" in opts && !opts.params_first && !opts.params_last) + ; + + if (params_first) { + act = "push"; + } + else { + act = "unshift"; + } + + if (opts.gen) { + if (opts.spread) { + fn = paramSpread(fn); + } + return function $$wrapped$gen() { + return ASQ.apply(ø,arguments).runner(fn); + }; + } + if (errfcb) { + return function $$wrapped$errfcb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done.errfcb); + fn.apply(_this,args); + }); + }; + } + if (opts.splitcb) { + return function $$wrapped$splitcb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done,done.fail); + fn.apply(_this,args); + }); + }; + } + if (opts.simplecb) { + return function $$wrapped$simplecb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done); + fn.apply(_this,args); + }); + }; + } +}; + + + // just return `ASQ` itself for convenience sake + return ASQ; +}); diff --git a/frontend-masters-exercises/exercises/ex9/browser-polyfill.min.js b/frontend-masters-exercises/exercises/ex9/browser-polyfill.min.js new file mode 100755 index 0000000..f0683c2 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex9/browser-polyfill.min.js @@ -0,0 +1,3 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;oindex){value=O[index++];if(value!=value)return true}else for(;length>index;index++)if(IS_INCLUDES||index in O){if(O[index]===el)return IS_INCLUDES||index}return!IS_INCLUDES&&-1}}},{"./$":24}],4:[function(require,module,exports){var $=require("./$"),ctx=require("./$.ctx");module.exports=function(TYPE){var IS_MAP=TYPE==1,IS_FILTER=TYPE==2,IS_SOME=TYPE==3,IS_EVERY=TYPE==4,IS_FIND_INDEX=TYPE==6,NO_HOLES=TYPE==5||IS_FIND_INDEX;return function($this,callbackfn,that){var O=Object($.assertDefined($this)),self=$.ES5Object(O),f=ctx(callbackfn,that,3),length=$.toLength(self.length),index=0,result=IS_MAP?Array(length):IS_FILTER?[]:undefined,val,res;for(;length>index;index++)if(NO_HOLES||index in self){val=self[index];res=f(val,index,O);if(TYPE){if(IS_MAP)result[index]=res;else if(res)switch(TYPE){case 3:return true;case 5:return val;case 6:return index;case 2:result.push(val)}else if(IS_EVERY)return false}}return IS_FIND_INDEX?-1:IS_SOME||IS_EVERY?IS_EVERY:result}}},{"./$":24,"./$.ctx":12}],5:[function(require,module,exports){var $=require("./$");function assert(condition,msg1,msg2){if(!condition)throw TypeError(msg2?msg1+msg2:msg1)}assert.def=$.assertDefined;assert.fn=function(it){if(!$.isFunction(it))throw TypeError(it+" is not a function!");return it};assert.obj=function(it){if(!$.isObject(it))throw TypeError(it+" is not an object!");return it};assert.inst=function(it,Constructor,name){if(!(it instanceof Constructor))throw TypeError(name+": use the 'new' operator!");return it};module.exports=assert},{"./$":24}],6:[function(require,module,exports){var $=require("./$"),enumKeys=require("./$.enum-keys");module.exports=Object.assign||function assign(target,source){var T=Object($.assertDefined(target)),l=arguments.length,i=1;while(l>i){var S=$.ES5Object(arguments[i++]),keys=enumKeys(S),length=keys.length,j=0,key;while(length>j)T[key=keys[j++]]=S[key]}return T}},{"./$":24,"./$.enum-keys":15}],7:[function(require,module,exports){var $=require("./$"),TAG=require("./$.wks")("toStringTag"),toString={}.toString;function cof(it){return toString.call(it).slice(8,-1)}cof.classof=function(it){var O,T;return it==undefined?it===undefined?"Undefined":"Null":typeof(T=(O=Object(it))[TAG])=="string"?T:cof(O)};cof.set=function(it,tag,stat){if(it&&!$.has(it=stat?it:it.prototype,TAG))$.hide(it,TAG,tag)};module.exports=cof},{"./$":24,"./$.wks":42}],8:[function(require,module,exports){"use strict";var $=require("./$"),ctx=require("./$.ctx"),safe=require("./$.uid").safe,assert=require("./$.assert"),forOf=require("./$.for-of"),step=require("./$.iter").step,$has=$.has,set=$.set,isObject=$.isObject,hide=$.hide,isExtensible=Object.isExtensible||isObject,ID=safe("id"),O1=safe("O1"),LAST=safe("last"),FIRST=safe("first"),ITER=safe("iter"),SIZE=$.DESC?safe("size"):"size",id=0;function fastKey(it,create){if(!isObject(it))return typeof it=="symbol"?it:(typeof it=="string"?"S":"P")+it;if(!$has(it,ID)){if(!isExtensible(it))return"F";if(!create)return"E";hide(it,ID,++id)}return"O"+it[ID]}function getEntry(that,key){var index=fastKey(key),entry;if(index!=="F")return that[O1][index];for(entry=that[FIRST];entry;entry=entry.n){if(entry.k==key)return entry}}module.exports={getConstructor:function(wrapper,NAME,IS_MAP,ADDER){var C=wrapper(function(that,iterable){assert.inst(that,C,NAME);set(that,O1,$.create(null));set(that,SIZE,0);set(that,LAST,undefined);set(that,FIRST,undefined);if(iterable!=undefined)forOf(iterable,IS_MAP,that[ADDER],that)});require("./$.mix")(C.prototype,{clear:function clear(){for(var that=this,data=that[O1],entry=that[FIRST];entry;entry=entry.n){entry.r=true;if(entry.p)entry.p=entry.p.n=undefined;delete data[entry.i]}that[FIRST]=that[LAST]=undefined;that[SIZE]=0},"delete":function(key){var that=this,entry=getEntry(that,key);if(entry){var next=entry.n,prev=entry.p;delete that[O1][entry.i];entry.r=true;if(prev)prev.n=next;if(next)next.p=prev;if(that[FIRST]==entry)that[FIRST]=next;if(that[LAST]==entry)that[LAST]=prev;that[SIZE]--}return!!entry},forEach:function forEach(callbackfn){var f=ctx(callbackfn,arguments[1],3),entry;while(entry=entry?entry.n:this[FIRST]){f(entry.v,entry.k,this);while(entry&&entry.r)entry=entry.p}},has:function has(key){return!!getEntry(this,key)}});if($.DESC)$.setDesc(C.prototype,"size",{get:function(){return assert.def(this[SIZE])}});return C},def:function(that,key,value){var entry=getEntry(that,key),prev,index;if(entry){entry.v=value}else{that[LAST]=entry={i:index=fastKey(key,true),k:key,v:value,p:prev=that[LAST],n:undefined,r:false};if(!that[FIRST])that[FIRST]=entry;if(prev)prev.n=entry;that[SIZE]++;if(index!=="F")that[O1][index]=entry}return that},getEntry:getEntry,setIter:function(C,NAME,IS_MAP){require("./$.iter-define")(C,NAME,function(iterated,kind){set(this,ITER,{o:iterated,k:kind})},function(){var iter=this[ITER],kind=iter.k,entry=iter.l;while(entry&&entry.r)entry=entry.p;if(!iter.o||!(iter.l=entry=entry?entry.n:iter.o[FIRST])){iter.o=undefined;return step(1)}if(kind=="keys")return step(0,entry.k);if(kind=="values")return step(0,entry.v);return step(0,[entry.k,entry.v])},IS_MAP?"entries":"values",!IS_MAP,true)}}},{"./$":24,"./$.assert":5,"./$.ctx":12,"./$.for-of":16,"./$.iter":23,"./$.iter-define":21,"./$.mix":26,"./$.uid":40}],9:[function(require,module,exports){var $def=require("./$.def"),forOf=require("./$.for-of");module.exports=function(NAME){$def($def.P,NAME,{toJSON:function toJSON(){var arr=[];forOf(this,false,arr.push,arr);return arr}})}},{"./$.def":13,"./$.for-of":16}],10:[function(require,module,exports){"use strict";var $=require("./$"),safe=require("./$.uid").safe,assert=require("./$.assert"),forOf=require("./$.for-of"),$has=$.has,isObject=$.isObject,hide=$.hide,isExtensible=Object.isExtensible||isObject,id=0,ID=safe("id"),WEAK=safe("weak"),LEAK=safe("leak"),method=require("./$.array-methods"),find=method(5),findIndex=method(6);function findFrozen(store,key){return find(store.array,function(it){return it[0]===key})}function leakStore(that){return that[LEAK]||hide(that,LEAK,{array:[],get:function(key){var entry=findFrozen(this,key);if(entry)return entry[1]},has:function(key){return!!findFrozen(this,key)},set:function(key,value){var entry=findFrozen(this,key);if(entry)entry[1]=value;else this.array.push([key,value])},"delete":function(key){var index=findIndex(this.array,function(it){return it[0]===key});if(~index)this.array.splice(index,1);return!!~index}})[LEAK]}module.exports={getConstructor:function(wrapper,NAME,IS_MAP,ADDER){var C=wrapper(function(that,iterable){$.set(assert.inst(that,C,NAME),ID,id++);if(iterable!=undefined)forOf(iterable,IS_MAP,that[ADDER],that)});require("./$.mix")(C.prototype,{"delete":function(key){if(!isObject(key))return false;if(!isExtensible(key))return leakStore(this)["delete"](key);return $has(key,WEAK)&&$has(key[WEAK],this[ID])&&delete key[WEAK][this[ID]]},has:function has(key){if(!isObject(key))return false;if(!isExtensible(key))return leakStore(this).has(key);return $has(key,WEAK)&&$has(key[WEAK],this[ID])}});return C},def:function(that,key,value){if(!isExtensible(assert.obj(key))){leakStore(that).set(key,value)}else{$has(key,WEAK)||hide(key,WEAK,{});key[WEAK][that[ID]]=value}return that},leakStore:leakStore,WEAK:WEAK,ID:ID}},{"./$":24,"./$.array-methods":4,"./$.assert":5,"./$.for-of":16,"./$.mix":26,"./$.uid":40}],11:[function(require,module,exports){"use strict";var $=require("./$"),$def=require("./$.def"),BUGGY=require("./$.iter").BUGGY,forOf=require("./$.for-of"),species=require("./$.species"),assertInstance=require("./$.assert").inst;module.exports=function(NAME,wrapper,methods,common,IS_MAP,IS_WEAK){var Base=$.g[NAME],C=Base,ADDER=IS_MAP?"set":"add",proto=C&&C.prototype,O={};function fixMethod(KEY){var fn=proto[KEY];require("./$.redef")(proto,KEY,KEY=="delete"?function(a){return fn.call(this,a===0?0:a)}:KEY=="has"?function has(a){return fn.call(this,a===0?0:a)}:KEY=="get"?function get(a){return fn.call(this,a===0?0:a)}:KEY=="add"?function add(a){fn.call(this,a===0?0:a);return this}:function set(a,b){fn.call(this,a===0?0:a,b);return this})}if(!$.isFunction(C)||!(IS_WEAK||!BUGGY&&proto.forEach&&proto.entries)){C=common.getConstructor(wrapper,NAME,IS_MAP,ADDER);require("./$.mix")(C.prototype,methods)}else{var inst=new C,chain=inst[ADDER](IS_WEAK?{}:-0,1),buggyZero;if(!require("./$.iter-detect")(function(iter){new C(iter)})){C=wrapper(function(target,iterable){assertInstance(target,C,NAME);var that=new Base;if(iterable!=undefined)forOf(iterable,IS_MAP,that[ADDER],that);return that});C.prototype=proto;proto.constructor=C}IS_WEAK||inst.forEach(function(val,key){buggyZero=1/key===-Infinity});if(buggyZero){fixMethod("delete");fixMethod("has");IS_MAP&&fixMethod("get")}if(buggyZero||chain!==inst)fixMethod(ADDER)}require("./$.cof").set(C,NAME);O[NAME]=C;$def($def.G+$def.W+$def.F*(C!=Base),O);species(C);species($.core[NAME]);if(!IS_WEAK)common.setIter(C,NAME,IS_MAP);return C}},{"./$":24,"./$.assert":5,"./$.cof":7,"./$.def":13,"./$.for-of":16,"./$.iter":23,"./$.iter-detect":22,"./$.mix":26,"./$.redef":29,"./$.species":34}],12:[function(require,module,exports){var assertFunction=require("./$.assert").fn;module.exports=function(fn,that,length){assertFunction(fn);if(~length&&that===undefined)return fn;switch(length){case 1:return function(a){return fn.call(that,a)};case 2:return function(a,b){return fn.call(that,a,b)};case 3:return function(a,b,c){return fn.call(that,a,b,c)}}return function(){return fn.apply(that,arguments)}}},{"./$.assert":5}],13:[function(require,module,exports){var $=require("./$"),global=$.g,core=$.core,isFunction=$.isFunction,$redef=require("./$.redef");function ctx(fn,that){return function(){return fn.apply(that,arguments)}}global.core=core;$def.F=1;$def.G=2;$def.S=4;$def.P=8;$def.B=16;$def.W=32;function $def(type,name,source){var key,own,out,exp,isGlobal=type&$def.G,isProto=type&$def.P,target=isGlobal?global:type&$def.S?global[name]:(global[name]||{}).prototype,exports=isGlobal?core:core[name]||(core[name]={});if(isGlobal)source=name;for(key in source){own=!(type&$def.F)&&target&&key in target;out=(own?target:source)[key];if(type&$def.B&&own)exp=ctx(out,global);else exp=isProto&&isFunction(out)?ctx(Function.call,out):out;if(target&&!own)$redef(target,key,out);if(exports[key]!=out)$.hide(exports,key,exp);if(isProto)(exports.prototype||(exports.prototype={}))[key]=out}}module.exports=$def},{"./$":24,"./$.redef":29}],14:[function(require,module,exports){var $=require("./$"),document=$.g.document,isObject=$.isObject,is=isObject(document)&&isObject(document.createElement);module.exports=function(it){return is?document.createElement(it):{}}},{"./$":24}],15:[function(require,module,exports){var $=require("./$");module.exports=function(it){var keys=$.getKeys(it),getDesc=$.getDesc,getSymbols=$.getSymbols;if(getSymbols)$.each.call(getSymbols(it),function(key){if(getDesc(it,key).enumerable)keys.push(key)});return keys}},{"./$":24}],16:[function(require,module,exports){var ctx=require("./$.ctx"),get=require("./$.iter").get,call=require("./$.iter-call");module.exports=function(iterable,entries,fn,that){var iterator=get(iterable),f=ctx(fn,that,entries?2:1),step;while(!(step=iterator.next()).done){if(call(iterator,f,step.value,entries)===false){return call.close(iterator)}}}},{"./$.ctx":12,"./$.iter":23,"./$.iter-call":20}],17:[function(require,module,exports){module.exports=function($){$.FW=true;$.path=$.g;return $}},{}],18:[function(require,module,exports){var $=require("./$"),toString={}.toString,getNames=$.getNames;var windowNames=typeof window=="object"&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[];function getWindowNames(it){try{return getNames(it)}catch(e){return windowNames.slice()}}module.exports.get=function getOwnPropertyNames(it){if(windowNames&&toString.call(it)=="[object Window]")return getWindowNames(it);return getNames($.toObject(it))}},{"./$":24}],19:[function(require,module,exports){module.exports=function(fn,args,that){var un=that===undefined;switch(args.length){case 0:return un?fn():fn.call(that);case 1:return un?fn(args[0]):fn.call(that,args[0]);case 2:return un?fn(args[0],args[1]):fn.call(that,args[0],args[1]);case 3:return un?fn(args[0],args[1],args[2]):fn.call(that,args[0],args[1],args[2]);case 4:return un?fn(args[0],args[1],args[2],args[3]):fn.call(that,args[0],args[1],args[2],args[3]);case 5:return un?fn(args[0],args[1],args[2],args[3],args[4]):fn.call(that,args[0],args[1],args[2],args[3],args[4])}return fn.apply(that,args)}},{}],20:[function(require,module,exports){var assertObject=require("./$.assert").obj;function close(iterator){var ret=iterator["return"];if(ret!==undefined)assertObject(ret.call(iterator))}function call(iterator,fn,value,entries){try{return entries?fn(assertObject(value)[0],value[1]):fn(value)}catch(e){close(iterator);throw e}}call.close=close;module.exports=call},{"./$.assert":5}],21:[function(require,module,exports){var $def=require("./$.def"),$redef=require("./$.redef"),$=require("./$"),cof=require("./$.cof"),$iter=require("./$.iter"),SYMBOL_ITERATOR=require("./$.wks")("iterator"),FF_ITERATOR="@@iterator",KEYS="keys",VALUES="values",Iterators=$iter.Iterators;module.exports=function(Base,NAME,Constructor,next,DEFAULT,IS_SET,FORCE){$iter.create(Constructor,NAME,next);function createMethod(kind){function $$(that){return new Constructor(that,kind)}switch(kind){case KEYS:return function keys(){return $$(this)};case VALUES:return function values(){return $$(this)}}return function entries(){return $$(this)}}var TAG=NAME+" Iterator",proto=Base.prototype,_native=proto[SYMBOL_ITERATOR]||proto[FF_ITERATOR]||DEFAULT&&proto[DEFAULT],_default=_native||createMethod(DEFAULT),methods,key;if(_native){var IteratorPrototype=$.getProto(_default.call(new Base));cof.set(IteratorPrototype,TAG,true);if($.FW&&$.has(proto,FF_ITERATOR))$iter.set(IteratorPrototype,$.that)}if($.FW||FORCE)$iter.set(proto,_default);Iterators[NAME]=_default;Iterators[TAG]=$.that;if(DEFAULT){methods={keys:IS_SET?_default:createMethod(KEYS),values:DEFAULT==VALUES?_default:createMethod(VALUES),entries:DEFAULT!=VALUES?_default:createMethod("entries")};if(FORCE)for(key in methods){if(!(key in proto))$redef(proto,key,methods[key])}else $def($def.P+$def.F*$iter.BUGGY,NAME,methods)}}},{"./$":24,"./$.cof":7,"./$.def":13,"./$.iter":23,"./$.redef":29,"./$.wks":42}],22:[function(require,module,exports){var SYMBOL_ITERATOR=require("./$.wks")("iterator"),SAFE_CLOSING=false;try{var riter=[7][SYMBOL_ITERATOR]();riter["return"]=function(){SAFE_CLOSING=true};Array.from(riter,function(){throw 2})}catch(e){}module.exports=function(exec){if(!SAFE_CLOSING)return false;var safe=false;try{var arr=[7],iter=arr[SYMBOL_ITERATOR]();iter.next=function(){safe=true};arr[SYMBOL_ITERATOR]=function(){return iter};exec(arr)}catch(e){}return safe}},{"./$.wks":42}],23:[function(require,module,exports){"use strict";var $=require("./$"),cof=require("./$.cof"),classof=cof.classof,assert=require("./$.assert"),assertObject=assert.obj,SYMBOL_ITERATOR=require("./$.wks")("iterator"),FF_ITERATOR="@@iterator",Iterators=require("./$.shared")("iterators"),IteratorPrototype={};setIterator(IteratorPrototype,$.that);function setIterator(O,value){$.hide(O,SYMBOL_ITERATOR,value);if(FF_ITERATOR in[])$.hide(O,FF_ITERATOR,value)}module.exports={BUGGY:"keys"in[]&&!("next"in[].keys()),Iterators:Iterators,step:function(done,value){return{value:value,done:!!done}},is:function(it){var O=Object(it),Symbol=$.g.Symbol;return(Symbol&&Symbol.iterator||FF_ITERATOR)in O||SYMBOL_ITERATOR in O||$.has(Iterators,classof(O))},get:function(it){var Symbol=$.g.Symbol,getIter;if(it!=undefined){getIter=it[Symbol&&Symbol.iterator||FF_ITERATOR]||it[SYMBOL_ITERATOR]||Iterators[classof(it)]}assert($.isFunction(getIter),it," is not iterable!");return assertObject(getIter.call(it))},set:setIterator,create:function(Constructor,NAME,next,proto){Constructor.prototype=$.create(proto||IteratorPrototype,{next:$.desc(1,next)});cof.set(Constructor,NAME+" Iterator")}}},{"./$":24,"./$.assert":5,"./$.cof":7,"./$.shared":33,"./$.wks":42}],24:[function(require,module,exports){"use strict";var global=typeof self!="undefined"?self:Function("return this")(),core={},defineProperty=Object.defineProperty,hasOwnProperty={}.hasOwnProperty,ceil=Math.ceil,floor=Math.floor,max=Math.max,min=Math.min;var DESC=!!function(){try{return defineProperty({},"a",{get:function(){return 2}}).a==2}catch(e){}}();var hide=createDefiner(1);function toInteger(it){return isNaN(it=+it)?0:(it>0?floor:ceil)(it)}function desc(bitmap,value){return{enumerable:!(bitmap&1),configurable:!(bitmap&2),writable:!(bitmap&4),value:value}}function simpleSet(object,key,value){object[key]=value;return object}function createDefiner(bitmap){return DESC?function(object,key,value){return $.setDesc(object,key,desc(bitmap,value))}:simpleSet}function isObject(it){return it!==null&&(typeof it=="object"||typeof it=="function")}function isFunction(it){return typeof it=="function"}function assertDefined(it){if(it==undefined)throw TypeError("Can't call method on "+it);return it}var $=module.exports=require("./$.fw")({g:global,core:core,html:global.document&&document.documentElement,isObject:isObject,isFunction:isFunction,that:function(){return this},toInteger:toInteger,toLength:function(it){return it>0?min(toInteger(it),9007199254740991):0},toIndex:function(index,length){index=toInteger(index);return index<0?max(index+length,0):min(index,length)},has:function(it,key){return hasOwnProperty.call(it,key)},create:Object.create,getProto:Object.getPrototypeOf,DESC:DESC,desc:desc,getDesc:Object.getOwnPropertyDescriptor,setDesc:defineProperty,setDescs:Object.defineProperties,getKeys:Object.keys,getNames:Object.getOwnPropertyNames,getSymbols:Object.getOwnPropertySymbols,assertDefined:assertDefined,ES5Object:Object,toObject:function(it){return $.ES5Object(assertDefined(it))},hide:hide,def:createDefiner(0),set:global.Symbol?simpleSet:hide,each:[].forEach});if(typeof __e!="undefined")__e=core;if(typeof __g!="undefined")__g=global},{"./$.fw":17}],25:[function(require,module,exports){var $=require("./$");module.exports=function(object,el){var O=$.toObject(object),keys=$.getKeys(O),length=keys.length,index=0,key;while(length>index)if(O[key=keys[index++]]===el)return key}},{"./$":24}],26:[function(require,module,exports){var $redef=require("./$.redef");module.exports=function(target,src){for(var key in src)$redef(target,key,src[key]);return target}},{"./$.redef":29}],27:[function(require,module,exports){var $=require("./$"),assertObject=require("./$.assert").obj;module.exports=function ownKeys(it){assertObject(it);var keys=$.getNames(it),getSymbols=$.getSymbols;return getSymbols?keys.concat(getSymbols(it)):keys}},{"./$":24,"./$.assert":5}],28:[function(require,module,exports){"use strict";var $=require("./$"),invoke=require("./$.invoke"),assertFunction=require("./$.assert").fn;module.exports=function(){var fn=assertFunction(this),length=arguments.length,pargs=Array(length),i=0,_=$.path._,holder=false;while(length>i)if((pargs[i]=arguments[i++])===_)holder=true;return function(){var that=this,_length=arguments.length,j=0,k=0,args;if(!holder&&!_length)return invoke(fn,pargs,that);args=pargs.slice();if(holder)for(;length>j;j++)if(args[j]===_)args[j]=arguments[k++];while(_length>k)args.push(arguments[k++]);return invoke(fn,args,that)}}},{"./$":24,"./$.assert":5,"./$.invoke":19}],29:[function(require,module,exports){var $=require("./$"),tpl=String({}.hasOwnProperty),SRC=require("./$.uid").safe("src"),_toString=Function.toString;function $redef(O,key,val,safe){if($.isFunction(val)){var base=O[key];$.hide(val,SRC,base?String(base):tpl.replace(/hasOwnProperty/,String(key)));if(!("name"in val))val.name=key}if(O===$.g){O[key]=val}else{if(!safe)delete O[key];$.hide(O,key,val)}}$redef(Function.prototype,"toString",function toString(){return $.has(this,SRC)?this[SRC]:_toString.call(this)});$.core.inspectSource=function(it){return _toString.call(it)};module.exports=$redef},{"./$":24,"./$.uid":40}],30:[function(require,module,exports){"use strict";module.exports=function(regExp,replace,isStatic){var replacer=replace===Object(replace)?function(part){return replace[part]}:replace;return function(it){return String(isStatic?it:this).replace(regExp,replacer)}}},{}],31:[function(require,module,exports){module.exports=Object.is||function is(x,y){return x===y?x!==0||1/x===1/y:x!=x&&y!=y}},{}],32:[function(require,module,exports){var $=require("./$"),assert=require("./$.assert");function check(O,proto){assert.obj(O);assert(proto===null||$.isObject(proto),proto,": can't set as prototype!")}module.exports={set:Object.setPrototypeOf||("__proto__"in{}?function(buggy,set){try{set=require("./$.ctx")(Function.call,$.getDesc(Object.prototype,"__proto__").set,2);set({},[])}catch(e){buggy=true}return function setPrototypeOf(O,proto){check(O,proto);if(buggy)O.__proto__=proto;else set(O,proto);return O}}():undefined),check:check}},{"./$":24,"./$.assert":5,"./$.ctx":12}],33:[function(require,module,exports){var $=require("./$"),SHARED="__core-js_shared__",store=$.g[SHARED]||($.g[SHARED]={});module.exports=function(key){return store[key]||(store[key]={})}},{"./$":24}],34:[function(require,module,exports){var $=require("./$"),SPECIES=require("./$.wks")("species");module.exports=function(C){if($.DESC&&!(SPECIES in C))$.setDesc(C,SPECIES,{configurable:true,get:$.that})}},{"./$":24,"./$.wks":42}],35:[function(require,module,exports){var $=require("./$");module.exports=function(TO_STRING){return function(that,pos){var s=String($.assertDefined(that)),i=$.toInteger(pos),l=s.length,a,b;if(i<0||i>=l)return TO_STRING?"":undefined;a=s.charCodeAt(i);return a<55296||a>56319||i+1===l||(b=s.charCodeAt(i+1))<56320||b>57343?TO_STRING?s.charAt(i):a:TO_STRING?s.slice(i,i+2):(a-55296<<10)+(b-56320)+65536}}},{"./$":24}],36:[function(require,module,exports){var $=require("./$"),repeat=require("./$.string-repeat");module.exports=function(that,minLength,fillChar,left){var S=String($.assertDefined(that));if(minLength===undefined)return S;var intMinLength=$.toInteger(minLength);var fillLen=intMinLength-S.length;if(fillLen<0||fillLen===Infinity){throw new RangeError("Cannot satisfy string length "+minLength+" for string: "+S)}var sFillStr=fillChar===undefined?" ":String(fillChar);var sFillVal=repeat.call(sFillStr,Math.ceil(fillLen/sFillStr.length));if(sFillVal.length>fillLen)sFillVal=left?sFillVal.slice(sFillVal.length-fillLen):sFillVal.slice(0,fillLen);return left?sFillVal.concat(S):S.concat(sFillVal)}},{"./$":24,"./$.string-repeat":37}],37:[function(require,module,exports){"use strict";var $=require("./$");module.exports=function repeat(count){var str=String($.assertDefined(this)),res="",n=$.toInteger(count);if(n<0||n==Infinity)throw RangeError("Count can't be negative");for(;n>0;(n>>>=1)&&(str+=str))if(n&1)res+=str;return res}},{"./$":24}],38:[function(require,module,exports){"use strict";var $=require("./$"),ctx=require("./$.ctx"),cof=require("./$.cof"),invoke=require("./$.invoke"),cel=require("./$.dom-create"),global=$.g,isFunction=$.isFunction,html=$.html,process=global.process,setTask=global.setImmediate,clearTask=global.clearImmediate,MessageChannel=global.MessageChannel,counter=0,queue={},ONREADYSTATECHANGE="onreadystatechange",defer,channel,port;function run(){var id=+this;if($.has(queue,id)){var fn=queue[id];delete queue[id];fn()}}function listner(event){run.call(event.data)}if(!isFunction(setTask)||!isFunction(clearTask)){setTask=function(fn){var args=[],i=1;while(arguments.length>i)args.push(arguments[i++]);queue[++counter]=function(){invoke(isFunction(fn)?fn:Function(fn),args)};defer(counter);return counter};clearTask=function(id){delete queue[id]};if(cof(process)=="process"){defer=function(id){process.nextTick(ctx(run,id,1))}}else if(global.addEventListener&&isFunction(global.postMessage)&&!global.importScripts){defer=function(id){global.postMessage(id,"*")};global.addEventListener("message",listner,false)}else if(isFunction(MessageChannel)){channel=new MessageChannel;port=channel.port2;channel.port1.onmessage=listner;defer=ctx(port.postMessage,port,1)}else if(ONREADYSTATECHANGE in cel("script")){defer=function(id){html.appendChild(cel("script"))[ONREADYSTATECHANGE]=function(){html.removeChild(this);run.call(id)}}}else{defer=function(id){setTimeout(ctx(run,id,1),0)}}}module.exports={set:setTask,clear:clearTask}},{"./$":24,"./$.cof":7,"./$.ctx":12,"./$.dom-create":14,"./$.invoke":19}],39:[function(require,module,exports){module.exports=function(exec){try{exec();return false}catch(e){return true}}},{}],40:[function(require,module,exports){var sid=0;function uid(key){return"Symbol(".concat(key===undefined?"":key,")_",(++sid+Math.random()).toString(36))}uid.safe=require("./$").g.Symbol||uid;module.exports=uid},{"./$":24}],41:[function(require,module,exports){var UNSCOPABLES=require("./$.wks")("unscopables");if(!(UNSCOPABLES in[]))require("./$").hide(Array.prototype,UNSCOPABLES,{});module.exports=function(key){[][UNSCOPABLES][key]=true}},{"./$":24,"./$.wks":42}],42:[function(require,module,exports){var global=require("./$").g,store=require("./$.shared")("wks");module.exports=function(name){return store[name]||(store[name]=global.Symbol&&global.Symbol[name]||require("./$.uid").safe("Symbol."+name))}},{"./$":24,"./$.shared":33,"./$.uid":40}],43:[function(require,module,exports){var $=require("./$"),cel=require("./$.dom-create"),cof=require("./$.cof"),$def=require("./$.def"),invoke=require("./$.invoke"),arrayMethod=require("./$.array-methods"),IE_PROTO=require("./$.uid").safe("__proto__"),assert=require("./$.assert"),assertObject=assert.obj,ObjectProto=Object.prototype,html=$.html,A=[],_slice=A.slice,_join=A.join,classof=cof.classof,has=$.has,defineProperty=$.setDesc,getOwnDescriptor=$.getDesc,defineProperties=$.setDescs,isFunction=$.isFunction,isObject=$.isObject,toObject=$.toObject,toLength=$.toLength,toIndex=$.toIndex,IE8_DOM_DEFINE=false,$indexOf=require("./$.array-includes")(false),$forEach=arrayMethod(0),$map=arrayMethod(1),$filter=arrayMethod(2),$some=arrayMethod(3),$every=arrayMethod(4);if(!$.DESC){try{IE8_DOM_DEFINE=defineProperty(cel("div"),"x",{get:function(){return 8}}).x==8}catch(e){}$.setDesc=function(O,P,Attributes){if(IE8_DOM_DEFINE)try{return defineProperty(O,P,Attributes)}catch(e){}if("get"in Attributes||"set"in Attributes)throw TypeError("Accessors not supported!");if("value"in Attributes)assertObject(O)[P]=Attributes.value;return O};$.getDesc=function(O,P){if(IE8_DOM_DEFINE)try{return getOwnDescriptor(O,P)}catch(e){}if(has(O,P))return $.desc(!ObjectProto.propertyIsEnumerable.call(O,P),O[P])};$.setDescs=defineProperties=function(O,Properties){assertObject(O);var keys=$.getKeys(Properties),length=keys.length,i=0,P;while(length>i)$.setDesc(O,P=keys[i++],Properties[P]);return O}}$def($def.S+$def.F*!$.DESC,"Object",{getOwnPropertyDescriptor:$.getDesc,defineProperty:$.setDesc,defineProperties:defineProperties});var keys1=("constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,"+"toLocaleString,toString,valueOf").split(","),keys2=keys1.concat("length","prototype"),keysLen1=keys1.length;var createDict=function(){var iframe=cel("iframe"),i=keysLen1,gt=">",iframeDocument;iframe.style.display="none";html.appendChild(iframe);iframe.src="javascript:";iframeDocument=iframe.contentWindow.document;iframeDocument.open();iframeDocument.write(" + + + + + + + + diff --git a/frontend-masters-exercises/exercises/ex9/ex9-fixed.js b/frontend-masters-exercises/exercises/ex9/ex9-fixed.js new file mode 100755 index 0000000..fda200f --- /dev/null +++ b/frontend-masters-exercises/exercises/ex9/ex9-fixed.js @@ -0,0 +1,44 @@ +$(document).ready(function(){ + var $btn = $("#btn"), + $list = $("#list"), + clicks = ASQ.csp.chan(), + msgs = ASQ.csp.chan(), + queuedClick; + + $btn.click(listenToClicks); + + // run go-routines + ASQ().runner( + ASQ.csp.go(sampleClicks), + ASQ.csp.go(logClick) + ); + + // push click event messages into channel + function listenToClicks(evt){ + if (!queuedClick) { + queuedClick = ASQ.csp.putAsync(clicks,evt); + queuedClick.then(function(){ + queuedClick = null; + }); + } + } + + // sample clicks channel + function *sampleClicks() { + while (true) { + yield ASQ.csp.take( + ASQ.csp.timeout(1000) + ); + yield ASQ.csp.take(clicks); + yield ASQ.csp.put(msgs,"clicked!"); + } + } + + // subscribe to sampled message channel + function *logClick() { + while (true) { + var msg = yield ASQ.csp.take(msgs); + $list.append($("
" + msg + "
")); + } + } +}); diff --git a/frontend-masters-exercises/exercises/ex9/ex9.html b/frontend-masters-exercises/exercises/ex9/ex9.html new file mode 100755 index 0000000..d67db5e --- /dev/null +++ b/frontend-masters-exercises/exercises/ex9/ex9.html @@ -0,0 +1,18 @@ + + + + +Exercise 9 + + +

Exercise 9

+ +

+
+ + + + + + + diff --git a/frontend-masters-exercises/exercises/ex9/ex9.js b/frontend-masters-exercises/exercises/ex9/ex9.js new file mode 100755 index 0000000..b167571 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex9/ex9.js @@ -0,0 +1,11 @@ +$(document).ready(function(){ + var $btn = $("#btn"), + $list = $("#list"); + + $btn.click(/* TODO */); + + // Hint: ASQ().runner( .. ) + + // TODO: setup sampling go-routine and + // channel, populate $list +}); diff --git a/frontend-masters-exercises/exercises/ex9/jquery.js b/frontend-masters-exercises/exercises/ex9/jquery.js new file mode 100755 index 0000000..3883779 --- /dev/null +++ b/frontend-masters-exercises/exercises/ex9/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v1.8.3 jquery.com | jquery.org/license */ +(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write(""),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t
a",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="
t
",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="
",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;ti.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="
",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="

",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t0)for(i=r;i=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*\s*$/g,Nt={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X
","
"]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1>");try{for(;r1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]===""&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("
").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window); \ No newline at end of file diff --git a/promise-it-wont-hurt-solutions/src/01-warmup.js b/promise-it-wont-hurt-solutions/src/01-warmup.js index e69de29..db90508 100644 --- a/promise-it-wont-hurt-solutions/src/01-warmup.js +++ b/promise-it-wont-hurt-solutions/src/01-warmup.js @@ -0,0 +1,65 @@ +// Promise It Won’t Hurt +// ─────────────────────── +// Warm up +// Exercise 1 of 13 +// +// +// # What is a promise? +// +// One of the new features in ECMAScript 2015 (also called “ES6” and +// “Harmony”) is a new type of objects: promises. It extends the widely known +// Promise/A+ specification and standardizes it to be part of the language +// core. +// +// In its most basic terms, a promise is an object that defines a method called +// then. The promise object represents a value that may be available some time +// in the future. It greatly simplifies asynchronous logic in JavaScript. +// +// Compare the following code, written in the more traditional idiom of +// asynchronous callbacks, with no error handling: +// +// Parse.User.logIn('user', 'pass', { +// success: function (user) { +// query.find({ +// success: function (results) { +// results[0].save({ key: value }, { +// success: function (result) { +// // the object was saved +// } +// }); +// } +// }); +// } +// }); +// +// And the much more elegant Promise workflow, with first-class error handling: +// +// Parse.User.logIn('user', 'pass').then(function (user) { +// return query.find(); +// }).then(function (results) { +// return results[0].save({ key: value }); +// }).then(function (result) { +// // the object was saved +// }).catch(function (err) { +// // an error happened somewhere in the process +// }); +// +// Promises make writing performant, asynchronous code much easier and more fun. + + +// ## Task +// +// For this first lesson, let’s review what we already know about asynchronous +// operations in JavaScript. +// +// Using setTimeout, print the string 'TIMED OUT!' after 300ms. +// +// +// » To print these instructions again, run: promise-it-wont-hurt print +// » To execute your program in a test environment, run: promise-it-wont-hurt run program.js +// » To verify your program, run: promise-it-wont-hurt verify program.js +// » For help run: promise-it-wont-hurt help + +setTimeout(function() { + console.log("TIMED OUT!") +}), 300; diff --git a/promise-it-wont-hurt-solutions/src/02-fullfill-a-promise.js b/promise-it-wont-hurt-solutions/src/02-fullfill-a-promise.js index e69de29..c60ada3 100644 --- a/promise-it-wont-hurt-solutions/src/02-fullfill-a-promise.js +++ b/promise-it-wont-hurt-solutions/src/02-fullfill-a-promise.js @@ -0,0 +1,114 @@ +// # Fulfilling a Promise +// +// Promises have an important internal property: its state. A promise is one of: +// +// * fulfilled, +// * rejected, or +// * pending, which is the state of a promise waiting to be fulfilled or rejected. +// +// Sometimes you will also hear the term “resolved.” For now, you can treat it as +// meaning either fulfilled or rejected. + +// Most promises are created with new Promise(executor), in which executor is +// a callback function with the signature function (fulfill, reject). Inside +// executor, either fulfill or reject is called, to indicate the outcome of +// the operation. For promises, fulfilling means that the operation successfully +// completes and yields a value. In order to pass this value along, call fulfill +// function with this value as the first parameter. +// +// As mentioned in the last lesson, a promise has a then property function. It +// is the main way of manipulating promises and their values. It takes two +// optional callback parameters onFulfilled and onRejected: the first will be +// called when the promise is fulfilled, and the second when the promise is +// rejected. When the fulfill function is called in executor with a value, +// the promise internals pass it along, and then call this first callback with the +// same value. +// +// In practice, you can call the then property function multiple times, to do +// multiple things with the value of the promise. Or, more commonly, you could do +// them all in the same onFulfilled callback, which allows you to control more +// easily the logic flows. +// +// If you call fulfill function in executor without a parameter, the +// onFulfilled callback(s) will still be called, but the parameter to those +// callbacks will be undefined. +// +// We will talk about rejecting in our next lesson. +// +// ## Setup +// +// To use ES2015 Promises, you need either a JavaScript engine that supports it, +// or one of the many polyfills available. Node.js 0.12 or higher, and all +// versions of io.js, have native promise support. However, if you are stuck with +// an older version of Node.js, don’t fret: for this workshopper, a promise +// implementation will be automatically supplied if none is available. +// +// When writing your own code, we recommend using es6-promise polyfill, since it +// aims to be strictly compliant to ES2015 without any extra features. To use +// es6-promise, execute the following in a shell: +// +// npm install es6-promise +// +// Then, in the main file in your app, add the following line: +// +// require('es6-promise'); +// +// Now you can use ES2015 promises everywhere! + +// ## Task + +// Create a promise. Have it fulfilled with a value of 'FULFILLED!' in +// executor after a delay of 300ms, using setTimeout. +// +// Then, print the contents of the promise after if has been fulfilled by passing +// console.log to then. +// +// ## Boilerplate +// +// 'use strict'; +// +// var promise = new Promise(function (fulfill, reject) { +// // Your solution here +// }); +// +// // Your solution here +// +// +// » To print these instructions again, run: promise-it-wont-hurt print +// » To execute your program in a test environment, run: promise-it-wont-hurt run program.js +// » To verify your program, run: promise-it-wont-hurt verify program.js +// » For help run: promise-it-wont-hurt help + +//My solution + 'use strict'; + + var promise = new Promise(function (fulfill, reject) { + // Your solution here + setTimeout(function() { + fulfill("FULFILLED!") + },300); + }).then(function(value){ + console.log(value) + }) + // Your solution here + + +//Their solution +'use strict'; + +// Create a promise +var promise = new Promise(function (fulfill, reject) { + // After the timeout reaches 300ms, fulfill the promise with value + // 'FULFILLED!'. + + setTimeout(function () { + fulfill('FULFILLED!'); + }, 300); +}); + +// Add a handler to the promise’s fulfillment. `console.log` will be called +// with the value passed to `fulfill`, which is `'FULFILLED!'`. +// Note that this statement will ALWAYS be executed before `fulfill` is +// called (we'll talk about this in depth in the lessons to come). + +promise.then(console.log); diff --git a/promise-it-wont-hurt-solutions/src/03-reject-a-promise.js b/promise-it-wont-hurt-solutions/src/03-reject-a-promise.js index e69de29..2600db0 100644 --- a/promise-it-wont-hurt-solutions/src/03-reject-a-promise.js +++ b/promise-it-wont-hurt-solutions/src/03-reject-a-promise.js @@ -0,0 +1,73 @@ +// # Rejecting a Promise +// +// After the last session, you should be able to create a promise, fulfill it +// with a value, and read that value after the fulfillment of the promise. Now, +// not all promises result in a successful execution; some errors may have +// happened in the process. That's where promise rejection comes into play. +// +// When a promise is rejected, this is typically (though not always) used to +// indicate that a value was not successfully obtained by the promise. Promises +// provide a way to pass the specific error that prevents the successful +// execution. +// +// Once a promise has been rejected, it can never be fulfilled (nor rejected +// again). This aspect of promises will be explored deeper in the next lesson. +// // +// // ## Task +// // +// // Create a promise that after a delay of 300ms, rejects with an Error object. +// // The Error object should be constructed with parameter 'REJECTED!', which is +// // the textual message of the error. +// // +// // Create a function onReject to print error.message using console.log. Pass +// // this function as a rejection handler to the then method of your promise. +// // +// // ## Hint +// // +// // As a review from last lesson, a promise's then function takes two callbacks: +// the first to be called when the promise is fulfilled and the second when the +// promise is rejected. +// +// ## Boilerplate +// +// var promise = new Promise(function (fulfill, reject) { +// // Your solution here +// }); +// +// function onReject (error) { +// // Your solution here +// } +// +// // Your solution here +// +// +// » To print these instructions again, run: promise-it-wont-hurt print +// » To execute your program in a test environment, run: promise-it-wont-hurt run program.js +// » To verify your program, run: promise-it-wont-hurt verify program.js +// » For help run: promise-it-wont-hurt help + +//This solution throws a string instead of an error object +// var promise = new Promise(function (fulfill, reject) { +// setTimeout(function() { +// reject("REJECTED!") +// }, 300); +// }); +// +// function onReject (error) { +// console.log(error) +// } +// +// promise.then(null, onReject) + +//This is my solution and their solution +var promise = new Promise(function (fulfill, reject) { + setTimeout(function() { + reject(new Error("REJECTED!")) + }, 300); +}); + +function onReject (error) { + console.log(error.message) +} + +promise.then(null, onReject) diff --git a/promise-it-wont-hurt-solutions/src/04-to-reject-or-not-to-reject.js b/promise-it-wont-hurt-solutions/src/04-to-reject-or-not-to-reject.js index e69de29..109d0e8 100644 --- a/promise-it-wont-hurt-solutions/src/04-to-reject-or-not-to-reject.js +++ b/promise-it-wont-hurt-solutions/src/04-to-reject-or-not-to-reject.js @@ -0,0 +1,89 @@ +// # What happens if we reject AND resolve a promise? +// +// The ES2015 spec states that a promise, once fullfilled or rejected, may +// not change states for the rest of its lifetime. This is an important +// feature of promises and it is also one of the things that differentiates it +// from an EventEmitter (and other forms of repeatable callbacks). +// +// Callback-style code usually requires a callback function to be invoked +// somewhere in the body of the function that it was passed to. Many, if not +// most times, that function is intended to be called only once. However, through +// errors in logic, problems with syntax, or other simple mistakes it is +// possible to call your callback multiple times and create vexing states in your +// app or insidious bugs. + + /* + * This code is bad, but nonetheless common and has the nasty result of + * calling the supplied callback more than once (possibly destroying the + * earth?). It is conventional to return the first invocation of callback + * but it’s easy to overlook! + */ + + function myFunc(user, callback) { + if (user) { + callback(null, user); + } + + return callback('No user was found', null); + } + +// ## Task +// +// Let’s build a simple script to prove to ourselves that promises may only +// resolve one time and all future attempts to resolve them will simply be ignored. +// +// First, create a promise using the Promise constructor as we have been doing. +// +// In the promise’s executor, immediately attempt to fulfill the promise with a +// value of 'I FIRED'. +// +// Then, after the fulfill call, immediately try to reject the promise with an +// Error created with parameter 'I DID NOT FIRE'. +// +// After the promise creation, create a function onRejected with one parameter +// error that prints the Error’s message with console.log. +// +// Lastly, pass console.log and the function you just created as the success +// and rejection handlers respectively. +// +// If successful, your script should only log “I FIRED” and should not log +// “I DID NOT FIRE”. +// +// Note that unlike the prior exercises, you do not have to use setTimeout with +// this. + + + // » To print these instructions again, run: promise-it-wont-hurt print + // » To execute your program in a test environment, run: promise-it-wont-hurt run program.js + // » To verify your program, run: promise-it-wont-hurt verify program.js + // » For help run: promise-it-wont-hurt help + +//Another way of writing it +// var promise = new Promise(function (fulfill,reject) { +// fulfill("I FIRED") +// reject(new Error("I DID NOT FIRE")) +// }); +// +// function onRejected(error) { +// console.log(error) +// } +// +// promise.then(function(success, failure) { +// if (success) { +// console.log(success) +// } else { +// onRejected(failure) +// } +// }) + +//My solution and their solution +var promise = new Promise(function (fulfill,reject) { + fulfill("I FIRED") + reject(new Error("I DID NOT FIRE")) +}); + +function onRejected(error) { + console.log(error) +} + +promise.then(console.log, onRejected) diff --git a/promise-it-wont-hurt-solutions/src/05-always-asynchronous.js b/promise-it-wont-hurt-solutions/src/05-always-asynchronous.js index e69de29..2de0387 100644 --- a/promise-it-wont-hurt-solutions/src/05-always-asynchronous.js +++ b/promise-it-wont-hurt-solutions/src/05-always-asynchronous.js @@ -0,0 +1,51 @@ +// # Are promises always resolved asynchronously? +// +// The ES2015 spec declares that promises must not fire their +// resolution/rejection function on the same turn of the event loop that they are +// created on. This is very important because it eliminates the possibility of +// execution order varying and resulting in indeterminate outcomes. +// +// You can expect that the functions passed to the then method of a +// promise will be called on the next turn of the event loop. +// +// ## Task +// +// In this lesson, we are going to prove to ourselves that promises are always +// asynchronous. +// +// First, create a promise using the Promise constructor. +// +// In the promise’s executor, immediately fulfill the promise with a value of +// 'PROMISE VALUE'. +// +// After the creation of the promise, pass console.log as the success handler to +// the promise. +// +// Finally, print out “MAIN PROGRAM” with console.log. +// +// ## Hints +// +// If the execution of promise is synchronous, the value of the promise is already +// known after its construction. The console.log passed into then would then +// be executed as soon as the then is called. +// +// However, if your script is successful, you should see “MAIN PROGRAM” before +// “PROMISE VALUE”. +// +// This shows you that despite the promise being resolved synchronously, the +// provided function is not executed until the next turn of the event loop. +// +// +// » To print these instructions again, run: promise-it-wont-hurt print +// » To execute your program in a test environment, run: promise-it-wont-hurt run program.js +// » To verify your program, run: promise-it-wont-hurt verify program.js +// » For help run: promise-it-wont-hurt help + + +var promise = new Promise(function (fulfill, reject) { + fulfill("PROMISE VALUE") +}); + +promise.then(console.log).then(console.log("MAIN PROGRAM")) + +// console.log("MAIN PROGRAM") diff --git a/promise-it-wont-hurt-solutions/src/06-shortcuts.js b/promise-it-wont-hurt-solutions/src/06-shortcuts.js index e69de29..a43f2f1 100644 --- a/promise-it-wont-hurt-solutions/src/06-shortcuts.js +++ b/promise-it-wont-hurt-solutions/src/06-shortcuts.js @@ -0,0 +1,126 @@ +// # Promise me... quicker +// +// The ES2015 specification defines some shortcuts that make creating and working +// with promises faster and easier. +// +// The first is .catch. So far we already know how to handle the rejection of a +// promise -- through the second parameter to .then function. However, +// sometimes you only want to handle the rejection and not success. In these +// cases, since the onFulfilled callback is optional, you can specify null in +// place of it. However, a much easier way to achieve this is to use .catch. +// Instead of having to write +// +// promise.then(null, function (err) { +// console.error('THERE IS AN ERROR!!!'); +// console.error(err.message); +// }); +// +// You could simply write +// +// promise.catch(function (err) { +// console.error('THERE IS AN ERROR!!!'); +// console.error(err.message); +// }); +// +// This notation also has the benefit of making the easier to understand for +// people who do not speak Promises yet, since it is fairly obvious to everyone +// who has done JavaScript programming to understand what catch means. +// +// The second and third are Promise.resolve and Promise.reject. The code +// examples below will tell you exactly what they do: +// +// // The way you have learned: create promise through the constructor. +// +// var promise = new Promise(function (fulfill, reject) { +// fulfill('SECRET VALUE'); +// }); +// +// // Introducing: Promise.resolve +// // It does the exact same thing as above: +// +// var promise = Promise.resolve('SECRET VALUE'); +// +// +// // Likewise... +// +// var promise = new Promise(function (fulfill, reject) { +// reject(new Error('SECRET VALUE')); +// }); +// +// var promise = Promise.reject(new Error('SECRET VALUE')); +// +// ## Task +// +// We don’t have any specific task we’d like to assign to you for this lesson. +// Feel free to explore all three functions at your own pace. When you are +// preparing to submit though, make sure you are using at least catch and one +// of Promise.resolve and Promise.reject ☺ +// +// +// » To print these instructions again, run: promise-it-wont-hurt print +// » To execute your program in a test environment, run: promise-it-wont-hurt run program.js +// » To verify your program, run: promise-it-wont-hurt verify program.js +// » For help run: promise-it-wont-hurt help + +//Without catch +// var promise = new Promise(function(fulfill, reject) { + // //fulfill("SUCCESS") +// reject(new Error("This isn't working")) +// }) +// +// promise.then(console.log, function(error) { +// console.log(error.message) +// }) + +//With catch +var promise = new Promise(function(fulfill, reject) { + // fulfill("SUCCESS") + reject(new Error("This isn't working")) +}) + +promise.then(console.log) + +promise.catch(function(error) { + console.log(error.message) +}) + + +var promise = Promise.resolve(function(fulfill) { + fulfill("Hello World!") +}) + +var promise = Promise.reject(function(reject) { + reject(new Error("This isn't working")) +}) + +// Their example of playing around with it +// 'use strict'; +// +// var message; +// var promise; +// +// function randomBytes(n) { +// return (Math.random() * Math.pow(256, n) | 0).toString(16); +// } +// +// message = +// 'A fatal exception ' + randomBytes(1) + ' has occurred at ' + +// randomBytes(2) + ':' + randomBytes(4) + '. Your system\nwill be ' + +// 'terminated in 3 seconds.'; +// +// promise = Promise.reject(new Error(message)); +// +// promise.catch(function (err) { +// var i = 3; +// +// process.stderr.write(err.message); +// +// setTimeout(function boom() { +// process.stderr.write('\rwill be terminated in ' + (--i) + ' seconds.'); +// if (!i) { +// process.stderr.write('\n..... . . . boom . . . .....\n'); +// } else { +// setTimeout(boom, 1000); +// } +// }, 1000); +// }); diff --git a/promise-it-wont-hurt-solutions/src/07-promise-after-promise.js b/promise-it-wont-hurt-solutions/src/07-promise-after-promise.js index e69de29..468ad14 100644 --- a/promise-it-wont-hurt-solutions/src/07-promise-after-promise.js +++ b/promise-it-wont-hurt-solutions/src/07-promise-after-promise.js @@ -0,0 +1,104 @@ +// # Promise followed by promises +// +// So far, you have handled promise fulfillment and rejection, but all your +// handlers have been done synchronously like printing text. What if you want to +// do something asynchronously? +// +// Let us refer back to the example we used in the first lesson. +// +// Parse.User.logIn('user', 'pass', { +// success: function (user) { +// query.find({ +// success: function (results) { +// results[0].save({ key: value }, { +// success: function (result) { +// // the object was saved +// } +// }); +// } +// }); +// } +// }); +// +// Now, if all three functions return promises, you should be able to translate +// this code into: +// +// Parse.User.logIn('user', 'pass').then(function (user) { +// query.find().then(function (results) { +// results[0].save({ key: value }).then(function (result) { +// // the object was saved +// }); +// }); +// }); +// +// That’s quite a lot better: the awkward success property functions have been +// replaced. However, the despised pattern of “callback hell” is still there: if +// you want to do more than three things the code will rack up fairly quickly. +// +// To solve this problem, promises allow you to return another promise in the +// then function callbacks. This new promise you return in the promise will in +// turn be returned by then, so you can use it to do something after both of +// the actions are done. For example, the above code can be replaced by: +// +// var originalPromise = Parse.User.logIn('user', 'pass'); +// +// var findPromise = originalPromise.then(function (user) { +// // At this point, you have logged in. +// +// // query.find() returns another promise, which will become `findPromise` +// return query.find(); +// }); +// +// var savePromise = findPromise.then(function (results) { +// // At this point, the query finding is done. +// +// // The promise returned by `save` will become `savePromise` +// return results[0].save({ key: value }); +// }); +// +// savePromise.then(function (result) { +// // the object was saved +// }); +// +// which can then be simplified to: +// +// Parse.User.logIn('user', 'pass').then(function (user) { +// return query.find(); +// }).then(function (results) { +// return results[0].save({ key: value }); +// }).then(function (result) { +// // the object was saved +// }); +// +// That’s quite beautiful, no? +// +// ## Task +// +// This task will allow you to demonstrate an understanding how to chain promises +// together using then. +// +// Call first function in your program. first() will return a promise that +// will be fulfilled with a secret value. +// +// Call second with the fulfilled value of first. Return the promise returned +// by second in your onFulfilled callback. +// +// Finally, print the fulfilled value of that new promise with console.log. +// +// +// » To print these instructions again, run: promise-it-wont-hurt print +// » To execute your program in a test environment, run: promise-it-wont-hurt run program.js +// » To verify your program, run: promise-it-wont-hurt verify program.js +// » For help run: promise-it-wont-hurt help + +//Note: It's important to know that in this exercise the first() and second() functionds are supplied by the promise-it-wont-hurt lesson in the background + +// my solution +// first().then(function(firstValue) { +// return second(firstValue) +// }).then(function(secondValue) { +// console.log(secondValue) +// }) + +//Their solution +first().then(second).then(console.log); diff --git a/promise-it-wont-hurt-solutions/src/08-values-and-promises.js b/promise-it-wont-hurt-solutions/src/08-values-and-promises.js index e69de29..4d83dcb 100644 --- a/promise-it-wont-hurt-solutions/src/08-values-and-promises.js +++ b/promise-it-wont-hurt-solutions/src/08-values-and-promises.js @@ -0,0 +1,81 @@ +// # Do I HAVE to return promises? +// +// No! Fulfillment handlers may return promises or values. Your Promises +// library will do the correct thing and wrap your return value in a promise if +// need be. This is awesome because it allows you to intermix values with +// promises in a chain. +// +// Imagine that you have a cache of models that may already contain a model you +// would like to request from the server. You could check your cache +// synchronously and return the found value or send an AJAX request to your +// remote server to fetch it. +// +// Wrapping this functionality in a promise means that both behaviors can be +// consumed under a single abstraction: +// +// doSomeSetup() +// .then(function () { +// return cache.fetchModel(id) || promisedAjax("users/" + id); +// }) +// .then(displayUser) +// +// The key thing to understand here is that your handlers will wrap your +// return values in promises even if they are obtained synchronously. +// +// Another very important point to understand is that, as discussed before, the +// returned value will resolve on the next turn of the event loop. +// +// ## Task +// +// Construct a promise chain that returns values to prove to yourself that +// promise handlers will wrap your returned values in promises allowing +// additional chaining. +// +// * Declare a function `attachTitle` which prepends `'DR. '` to its firstargument and returns the result. +// * Create a fulfilled promise with a value of `'MANHATTAN'`. +// * Build a promise chain off the promise we just constructed that first calls`attachTitle` then calls `console.log`. +// +// If your program runs successfully, it should print out “DR. MANHATTAN” which +// is extremely exciting. +// +// +// » To print these instructions again, run: promise-it-wont-hurt print +// » To execute your program in a test environment, run: promise-it-wont-hurt run program.js +// » To verify your program, run: promise-it-wont-hurt verify program.js +// » For help run: promise-it-wont-hurt help + + + +// My way +function attachTitle(arg) { + var title = 'DR. ' + arg + return title +} + +var promise = new Promise(function(fulfill, reject) { + fulfill("MANHATTAN") +}) + +promise.then(attachTitle).then(console.log) + +//Their way +// function attachTitle(name) { +// return 'DR. ' + name +// } +// +// +// Promise.resolve("MANHATTAN").then(attachTitle).then(console.log) + +//Another way that is valid but "doesn't invoke attachTitle" directly +// function attachTitle(arg) { +// var title = 'DR. ' + arg +// return title +// } +// +// var promise = new Promise(function(fulfill, reject) { +// fulfill("MANHATTAN") +// }) +// +// promise.then(function(arg) { +// return attachTitle(arg) +// }).then(console.log) diff --git a/promise-it-wont-hurt-solutions/src/09-throw-an-error.js b/promise-it-wont-hurt-solutions/src/09-throw-an-error.js index e69de29..f6dea53 100644 --- a/promise-it-wont-hurt-solutions/src/09-throw-an-error.js +++ b/promise-it-wont-hurt-solutions/src/09-throw-an-error.js @@ -0,0 +1,57 @@ +// # What happens when an error is thrown? +// +// One of the tremendous strengths of promises is that they handle errors in a +// manner similar to synchronous code. Unlike in traditional callback-based code, +// you do not need to strictly handle all your errors at every step. +// +// If an error is thrown inside a function, it can be captured. +// +// If an error is thrown inside a function, it will be handled by the next +// available "rejection" handler. This allows you to write code that looks +// remarkably like a try/catch block would in synchronous code. +// +// try { +// doSomethingRisky(); +// doAnotherRiskyThing(); +// } catch (e) { +// console.log(e); +// } +// +// The equivalent "promisified" code might look like: +// +// doSomethingRisky() +// .then(doAnotherRiskyThing) +// .then(null, console.log); +// +// ## Task +// +// Let's build exactly the system discussed above. +// +// Some invalid JSON will be available on process.argv[2]. +// +// * Build a function called `parsePromised` that creates a promise,performs `JSON.parse` in a `try`/`catch` block, and fulfills or rejectsthe promise depending on whether an error is thrown.**Note:** your function should synchronously return the promise! +// * Build a sequence of steps like the ones shown above that catchesany thrown errors and logs them to the console. +// +// +// » To print these instructions again, run: promise-it-wont-hurt print +// » To execute your program in a test environment, run: promise-it-wont-hurt run program.js +// » To verify your program, run: promise-it-wont-hurt verify program.js +// » For help run: promise-it-wont-hurt help +// + + +//Solution +var q = require('q'); + +function parsePromised(toBeParsed) { + var deferred = q.defer(); + try { + var parsed = JSON.parse(toBeParsed); + deferred.resolve(parsed); + } catch (err) { + deferred.reject(err); + } + return deferred.promise; +} + +parsePromised(process.argv[2]).then(console.log).then(null, console.log); diff --git a/promise-it-wont-hurt-solutions/src/10-an-important-file.js b/promise-it-wont-hurt-solutions/src/10-an-important-file.js index e69de29..ff76dd9 100644 --- a/promise-it-wont-hurt-solutions/src/10-an-important-file.js +++ b/promise-it-wont-hurt-solutions/src/10-an-important-file.js @@ -0,0 +1,117 @@ +// # There's always a catch… (lol pun) +// +// Promises are designed to emulate synchronous control flows. +// If any of them throw an exception, the exception will bubble up +// through the stack until it is caught by a catch block or +// hits the global context where it will be thrown. +// +// In the code below, each expression is evaluated one after the +// other. If any expression throws an exception, all subsequent +// expressions will not be executed and the catch block +// will catch and handle it. +// +// try { +// doStuff() +// doMoreStuff() +// } catch (err) { +// complainAboutJavascript(err); +// } +// +// With promises, we can achieve a very similar control flow as shown +// (assume all functions return promises): +// +// doStuff() +// .then(doMoreStuff) +// .then(null, complainAboutJavascript); +// +// Maybe we should combine the last two lines since one is a fulfill +// handler and the other is a rejection handler? NO! While this +// might initially seem sensible consider what would happen if +// doMoreStuff threw an error. Since the promise returned from it +// would be rejected, it would look for the next rejection handler +// to handle it. +// +// Remember: A promise can never resolve more than once. +// +// It is, therefore, a best practice to always put a rejection handler +// at the bottom of your promise chain (much like a catch block). +// +// It is worth pointing out that both the synchronous and asynchronous +// code have the same problem. If the rejection handler itself throws +// an error you are going to have a bad time. +// +// Many promise libraries try to ameliorate this problem for you +// by providing a done handler that simply handles any uncaught +// errors. The rule of thumb is this: +// +// > If you are **not** returning a value from your promise to a caller, +// > then attach a `done` handler to guard against uncaught exceptions. +// +// An example is shown below: +// +// doStuff() +// .then(doMoreStuff) +// .then(null, complainAboutJavascript) +// .done(); +// +// ## Task +// +// We are going to demonstrate this to ourselves by creating a chain +// of functions that all print to the console. +// +// * Create a function `alwaysThrows` that throws an `Error` withtext `"OH NOES"`; +// * Create a function `iterate` that prints the first argument(an integer) to it and then returns that argument + 1; +// * Create a promise chain that wraps your iterate method using Q's`fcall` then a series of iterations that attempts to perform `iterate`a total of 10 times. +// * Attach `console.log` as a rejection handler at the bottom of yourchain. +// * Insert a call to `alwaysThrows` after your 5th call of `iterate` +// +// If you have done this correctly, your code should print 1,2,3,4,5, +// "[Error: OH NOES]". It's important to notice that the thrown exception was +// turned into a rejected promise which caused the rejected promise to +// travel down the promise chain to the first available rejection handler. +// +// ## Bonus +// +// Try swapping your rejection handler from console.log to alwaysThrows. +// Your program will now throw an exception in the global context! Ahh! +// Try to fix this using the approach described above. +// +// +// » To print these instructions again, run: promise-it-wont-hurt print +// » To execute your program in a test environment, run: promise-it-wont-hurt run program.js +// » To verify your program, run: promise-it-wont-hurt verify program.js +// » For help run: promise-it-wont-hurt help + +// function alwaysThrows() { +// return new Error("OH NOES") +// } +// +// function iterate(i) { +// console.log(i) +// return i + 1 +// } +// +// Promise.resolve(1) +// .then(iterate) +// .then(iterate) +// .then(iterate) +// .then(iterate) +// .then(alwaysThrows) +// .then(iterate) +// .then(iterate) +// .catch(error) +// .catch(console.log) + +//Solution +var q = require('q'); + +function throwMyGod() { + throw new Error('OH NOES'); +} + +function iterate(arg) { + console.log(arg); + return arg + 1; +} + +q.fcall(iterate, 1).then(iterate).then(iterate).then(iterate).then(iterate).then(throwMyGod).then(iterate).then(iterate).then(iterate).then(iterate).then(iterate).then(null, console.log); diff --git a/promise-it-wont-hurt-solutions/src/11-multiple-promises.js b/promise-it-wont-hurt-solutions/src/11-multiple-promises.js index e69de29..9ce887e 100644 --- a/promise-it-wont-hurt-solutions/src/11-multiple-promises.js +++ b/promise-it-wont-hurt-solutions/src/11-multiple-promises.js @@ -0,0 +1,116 @@ +// # Can you do what Async.js does? +// +// When doing asynchronous programming you will often want to perform multiple +// operations in parallel. In some cases you may wish to delay further processing +// until a list of async operations have completed. +// +// In synchronous code this is trivial because our operations are executed in the +// order they are specified: +// +// var thingOne = getThing(1); +// var thingTwo = getThing(2); +// +// combine(thingOne, thingTwo); +// +// We would like to build a function such that we can specify a list of +// asynchronous values we would like to fetch and then use once all are +// available. +// +// getAll(fetch(1), fetch(2)) +// .then(function (values) { +// console.log(values[0], values[1]); +// }); + +// ## Task +// +// Let’s build this function! +// +// Create a function all that accepts two promises as arguments. This all +// function should do all of the following: +// +// Create an internal promise in whatever way you see fit. +// +// Create a counter variable with initial value of 0. +// +// Attach then fulfillment handlers to both promises and increment the internal +// counter when the handlers are called. +// +// When the counter reaches 2, fulfill the internal promise with an array +// containing both values. +// +// Finally return that internal promise to the user. +// +// After you finish writing your all function, pass getPromise1() and +// getPromise2() into your new function and then attach console.log as a +// fulfillment handler to the promise returned by your function. These two +// promise-returning functions will be provided to you in the global scope. +// +// ## Hint +// +// You probably want to use the good old Promise constructor. If you do find some +// other way, please [file an +// issue](https://github.com/stevekane/promise-it-wont-hurt/issues); I’m +// interested in such a solution! +// +// While this lesson is a good practice for your skills, in real world +// programming, such a task is usually achieved by using Promise.all utility +// function, which we are basically reimplementing. It works by taking an +// iterable (like an array) of promises, rather than separate arguments. It also +// handles error catching, and any errors will be forwarded. +// +// Promise.all([getPromise1(), getPromise2()]) +// .then(onFulfilled, onRejected); +// +// In this lesson though, rest assured that that Promise.all is disabled 😈 +// +// +// » To print these instructions again, run: promise-it-wont-hurt print +// » To execute your program in a test environment, run: promise-it-wont-hurt run program.js +// » To verify your program, run: promise-it-wont-hurt verify program.js +// » For help run: promise-it-wont-hurt help + + +//Solution +all = (promise1, promise2) -> +var q = require('q'); +var deferred1 = q.defer(); +var deferred2 = q.defer(); +var prom1 = deferred1.promise; +var prom2 = deferred2.promise; + +/* +function all(promise1, promise2) { + return q.all([promise1, promise2]); +}*/ + +function all(promise1, promise2) { + var allDeferred = q.defer(); + var counter = 0; + var vals = []; + promise1 + .then(function (result) { + vals[0] = result; + counter++; + if (counter >= 2) { + allDeferred.resolve(vals); + } + }) + .then(null, allDeferred.reject) + .done(); + promise2 + .then(function (result) { + vals[1] = result; + counter++; + if (counter >= 2) { + allDeferred.resolve(vals); + } + }) + .then(null, allDeferred.reject) + .done(); + return allDeferred.promise; +} + +all(prom1, prom2).then(console.log); + +setTimeout(deferred1.resolve, 200, 'PROMISES'); +setTimeout(deferred2.resolve, 200, 'FTW'); diff --git a/promise-it-wont-hurt-solutions/src/12-fetch-json.js b/promise-it-wont-hurt-solutions/src/12-fetch-json.js index e69de29..61029dd 100644 --- a/promise-it-wont-hurt-solutions/src/12-fetch-json.js +++ b/promise-it-wont-hurt-solutions/src/12-fetch-json.js @@ -0,0 +1,52 @@ +// +// # Let's do something, you know, from "real life" +// +// Let's fetch JSON over HTTP… YAY! +// +// Fetching JSON data from remote machines via AJAX is commonplace +// on both the server and client. Promises also happen to map to AJAX +// particularly well. Any AJAX request may either succeed or fail, +// never both. Promises may fulfill or reject, never both. +// +// So wow. Much similarity. Very promising… +// +// Let's use a new module called q-io to take advantage of its http.read +// method which returns a promise for the value of a successful HTTP response +// body. +// +// Install by typing: +// +// $ npm install q-io --save +// +// ## Task +// +// Fetch JSON from [http://localhost:1337](http://localhost:1337) and console.log it. +// +// There are several things you will want to know: +// +// * `q-io`'s `http` module has a `read` method which returns a promise for thecontent of a successful (status 200) HTTP request. +// * Parse the returned JSON and `console.log` it for much win. +// +// This challenge is a bit tricky but the implementation is relatively +// straightforward. If you get stuck, refer to the q-io documentation for +// clarification: +// +// [https://github.com/kriskowal/q-io](https://github.com/kriskowal/q-io) +// +// +// » To print these instructions again, run: promise-it-wont-hurt print +// » To execute your program in a test environment, run: promise-it-wont-hurt run program.js +// » To verify your program, run: promise-it-wont-hurt verify program.js +// » For help run: promise-it-wont-hurt help + +//Solution +var qHttp = require('q-io/http'); + +qHttp.read('http://localhost:1337') + + .then(function (result) { + var parsed = JSON.parse(result); + console.log(parsed); + }) + .then(null, console.error) + .done(); diff --git a/promise-it-wont-hurt-solutions/src/13-do-some-work.js b/promise-it-wont-hurt-solutions/src/13-do-some-work.js index e69de29..3feb9ab 100644 --- a/promise-it-wont-hurt-solutions/src/13-do-some-work.js +++ b/promise-it-wont-hurt-solutions/src/13-do-some-work.js @@ -0,0 +1,44 @@ +// # Let's do several operations against "remote" machines +// +// Sending and fetching data from computers/processes other than your +// application is an increasingly common task in the world of Node.js +// and the browser. Many times, you will need to gather data from +// several sources, perform operations on it, and send some data back out. +// +// ## Task +// +// Let's talk to two remote processes over HTTP being run by your friend +// and mine, "localhost". +// +// * Port 7000: Faux session cache (Redis or some such thing) +// * Port 7001: Faux database (MongoDB, LevelDB, Postgres, etc) +// +// As in the previous lesson, use the q-io module to create promises +// as wrappers for HTTP responses. Hint: You will probably need more +// than one promise… +// +// * Send an HTTP GET request to the session cache on port 7000. A stringwill be returned to you representing a user ID. +// * Grab that ID from the session response and send an HTTP GET request toyour database on port 7001 to the url `localhost:7001/`. +// * If successfully done, your database will return a user object.`console.log` it to win many nerd-points. +// +// +// » To print these instructions again, run: promise-it-wont-hurt print +// » To execute your program in a test environment, run: promise-it-wont-hurt run program.js +// » To verify your program, run: promise-it-wont-hurt verify program.js +// » For help run: promise-it-wont-hurt help + +//Solution +var qHttp = require('q-io/http'); + +qHttp.read('http://localhost:7000') + .then(function (result) { + // toString can be omitted and JavaScript will do conversion to string for you + var id = result.toString(); + // here a new promise will be returned + return qHttp.read('http://localhost:7001/' + id); + }, console.error) // the error handler here is not really usefull. anyway + // just one error handler at the end of all is okay + .then(function (res) { // this is attached to the promise reading port 7001 + console.log(JSON.parse(res.toString())); + }, console.error) + .done();