From 8de66ebf063b6cf17d6eaf228633f1d96103f19f Mon Sep 17 00:00:00 2001 From: Radek Stepan Date: Mon, 11 Jan 2016 20:20:14 +0100 Subject: [PATCH] #105 commit unminified files --- .gitignore | 2 - README.md | 2 +- bin/run.js | 5 +- package.json | 2 +- public/css/app.bundle.css | 963 + public/js/app.bundle.js | 48926 ++++++++++++++++++++++++++++++++++++ 6 files changed, 49894 insertions(+), 6 deletions(-) create mode 100644 public/css/app.bundle.css create mode 100644 public/js/app.bundle.js diff --git a/.gitignore b/.gitignore index 74e6e95..b029d56 100644 --- a/.gitignore +++ b/.gitignore @@ -3,10 +3,8 @@ node_modules/ .build_cache~ .grunt/ build/*.map -public/js/app.bundle.js public/js/.app.bundle.js public/js/app.js -public/css/app.bundle.css public/css/.app.bundle.css public/css/app.css .DS_Store \ No newline at end of file diff --git a/README.md b/README.md index 33a6064..f47eba6 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ GitHub Burndown Chart as a Service. Answers the question "are my projects on tra ```bash $ npm install burnchart -g $ burnchart 8080 -# burnchart/2.0.8 started on http://0.0.0.0:8080 +# burnchart/2.0.8 started on port 8080 ``` ##Configuration diff --git a/bin/run.js b/bin/run.js index 99b1400..cd6786a 100755 --- a/bin/run.js +++ b/bin/run.js @@ -2,6 +2,7 @@ var stat = require('node-static'), path = require('path'), http = require('http'), + exec = require('child_process').exec, pakg = require('../package.json'); var opts = { @@ -20,5 +21,5 @@ var server = http.createServer(function(req, res) { server.on('listening', function() { var addr = server.address(); - console.log('burnchart/' + pakg.version + ' started on http://' + addr.address + ':' + addr.port); -}); \ No newline at end of file + console.log('burnchart/' + pakg.version + ' started on port ' + addr.port); +}); diff --git a/package.json b/package.json index 12c585f..529b773 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "burnchart", - "version": "2.0.9", + "version": "2.0.10", "description": "GitHub Burndown Chart as a Service", "author": "Radek Stepan (http://radekstepan.com)", "license": "AGPL-3.0", diff --git a/public/css/app.bundle.css b/public/css/app.bundle.css new file mode 100644 index 0000000..3aa0c18 --- /dev/null +++ b/public/css/app.bundle.css @@ -0,0 +1,963 @@ +/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS and IE text size adjust after device orientation change, + * without disabling user zoom. + */ +html { + font-family: sans-serif; + /* 1 */ + -ms-text-size-adjust: 100%; + /* 2 */ + -webkit-text-size-adjust: 100%; + /* 2 */ +} +/** + * Remove default margin. + */ +body { + margin: 0; +} +/* HTML5 display definitions + ========================================================================== */ +/** + * Correct `block` display not defined for any HTML5 element in IE 8/9. + * Correct `block` display not defined for `details` or `summary` in IE 10/11 + * and Firefox. + * Correct `block` display not defined for `main` in IE 11. + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; +} +/** + * 1. Correct `inline-block` display not defined in IE 8/9. + * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. + */ +audio, +canvas, +progress, +video { + display: inline-block; + /* 1 */ + vertical-align: baseline; + /* 2 */ +} +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ +audio:not([controls]) { + display: none; + height: 0; +} +/** + * Address `[hidden]` styling not present in IE 8/9/10. + * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22. + */ +[hidden], +template { + display: none; +} +/* Links + ========================================================================== */ +/** + * Remove the gray background color from active links in IE 10. + */ +a { + background-color: transparent; +} +/** + * Improve readability of focused elements when they are also in an + * active/hover state. + */ +a:active, +a:hover { + outline: 0; +} +/* Text-level semantics + ========================================================================== */ +/** + * Address styling not present in IE 8/9/10/11, Safari, and Chrome. + */ +abbr[title] { + border-bottom: 1px dotted; +} +/** + * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. + */ +b, +strong { + font-weight: bold; +} +/** + * Address styling not present in Safari and Chrome. + */ +dfn { + font-style: italic; +} +/** + * Address variable `h1` font-size and margin within `section` and `article` + * contexts in Firefox 4+, Safari, and Chrome. + */ +h1 { + font-size: 2em; + margin: 0.67em 0; +} +/** + * Address styling not present in IE 8/9. + */ +mark { + background: #ff0; + color: #000; +} +/** + * Address inconsistent and variable font size in all browsers. + */ +small { + font-size: 80%; +} +/** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +/* Embedded content + ========================================================================== */ +/** + * Remove border when inside `a` element in IE 8/9/10. + */ +img { + border: 0; +} +/** + * Correct overflow not hidden in IE 9/10/11. + */ +svg:not(:root) { + overflow: hidden; +} +/* Grouping content + ========================================================================== */ +/** + * Address margin not present in IE 8/9 and Safari. + */ +figure { + margin: 1em 40px; +} +/** + * Address differences between Firefox and other browsers. + */ +hr { + box-sizing: content-box; + height: 0; +} +/** + * Contain overflow in all browsers. + */ +pre { + overflow: auto; +} +/** + * Address odd `em`-unit font size rendering in all browsers. + */ +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} +/* Forms + ========================================================================== */ +/** + * Known limitation: by default, Chrome and Safari on OS X allow very limited + * styling of `select`, unless a `border` property is set. + */ +/** + * 1. Correct color not being inherited. + * Known issue: affects color of disabled elements. + * 2. Correct font properties not being inherited. + * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. + */ +button, +input, +optgroup, +select, +textarea { + color: inherit; + /* 1 */ + font: inherit; + /* 2 */ + margin: 0; + /* 3 */ +} +/** + * Address `overflow` set to `hidden` in IE 8/9/10/11. + */ +button { + overflow: visible; +} +/** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. + * Correct `select` style inheritance in Firefox. + */ +button, +select { + text-transform: none; +} +/** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + */ +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; + /* 2 */ + cursor: pointer; + /* 3 */ +} +/** + * Re-set default cursor for disabled elements. + */ +button[disabled], +html input[disabled] { + cursor: default; +} +/** + * Remove inner padding and border in Firefox 4+. + */ +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} +/** + * Address Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ +input { + line-height: normal; +} +/** + * It's recommended that you don't attempt to style these elements. + * Firefox's implementation doesn't respect box-sizing, padding, or width. + * + * 1. Address box sizing set to `content-box` in IE 8/9/10. + * 2. Remove excess padding in IE 8/9/10. + */ +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; + /* 1 */ + padding: 0; + /* 2 */ +} +/** + * Fix the cursor style for Chrome's increment/decrement buttons. For certain + * `font-size` values of the `input`, it causes the cursor style of the + * decrement button to change from `default` to `text`. + */ +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} +/** + * 1. Address `appearance` set to `searchfield` in Safari and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari and Chrome. + */ +input[type="search"] { + -webkit-appearance: textfield; + /* 1 */ + box-sizing: content-box; + /* 2 */ +} +/** + * Remove inner padding and search cancel button in Safari and Chrome on OS X. + * Safari (but not Chrome) clips the cancel button when the search input has + * padding (and `textfield` appearance). + */ +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +/** + * Define consistent border, margin, and padding. + */ +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} +/** + * 1. Correct `color` not being inherited in IE 8/9/10/11. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ +legend { + border: 0; + /* 1 */ + padding: 0; + /* 2 */ +} +/** + * Remove default vertical scrollbar in IE 8/9/10/11. + */ +textarea { + overflow: auto; +} +/** + * Don't inherit the `font-weight` (applied by a rule above). + * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. + */ +optgroup { + font-weight: bold; +} +/* Tables + ========================================================================== */ +/** + * Remove most spacing between table cells. + */ +table { + border-collapse: collapse; + border-spacing: 0; +} +td, +th { + padding: 0; +} +@font-face { + font-family: 'MuseoSlab500Regular'; + src: url("../fonts/museo-slab-500.eot"); + src: url("../fonts/museo-slab-500.eot?#iefix") format('embedded-opentype'), url("../fonts/museo-slab-500.woff") format('woff'), url("../fonts/museo-slab-500.ttf") format('truetype'), url("../fonts/museo-slab-500.svg#MuseoSlab500Regular") format('svg'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'MuseoSans500Regular'; + src: url("../fonts/museo-sans-500.eot"); + src: url("../fonts/museo-sans-500.eot?#iefix") format('embedded-opentype'), url("../fonts/museo-sans-500.woff") format('woff'), url("../fonts/museo-sans-500.ttf") format('truetype'), url("../fonts/museo-sans-500.svg#MuseoSans500Regular") format('svg'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'Fontello'; + src: url("../fonts/fontello.eot?74672344"); + src: url("../fonts/fontello.eot?74672344#iefix") format('embedded-opentype'), url("../fonts/fontello.woff?74672344") format('woff'), url("../fonts/fontello.ttf?74672344") format('truetype'), url("../fonts/fontello.svg?74672344#fontello") format('svg'); + font-weight: normal; + font-style: normal; +} +.icon { + vertical-align: middle; + font-family: "Fontello"; + font-style: normal; + font-weight: normal; + speak: none; + display: inline-block; + text-decoration: inherit; + text-align: center; + font-variant: normal; + text-transform: none; +} +.icon[class^='spin'], +.icon[class*=' spin'] { + -webkit-animation: spin 2s infinite linear; + -moz-animation: spin 2s infinite linear; + -o-animation: spin 2s infinite linear; + animation: spin 2s infinite linear; +} +lesshat-selector { + -lh-property: 0; } +@-webkit-keyframes spin{ from { -webkit-transform: rotate(0deg); } to { -webkit-transform: rotate(360deg); }} +@-moz-keyframes spin{ from { -moz-transform: rotate(0deg); } to { -moz-transform: rotate(360deg); }} +@-o-keyframes spin{ from { -o-transform: rotate(0deg); } to { -o-transform: rotate(360deg); }} +@keyframes spin{ from {-webkit-transform: rotate(0deg);-moz-transform: rotate(0deg);-ms-transform: rotate(0deg);transform: rotate(0deg); } to {-webkit-transform: rotate(360deg);-moz-transform: rotate(360deg);-ms-transform: rotate(360deg);transform: rotate(360deg); }; +} +#chart { + height: 300px; + position: relative; +} +#chart #tooltip { + position: absolute; + top: 0; + left: 0; +} +#chart svg path.line { + fill: none; + stroke-width: 1px; + clip-path: url("#clip"); +} +#chart svg path.line.actual { + stroke: #64584c; + stroke-width: 3px; +} +#chart svg path.line.ideal { + stroke: #cacaca; + stroke-width: 3px; +} +#chart svg path.line.trendline { + stroke: #64584c; + stroke-width: 1.5px; + stroke-dasharray: 5, 5; +} +#chart svg line.today { + stroke: #cacaca; + stroke-width: 1px; + shape-rendering: crispEdges; + stroke-dasharray: 5, 5; +} +#chart svg circle { + fill: #64584c; + stroke: transparent; + stroke-width: 15px; + cursor: pointer; +} +#chart svg .axis { + shape-rendering: crispEdges; +} +#chart svg .axis line { + stroke: rgba(202, 202, 202, 0.25); + shape-rendering: crispEdges; +} +#chart svg .axis text { + font-weight: bold; + fill: #cacaca; +} +#chart svg .axis path { + display: none; +} +.d3-tip { + margin-top: -10px; + font-size: 11px; + padding: 8px 10px 7px 10px; + text-align: center; + background: rgba(0, 0, 0, 0.75); + color: #fff; + -webkit-border-radius: 3px; + -webkit-background-clip: padding-box; + -moz-border-radius: 3px; + -moz-background-clip: padding; + border-radius: 3px; + background-clip: padding-box; +} +.d3-tip:after { + width: 100%; + color: rgba(0, 0, 0, 0.8); + content: "\25BC"; + position: absolute; +} +.d3-tip.n:after { + margin: -3px 0 0 0; + top: 100%; + left: 0; +} +html, +body { + margin: 0; + padding: 0; + height: 100%; +} +body { + color: #3e4457; + font-family: 'MuseoSans500Regular', sans-serif; +} +#app { + position: relative; + height: auto !important; + min-height: 100%; +} +a { + text-decoration: none; + color: #aaafbf; + cursor: pointer; +} +h1, +h2, +h3, +p { + margin: 0; +} +ul { + list-style-type: none; + margin: 0; + padding: 0; +} +ul li { + display: inline-block; +} +.wrap { + width: 800px; + margin: 0 auto; +} +#notify { + position: fixed; + top: -68px; + z-index: 1; + width: 100%; + background: #fcfcfc; + color: #aaafbf; + border-top: 3px solid #aaafbf; + border-bottom: 1px solid #f3f4f8; +} +#notify .close { + float: right; + font-size: 16px; + padding: 22px; + cursor: pointer; +} +#notify .close:before { + content: "\d7"; + display: block; +} +#notify.system { + top: 0%; + left: 50%; + width: 500px; + -webkit-transform: translateX(-50%) translateY(-50%); + -moz-transform: translateX(-50%) translateY(-50%); + -o-transform: translateX(-50%) translateY(-50%); + -ms-transform: translateX(-50%) translateY(-50%); + transform: translateX(-50%) translateY(-50%); +} +#notify.system p { + padding-top: 20px; +} +#notify.success, +#notify.ok, +#notify.good { + border-top-color: #00b361; + color: #00b361; +} +#notify.warn, +#notify.trouble { + border-top-color: #ea9712; + color: #ea9712; +} +#notify.alert, +#notify.bad, +#notify.fucked { + border-top-color: #C1041C; + color: #C1041C; +} +#notify .icon, +#notify p { + display: block; +} +#notify .icon { + font-size: 26px; + padding: 18px; + width: 38px; + float: left; +} +#notify p { + padding: 22px 20px 20px 74px; + text-align: justify; +} +#head { + background: #C1041C; + height: 64px; +} +#head #icon { + font-size: 26px; + padding: 10px 0; + line-height: 44px; + height: 44px; + width: 74px; + background: #77000e; + display: inline-block; + color: #C1041C; + margin: 0; + text-align: center; +} +#head .q { + position: relative; + display: inline-block; + margin: 13px 20px 0 20px; + vertical-align: top; +} +#head .q .icon { + position: absolute; + color: #C1041C; +} +#head .q .icon.search { + top: 8px; + left: 12px; +} +#head .q .icon.down-open { + top: 8px; + right: 12px; +} +#head .q input { + background: #77000e; + border: 0; + padding: 10px 12px 10px 36px; + font-size: 14px; + -webkit-border-radius: 2px; + -webkit-background-clip: padding-box; + -moz-border-radius: 2px; + -moz-background-clip: padding; + border-radius: 2px; + background-clip: padding-box; + color: #fff; + width: 220px; +} +#head ul { + display: inline-block; +} +#head ul li { + margin-left: 30px; +} +#head a { + color: #e0808d; + font-weight: bold; +} +#head a.active, +#head a:hover { + color: #fff; +} +#head .right { + float: right; + margin-right: 20px; + line-height: 64px; + color: #e0808d; +} +#head .right .button { + -webkit-border-radius: 2px; + -webkit-background-clip: padding-box; + -moz-border-radius: 2px; + -moz-background-clip: padding; + border-radius: 2px; + background-clip: padding-box; + background: #FFBB2A; + color: #C1041C; + padding: 11px 20px; +} +#title { + border-bottom: 3px solid #f3f4f8; + white-space: nowrap; + line-height: 30px; + margin-top: 20px; +} +#title .wrap { + white-space: normal; + border-bottom: 3px solid #aaafbf; + margin-bottom: -3px; + padding-bottom: 10px; +} +#title .title { + display: inline-block; + line-height: 30px; + margin-right: 20px; +} +#title .sub { + font-size: 16px; + font-weight: bold; + margin-right: 20px; +} +#title .description { + font-family: 'MuseoSlab500Regular', serif; + color: #b1b6c4; + display: inline-block; +} +#title:after { + display: block; + clear: both; + content: ""; +} +#page { + padding-bottom: 80px; +} +#page #content { + padding: 20px 0; + margin-top: 20px; + margin-bottom: 40px; +} +#page #content #hero { + background: url("../img/highway.jpg") center; + background-size: cover; + -webkit-border-radius: 2px; + -webkit-background-clip: padding-box; + -moz-border-radius: 2px; + -moz-background-clip: padding; + border-radius: 2px; + background-clip: padding-box; + margin-bottom: 30px; +} +#page #content #hero .content { + -webkit-border-radius: 2px; + -webkit-background-clip: padding-box; + -moz-border-radius: 2px; + -moz-background-clip: padding; + border-radius: 2px; + background-clip: padding-box; + color: #fff; + padding: 30px; + background: rgba(0, 0, 0, 0.5); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2); +} +#page #content #hero .content h2 { + margin-bottom: 20px; + margin-left: 140px; +} +#page #content #hero .content p { + font-family: 'MuseoSlab500Regular', serif; + font-size: 18px; + line-height: 24px; + margin-left: 140px; + text-align: justify; + text-justify: inter-word; +} +#page #content #hero .content .icon.direction { + font-size: 120px; + float: left; +} +#page #content #hero .content .cta { + text-align: center; + margin-top: 10px; +} +#page #content #hero .content .cta a { + font-family: 'MuseoSlab500Regular', serif; + padding: 11px 20px; + -webkit-border-radius: 2px; + -webkit-background-clip: padding-box; + -moz-border-radius: 2px; + -moz-background-clip: padding; + border-radius: 2px; + background-clip: padding-box; + display: inline-block; + margin: 0 4px; +} +#page #content #hero .content .cta a.primary { + font-weight: bold; + background: #C1041C; + color: #fff; +} +#page #content #hero .content .cta a.secondary { + background: #fff; + color: #C1041C; +} +#page #content #add h2 { + color: #3e4457; +} +#page #content #add p { + font-family: 'MuseoSlab500Regular', serif; + color: #b1b6c4; + margin-top: 10px; + line-height: 20px; + text-align: justify; + text-justify: inter-word; +} +#page #content #add p a { + color: #3e4457; +} +#page #content #add .form { + margin-top: 20px; +} +#page #content #add .form table { + width: 100%; +} +#page #content #add .form table tr td:first-child { + width: 100%; +} +#page #content #add .form input { + box-sizing: border-box; + padding: 10px; + width: 100%; + -webkit-border-radius: 2px 0 0 2px; + -webkit-background-clip: padding-box; + -moz-border-radius: 2px 0 0 2px; + -moz-background-clip: padding; + border-radius: 2px 0 0 2px; + background-clip: padding-box; + border: 1px solid #dde1ed; + border-right: 0; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2); +} +#page #content #add .form a { + margin-left: -2px; + font-family: 'MuseoSlab500Regular', serif; + padding: 11px 20px; + -webkit-border-radius: 0 2px 2px 0; + -webkit-background-clip: padding-box; + -moz-border-radius: 0 2px 2px 0; + -moz-background-clip: padding; + border-radius: 0 2px 2px 0; + background-clip: padding-box; + display: inline-block; + font-weight: bold; + background: #C1041C; + color: #fff; +} +#page #content #projects { + border: 1px solid #cdcecf; + -webkit-border-radius: 2px; + -webkit-background-clip: padding-box; + -moz-border-radius: 2px; + -moz-background-clip: padding; + border-radius: 2px; + background-clip: padding-box; +} +#page #content #projects h2 { + color: #3e4457; + display: inline-block; +} +#page #content #projects .sort:not(.icon) { + float: right; + line-height: 30px; +} +#page #content #projects table { + width: 100%; +} +#page #content #projects table tr td { + background: #fcfcfc; + padding: 20px 30px; + border-bottom: 1px solid #eaecf2; +} +#page #content #projects table tr td .project { + color: inherit; +} +#page #content #projects table tr td .project .error { + cursor: help; + color: #C1041C; +} +#page #content #projects table tr td a.project { + font-weight: bold; +} +#page #content #projects table tr td .milestone .icon { + font-size: 10px; + margin: 0; +} +#page #content #projects table tr td .progress { + width: 200px; +} +#page #content #projects table tr td .progress .percent, +#page #content #projects table tr td .progress .due { + color: #9399ad; + font-size: 13px; +} +#page #content #projects table tr td .progress .percent { + float: right; +} +#page #content #projects table tr td .progress .bar { + -webkit-border-radius: 4px; + -webkit-background-clip: padding-box; + -moz-border-radius: 4px; + -moz-background-clip: padding; + border-radius: 4px; + background-clip: padding-box; + background: #eaecf2; + height: 10px; + width: 100%; +} +#page #content #projects table tr td .progress .bar.inner { + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2); +} +#page #content #projects table tr td .progress .bar.red { + background: #C1041C; +} +#page #content #projects table tr td .progress .bar.green { + background: #00b361; +} +#page #content #projects table tr td .progress .due.red { + color: #C1041C; + font-weight: bold; +} +#page #content #projects table tr td:first-child { + color: #3e4457; +} +#page #content #projects table tr:nth-child(even) td { + background: #fefefe; +} +#page #content #projects table tr:last-child td { + border: 0; +} +#page #content #projects table tr.done td { + background: #ebf6f1; +} +#page #content #projects table tr.done td .milestone, +#page #content #projects table tr.done td .percent, +#page #content #projects table tr.done td .due { + color: #00b361; +} +#page #content #projects .header, +#page #content #projects .footer { + padding: 20px 30px; +} +#page #content #projects .header { + -webkit-box-shadow: 0 1px 2px rgba(221, 225, 237, 0.5); + -moz-box-shadow: 0 1px 2px rgba(221, 225, 237, 0.5); + box-shadow: 0 1px 2px rgba(221, 225, 237, 0.5); + margin-bottom: 2px; + border-bottom: 1px solid #dde1ed; +} +#page #content #projects .header a { + font-family: 'MuseoSlab500Regular', serif; +} +#page #content #projects .footer { + background: #f9fafb; + color: #aaafbf; + -webkit-box-shadow: inset 0 1px 2px rgba(221, 225, 237, 0.2); + -moz-box-shadow: inset 0 1px 2px rgba(221, 225, 237, 0.2); + box-shadow: inset 0 1px 2px rgba(221, 225, 237, 0.2); + border-top: 1px solid #dde1ed; + text-align: right; + font-family: 'MuseoSlab500Regular', serif; +} +#page #content #projects .footer .icon { + color: #aaafbf; +} +#page #content .protip { + border: 1px solid #EFEFEF; + -webkit-border-radius: 2px; + -webkit-background-clip: padding-box; + -moz-border-radius: 2px; + -moz-background-clip: padding; + border-radius: 2px; + background-clip: padding-box; + padding: 20px; + margin: 30px 0; + color: #B1B6C4; +} +#footer { + position: absolute; + width: 100%; + bottom: 0; + box-sizing: border-box; + border-top: 1px solid #f3f4f8; + text-align: center; + padding: 30px; + font-family: 'MuseoSlab500Regular', serif; +} diff --git a/public/js/app.bundle.js b/public/js/app.bundle.js new file mode 100644 index 0000000..9e64ebc --- /dev/null +++ b/public/js/app.bundle.js @@ -0,0 +1,48926 @@ +(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;o= 0 && + arr.length % 1 === 0 + ); + } + + function _arrayEach(arr, iterator) { + var index = -1, + length = arr.length; + + while (++index < length) { + iterator(arr[index], index, arr); + } + } + + function _map(arr, iterator) { + var index = -1, + length = arr.length, + result = Array(length); + + while (++index < length) { + result[index] = iterator(arr[index], index, arr); + } + return result; + } + + function _range(count) { + return _map(Array(count), function (v, i) { return i; }); + } + + function _reduce(arr, iterator, memo) { + _arrayEach(arr, function (x, i, a) { + memo = iterator(memo, x, i, a); + }); + return memo; + } + + function _forEachOf(object, iterator) { + _arrayEach(_keys(object), function (key) { + iterator(object[key], key); + }); + } + + function _indexOf(arr, item) { + for (var i = 0; i < arr.length; i++) { + if (arr[i] === item) return i; + } + return -1; + } + + var _keys = Object.keys || function (obj) { + var keys = []; + for (var k in obj) { + if (obj.hasOwnProperty(k)) { + keys.push(k); + } + } + return keys; + }; + + function _keyIterator(coll) { + var i = -1; + var len; + var keys; + if (_isArrayLike(coll)) { + len = coll.length; + return function next() { + i++; + return i < len ? i : null; + }; + } else { + keys = _keys(coll); + len = keys.length; + return function next() { + i++; + return i < len ? keys[i] : null; + }; + } + } + + // Similar to ES6's rest param (http://ariya.ofilabs.com/2013/03/es6-and-rest-parameter.html) + // This accumulates the arguments passed into an array, after a given index. + // From underscore.js (https://github.com/jashkenas/underscore/pull/2140). + function _restParam(func, startIndex) { + startIndex = startIndex == null ? func.length - 1 : +startIndex; + return function() { + var length = Math.max(arguments.length - startIndex, 0); + var rest = Array(length); + for (var index = 0; index < length; index++) { + rest[index] = arguments[index + startIndex]; + } + switch (startIndex) { + case 0: return func.call(this, rest); + case 1: return func.call(this, arguments[0], rest); + } + // Currently unused but handle cases outside of the switch statement: + // var args = Array(startIndex + 1); + // for (index = 0; index < startIndex; index++) { + // args[index] = arguments[index]; + // } + // args[startIndex] = rest; + // return func.apply(this, args); + }; + } + + function _withoutIndex(iterator) { + return function (value, index, callback) { + return iterator(value, callback); + }; + } + + //// exported async module functions //// + + //// nextTick implementation with browser-compatible fallback //// + + // capture the global reference to guard against fakeTimer mocks + var _setImmediate = typeof setImmediate === 'function' && setImmediate; + + var _delay = _setImmediate ? function(fn) { + // not a direct alias for IE10 compatibility + _setImmediate(fn); + } : function(fn) { + setTimeout(fn, 0); + }; + + if (typeof process === 'object' && typeof process.nextTick === 'function') { + async.nextTick = process.nextTick; + } else { + async.nextTick = _delay; + } + async.setImmediate = _setImmediate ? _delay : async.nextTick; + + + async.forEach = + async.each = function (arr, iterator, callback) { + return async.eachOf(arr, _withoutIndex(iterator), callback); + }; + + async.forEachSeries = + async.eachSeries = function (arr, iterator, callback) { + return async.eachOfSeries(arr, _withoutIndex(iterator), callback); + }; + + + async.forEachLimit = + async.eachLimit = function (arr, limit, iterator, callback) { + return _eachOfLimit(limit)(arr, _withoutIndex(iterator), callback); + }; + + async.forEachOf = + async.eachOf = function (object, iterator, callback) { + callback = _once(callback || noop); + object = object || []; + + var iter = _keyIterator(object); + var key, completed = 0; + + while ((key = iter()) != null) { + completed += 1; + iterator(object[key], key, only_once(done)); + } + + if (completed === 0) callback(null); + + function done(err) { + completed--; + if (err) { + callback(err); + } + // Check key is null in case iterator isn't exhausted + // and done resolved synchronously. + else if (key === null && completed <= 0) { + callback(null); + } + } + }; + + async.forEachOfSeries = + async.eachOfSeries = function (obj, iterator, callback) { + callback = _once(callback || noop); + obj = obj || []; + var nextKey = _keyIterator(obj); + var key = nextKey(); + function iterate() { + var sync = true; + if (key === null) { + return callback(null); + } + iterator(obj[key], key, only_once(function (err) { + if (err) { + callback(err); + } + else { + key = nextKey(); + if (key === null) { + return callback(null); + } else { + if (sync) { + async.setImmediate(iterate); + } else { + iterate(); + } + } + } + })); + sync = false; + } + iterate(); + }; + + + + async.forEachOfLimit = + async.eachOfLimit = function (obj, limit, iterator, callback) { + _eachOfLimit(limit)(obj, iterator, callback); + }; + + function _eachOfLimit(limit) { + + return function (obj, iterator, callback) { + callback = _once(callback || noop); + obj = obj || []; + var nextKey = _keyIterator(obj); + if (limit <= 0) { + return callback(null); + } + var done = false; + var running = 0; + var errored = false; + + (function replenish () { + if (done && running <= 0) { + return callback(null); + } + + while (running < limit && !errored) { + var key = nextKey(); + if (key === null) { + done = true; + if (running <= 0) { + callback(null); + } + return; + } + running += 1; + iterator(obj[key], key, only_once(function (err) { + running -= 1; + if (err) { + callback(err); + errored = true; + } + else { + replenish(); + } + })); + } + })(); + }; + } + + + function doParallel(fn) { + return function (obj, iterator, callback) { + return fn(async.eachOf, obj, iterator, callback); + }; + } + function doParallelLimit(fn) { + return function (obj, limit, iterator, callback) { + return fn(_eachOfLimit(limit), obj, iterator, callback); + }; + } + function doSeries(fn) { + return function (obj, iterator, callback) { + return fn(async.eachOfSeries, obj, iterator, callback); + }; + } + + function _asyncMap(eachfn, arr, iterator, callback) { + callback = _once(callback || noop); + arr = arr || []; + var results = _isArrayLike(arr) ? [] : {}; + eachfn(arr, function (value, index, callback) { + iterator(value, function (err, v) { + results[index] = v; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + } + + async.map = doParallel(_asyncMap); + async.mapSeries = doSeries(_asyncMap); + async.mapLimit = doParallelLimit(_asyncMap); + + // reduce only has a series version, as doing reduce in parallel won't + // work in many situations. + async.inject = + async.foldl = + async.reduce = function (arr, memo, iterator, callback) { + async.eachOfSeries(arr, function (x, i, callback) { + iterator(memo, x, function (err, v) { + memo = v; + callback(err); + }); + }, function (err) { + callback(err, memo); + }); + }; + + async.foldr = + async.reduceRight = function (arr, memo, iterator, callback) { + var reversed = _map(arr, identity).reverse(); + async.reduce(reversed, memo, iterator, callback); + }; + + async.transform = function (arr, memo, iterator, callback) { + if (arguments.length === 3) { + callback = iterator; + iterator = memo; + memo = _isArray(arr) ? [] : {}; + } + + async.eachOf(arr, function(v, k, cb) { + iterator(memo, v, k, cb); + }, function(err) { + callback(err, memo); + }); + }; + + function _filter(eachfn, arr, iterator, callback) { + var results = []; + eachfn(arr, function (x, index, callback) { + iterator(x, function (v) { + if (v) { + results.push({index: index, value: x}); + } + callback(); + }); + }, function () { + callback(_map(results.sort(function (a, b) { + return a.index - b.index; + }), function (x) { + return x.value; + })); + }); + } + + async.select = + async.filter = doParallel(_filter); + + async.selectLimit = + async.filterLimit = doParallelLimit(_filter); + + async.selectSeries = + async.filterSeries = doSeries(_filter); + + function _reject(eachfn, arr, iterator, callback) { + _filter(eachfn, arr, function(value, cb) { + iterator(value, function(v) { + cb(!v); + }); + }, callback); + } + async.reject = doParallel(_reject); + async.rejectLimit = doParallelLimit(_reject); + async.rejectSeries = doSeries(_reject); + + function _createTester(eachfn, check, getResult) { + return function(arr, limit, iterator, cb) { + function done() { + if (cb) cb(getResult(false, void 0)); + } + function iteratee(x, _, callback) { + if (!cb) return callback(); + iterator(x, function (v) { + if (cb && check(v)) { + cb(getResult(true, x)); + cb = iterator = false; + } + callback(); + }); + } + if (arguments.length > 3) { + eachfn(arr, limit, iteratee, done); + } else { + cb = iterator; + iterator = limit; + eachfn(arr, iteratee, done); + } + }; + } + + async.any = + async.some = _createTester(async.eachOf, toBool, identity); + + async.someLimit = _createTester(async.eachOfLimit, toBool, identity); + + async.all = + async.every = _createTester(async.eachOf, notId, notId); + + async.everyLimit = _createTester(async.eachOfLimit, notId, notId); + + function _findGetResult(v, x) { + return x; + } + async.detect = _createTester(async.eachOf, identity, _findGetResult); + async.detectSeries = _createTester(async.eachOfSeries, identity, _findGetResult); + async.detectLimit = _createTester(async.eachOfLimit, identity, _findGetResult); + + async.sortBy = function (arr, iterator, callback) { + async.map(arr, function (x, callback) { + iterator(x, function (err, criteria) { + if (err) { + callback(err); + } + else { + callback(null, {value: x, criteria: criteria}); + } + }); + }, function (err, results) { + if (err) { + return callback(err); + } + else { + callback(null, _map(results.sort(comparator), function (x) { + return x.value; + })); + } + + }); + + function comparator(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + } + }; + + async.auto = function (tasks, concurrency, callback) { + if (typeof arguments[1] === 'function') { + // concurrency is optional, shift the args. + callback = concurrency; + concurrency = null; + } + callback = _once(callback || noop); + var keys = _keys(tasks); + var remainingTasks = keys.length; + if (!remainingTasks) { + return callback(null); + } + if (!concurrency) { + concurrency = remainingTasks; + } + + var results = {}; + var runningTasks = 0; + + var hasError = false; + + var listeners = []; + function addListener(fn) { + listeners.unshift(fn); + } + function removeListener(fn) { + var idx = _indexOf(listeners, fn); + if (idx >= 0) listeners.splice(idx, 1); + } + function taskComplete() { + remainingTasks--; + _arrayEach(listeners.slice(0), function (fn) { + fn(); + }); + } + + addListener(function () { + if (!remainingTasks) { + callback(null, results); + } + }); + + _arrayEach(keys, function (k) { + if (hasError) return; + var task = _isArray(tasks[k]) ? tasks[k]: [tasks[k]]; + var taskCallback = _restParam(function(err, args) { + runningTasks--; + if (args.length <= 1) { + args = args[0]; + } + if (err) { + var safeResults = {}; + _forEachOf(results, function(val, rkey) { + safeResults[rkey] = val; + }); + safeResults[k] = args; + hasError = true; + + callback(err, safeResults); + } + else { + results[k] = args; + async.setImmediate(taskComplete); + } + }); + var requires = task.slice(0, task.length - 1); + // prevent dead-locks + var len = requires.length; + var dep; + while (len--) { + if (!(dep = tasks[requires[len]])) { + throw new Error('Has nonexistent dependency in ' + requires.join(', ')); + } + if (_isArray(dep) && _indexOf(dep, k) >= 0) { + throw new Error('Has cyclic dependencies'); + } + } + function ready() { + return runningTasks < concurrency && _reduce(requires, function (a, x) { + return (a && results.hasOwnProperty(x)); + }, true) && !results.hasOwnProperty(k); + } + if (ready()) { + runningTasks++; + task[task.length - 1](taskCallback, results); + } + else { + addListener(listener); + } + function listener() { + if (ready()) { + runningTasks++; + removeListener(listener); + task[task.length - 1](taskCallback, results); + } + } + }); + }; + + + + async.retry = function(times, task, callback) { + var DEFAULT_TIMES = 5; + var DEFAULT_INTERVAL = 0; + + var attempts = []; + + var opts = { + times: DEFAULT_TIMES, + interval: DEFAULT_INTERVAL + }; + + function parseTimes(acc, t){ + if(typeof t === 'number'){ + acc.times = parseInt(t, 10) || DEFAULT_TIMES; + } else if(typeof t === 'object'){ + acc.times = parseInt(t.times, 10) || DEFAULT_TIMES; + acc.interval = parseInt(t.interval, 10) || DEFAULT_INTERVAL; + } else { + throw new Error('Unsupported argument type for \'times\': ' + typeof t); + } + } + + var length = arguments.length; + if (length < 1 || length > 3) { + throw new Error('Invalid arguments - must be either (task), (task, callback), (times, task) or (times, task, callback)'); + } else if (length <= 2 && typeof times === 'function') { + callback = task; + task = times; + } + if (typeof times !== 'function') { + parseTimes(opts, times); + } + opts.callback = callback; + opts.task = task; + + function wrappedTask(wrappedCallback, wrappedResults) { + function retryAttempt(task, finalAttempt) { + return function(seriesCallback) { + task(function(err, result){ + seriesCallback(!err || finalAttempt, {err: err, result: result}); + }, wrappedResults); + }; + } + + function retryInterval(interval){ + return function(seriesCallback){ + setTimeout(function(){ + seriesCallback(null); + }, interval); + }; + } + + while (opts.times) { + + var finalAttempt = !(opts.times-=1); + attempts.push(retryAttempt(opts.task, finalAttempt)); + if(!finalAttempt && opts.interval > 0){ + attempts.push(retryInterval(opts.interval)); + } + } + + async.series(attempts, function(done, data){ + data = data[data.length - 1]; + (wrappedCallback || opts.callback)(data.err, data.result); + }); + } + + // If a callback is passed, run this as a controll flow + return opts.callback ? wrappedTask() : wrappedTask; + }; + + async.waterfall = function (tasks, callback) { + callback = _once(callback || noop); + if (!_isArray(tasks)) { + var err = new Error('First argument to waterfall must be an array of functions'); + return callback(err); + } + if (!tasks.length) { + return callback(); + } + function wrapIterator(iterator) { + return _restParam(function (err, args) { + if (err) { + callback.apply(null, [err].concat(args)); + } + else { + var next = iterator.next(); + if (next) { + args.push(wrapIterator(next)); + } + else { + args.push(callback); + } + ensureAsync(iterator).apply(null, args); + } + }); + } + wrapIterator(async.iterator(tasks))(); + }; + + function _parallel(eachfn, tasks, callback) { + callback = callback || noop; + var results = _isArrayLike(tasks) ? [] : {}; + + eachfn(tasks, function (task, key, callback) { + task(_restParam(function (err, args) { + if (args.length <= 1) { + args = args[0]; + } + results[key] = args; + callback(err); + })); + }, function (err) { + callback(err, results); + }); + } + + async.parallel = function (tasks, callback) { + _parallel(async.eachOf, tasks, callback); + }; + + async.parallelLimit = function(tasks, limit, callback) { + _parallel(_eachOfLimit(limit), tasks, callback); + }; + + async.series = function(tasks, callback) { + _parallel(async.eachOfSeries, tasks, callback); + }; + + async.iterator = function (tasks) { + function makeCallback(index) { + function fn() { + if (tasks.length) { + tasks[index].apply(null, arguments); + } + return fn.next(); + } + fn.next = function () { + return (index < tasks.length - 1) ? makeCallback(index + 1): null; + }; + return fn; + } + return makeCallback(0); + }; + + async.apply = _restParam(function (fn, args) { + return _restParam(function (callArgs) { + return fn.apply( + null, args.concat(callArgs) + ); + }); + }); + + function _concat(eachfn, arr, fn, callback) { + var result = []; + eachfn(arr, function (x, index, cb) { + fn(x, function (err, y) { + result = result.concat(y || []); + cb(err); + }); + }, function (err) { + callback(err, result); + }); + } + async.concat = doParallel(_concat); + async.concatSeries = doSeries(_concat); + + async.whilst = function (test, iterator, callback) { + callback = callback || noop; + if (test()) { + var next = _restParam(function(err, args) { + if (err) { + callback(err); + } else if (test.apply(this, args)) { + iterator(next); + } else { + callback.apply(null, [null].concat(args)); + } + }); + iterator(next); + } else { + callback(null); + } + }; + + async.doWhilst = function (iterator, test, callback) { + var calls = 0; + return async.whilst(function() { + return ++calls <= 1 || test.apply(this, arguments); + }, iterator, callback); + }; + + async.until = function (test, iterator, callback) { + return async.whilst(function() { + return !test.apply(this, arguments); + }, iterator, callback); + }; + + async.doUntil = function (iterator, test, callback) { + return async.doWhilst(iterator, function() { + return !test.apply(this, arguments); + }, callback); + }; + + async.during = function (test, iterator, callback) { + callback = callback || noop; + + var next = _restParam(function(err, args) { + if (err) { + callback(err); + } else { + args.push(check); + test.apply(this, args); + } + }); + + var check = function(err, truth) { + if (err) { + callback(err); + } else if (truth) { + iterator(next); + } else { + callback(null); + } + }; + + test(check); + }; + + async.doDuring = function (iterator, test, callback) { + var calls = 0; + async.during(function(next) { + if (calls++ < 1) { + next(null, true); + } else { + test.apply(this, arguments); + } + }, iterator, callback); + }; + + function _queue(worker, concurrency, payload) { + if (concurrency == null) { + concurrency = 1; + } + else if(concurrency === 0) { + throw new Error('Concurrency must not be zero'); + } + function _insert(q, data, pos, callback) { + if (callback != null && typeof callback !== "function") { + throw new Error("task callback must be a function"); + } + q.started = true; + if (!_isArray(data)) { + data = [data]; + } + if(data.length === 0 && q.idle()) { + // call drain immediately if there are no tasks + return async.setImmediate(function() { + q.drain(); + }); + } + _arrayEach(data, function(task) { + var item = { + data: task, + callback: callback || noop + }; + + if (pos) { + q.tasks.unshift(item); + } else { + q.tasks.push(item); + } + + if (q.tasks.length === q.concurrency) { + q.saturated(); + } + }); + async.setImmediate(q.process); + } + function _next(q, tasks) { + return function(){ + workers -= 1; + + var removed = false; + var args = arguments; + _arrayEach(tasks, function (task) { + _arrayEach(workersList, function (worker, index) { + if (worker === task && !removed) { + workersList.splice(index, 1); + removed = true; + } + }); + + task.callback.apply(task, args); + }); + if (q.tasks.length + workers === 0) { + q.drain(); + } + q.process(); + }; + } + + var workers = 0; + var workersList = []; + var q = { + tasks: [], + concurrency: concurrency, + payload: payload, + saturated: noop, + empty: noop, + drain: noop, + started: false, + paused: false, + push: function (data, callback) { + _insert(q, data, false, callback); + }, + kill: function () { + q.drain = noop; + q.tasks = []; + }, + unshift: function (data, callback) { + _insert(q, data, true, callback); + }, + process: function () { + while(!q.paused && workers < q.concurrency && q.tasks.length){ + + var tasks = q.payload ? + q.tasks.splice(0, q.payload) : + q.tasks.splice(0, q.tasks.length); + + var data = _map(tasks, function (task) { + return task.data; + }); + + if (q.tasks.length === 0) { + q.empty(); + } + workers += 1; + workersList.push(tasks[0]); + var cb = only_once(_next(q, tasks)); + worker(data, cb); + } + }, + length: function () { + return q.tasks.length; + }, + running: function () { + return workers; + }, + workersList: function () { + return workersList; + }, + idle: function() { + return q.tasks.length + workers === 0; + }, + pause: function () { + q.paused = true; + }, + resume: function () { + if (q.paused === false) { return; } + q.paused = false; + var resumeCount = Math.min(q.concurrency, q.tasks.length); + // Need to call q.process once per concurrent + // worker to preserve full concurrency after pause + for (var w = 1; w <= resumeCount; w++) { + async.setImmediate(q.process); + } + } + }; + return q; + } + + async.queue = function (worker, concurrency) { + var q = _queue(function (items, cb) { + worker(items[0], cb); + }, concurrency, 1); + + return q; + }; + + async.priorityQueue = function (worker, concurrency) { + + function _compareTasks(a, b){ + return a.priority - b.priority; + } + + function _binarySearch(sequence, item, compare) { + var beg = -1, + end = sequence.length - 1; + while (beg < end) { + var mid = beg + ((end - beg + 1) >>> 1); + if (compare(item, sequence[mid]) >= 0) { + beg = mid; + } else { + end = mid - 1; + } + } + return beg; + } + + function _insert(q, data, priority, callback) { + if (callback != null && typeof callback !== "function") { + throw new Error("task callback must be a function"); + } + q.started = true; + if (!_isArray(data)) { + data = [data]; + } + if(data.length === 0) { + // call drain immediately if there are no tasks + return async.setImmediate(function() { + q.drain(); + }); + } + _arrayEach(data, function(task) { + var item = { + data: task, + priority: priority, + callback: typeof callback === 'function' ? callback : noop + }; + + q.tasks.splice(_binarySearch(q.tasks, item, _compareTasks) + 1, 0, item); + + if (q.tasks.length === q.concurrency) { + q.saturated(); + } + async.setImmediate(q.process); + }); + } + + // Start with a normal queue + var q = async.queue(worker, concurrency); + + // Override push to accept second parameter representing priority + q.push = function (data, priority, callback) { + _insert(q, data, priority, callback); + }; + + // Remove unshift function + delete q.unshift; + + return q; + }; + + async.cargo = function (worker, payload) { + return _queue(worker, 1, payload); + }; + + function _console_fn(name) { + return _restParam(function (fn, args) { + fn.apply(null, args.concat([_restParam(function (err, args) { + if (typeof console === 'object') { + if (err) { + if (console.error) { + console.error(err); + } + } + else if (console[name]) { + _arrayEach(args, function (x) { + console[name](x); + }); + } + } + })])); + }); + } + async.log = _console_fn('log'); + async.dir = _console_fn('dir'); + /*async.info = _console_fn('info'); + async.warn = _console_fn('warn'); + async.error = _console_fn('error');*/ + + async.memoize = function (fn, hasher) { + var memo = {}; + var queues = {}; + var has = Object.prototype.hasOwnProperty; + hasher = hasher || identity; + var memoized = _restParam(function memoized(args) { + var callback = args.pop(); + var key = hasher.apply(null, args); + if (has.call(memo, key)) { + async.setImmediate(function () { + callback.apply(null, memo[key]); + }); + } + else if (has.call(queues, key)) { + queues[key].push(callback); + } + else { + queues[key] = [callback]; + fn.apply(null, args.concat([_restParam(function (args) { + memo[key] = args; + var q = queues[key]; + delete queues[key]; + for (var i = 0, l = q.length; i < l; i++) { + q[i].apply(null, args); + } + })])); + } + }); + memoized.memo = memo; + memoized.unmemoized = fn; + return memoized; + }; + + async.unmemoize = function (fn) { + return function () { + return (fn.unmemoized || fn).apply(null, arguments); + }; + }; + + function _times(mapper) { + return function (count, iterator, callback) { + mapper(_range(count), iterator, callback); + }; + } + + async.times = _times(async.map); + async.timesSeries = _times(async.mapSeries); + async.timesLimit = function (count, limit, iterator, callback) { + return async.mapLimit(_range(count), limit, iterator, callback); + }; + + async.seq = function (/* functions... */) { + var fns = arguments; + return _restParam(function (args) { + var that = this; + + var callback = args[args.length - 1]; + if (typeof callback == 'function') { + args.pop(); + } else { + callback = noop; + } + + async.reduce(fns, args, function (newargs, fn, cb) { + fn.apply(that, newargs.concat([_restParam(function (err, nextargs) { + cb(err, nextargs); + })])); + }, + function (err, results) { + callback.apply(that, [err].concat(results)); + }); + }); + }; + + async.compose = function (/* functions... */) { + return async.seq.apply(null, Array.prototype.reverse.call(arguments)); + }; + + + function _applyEach(eachfn) { + return _restParam(function(fns, args) { + var go = _restParam(function(args) { + var that = this; + var callback = args.pop(); + return eachfn(fns, function (fn, _, cb) { + fn.apply(that, args.concat([cb])); + }, + callback); + }); + if (args.length) { + return go.apply(this, args); + } + else { + return go; + } + }); + } + + async.applyEach = _applyEach(async.eachOf); + async.applyEachSeries = _applyEach(async.eachOfSeries); + + + async.forever = function (fn, callback) { + var done = only_once(callback || noop); + var task = ensureAsync(fn); + function next(err) { + if (err) { + return done(err); + } + task(next); + } + next(); + }; + + function ensureAsync(fn) { + return _restParam(function (args) { + var callback = args.pop(); + args.push(function () { + var innerArgs = arguments; + if (sync) { + async.setImmediate(function () { + callback.apply(null, innerArgs); + }); + } else { + callback.apply(null, innerArgs); + } + }); + var sync = true; + fn.apply(this, args); + sync = false; + }); + } + + async.ensureAsync = ensureAsync; + + async.constant = _restParam(function(values) { + var args = [null].concat(values); + return function (callback) { + return callback.apply(this, args); + }; + }); + + async.wrapSync = + async.asyncify = function asyncify(func) { + return _restParam(function (args) { + var callback = args.pop(); + var result; + try { + result = func.apply(this, args); + } catch (e) { + return callback(e); + } + // if result is Promise object + if (_isObject(result) && typeof result.then === "function") { + result.then(function(value) { + callback(null, value); + })["catch"](function(err) { + callback(err.message ? err : new Error(err)); + }); + } else { + callback(null, result); + } + }); + }; + + // Node.js + if (typeof module === 'object' && module.exports) { + module.exports = async; + } + // AMD / RequireJS + else if (typeof define === 'function' && define.amd) { + define([], function () { + return async; + }); + } + // included directly via