From b7fe455c935569a05d15baa9cf8a16299a553ccd Mon Sep 17 00:00:00 2001 From: Hendrixer Date: Wed, 22 Jul 2015 03:13:10 -0500 Subject: [PATCH 01/22] chore --- README.md | 7 +------ index.html | 10 ++++++++++ server.js | 20 ++++++++++++++++---- 3 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 index.html diff --git a/README.md b/README.md index 1e2c8d4..8bdf250 100644 --- a/README.md +++ b/README.md @@ -1,6 +1 @@ -##Getting started -* `npm i` - -##Todo - -create a basic web server with expressthat can handle a GET request for whatever resource you'd like and whatever url you want. Navigate to that url in the browser and see if yuor resource is there. The solution is on the `step-1-fix` branch +##Solution to step-1 diff --git a/index.html b/index.html new file mode 100644 index 0000000..1667638 --- /dev/null +++ b/index.html @@ -0,0 +1,10 @@ + + + + + hello + + +

hey there

+ + diff --git a/server.js b/server.js index 80f064e..62e12ab 100644 --- a/server.js +++ b/server.js @@ -1,4 +1,16 @@ -// TODO: create a basic server with express -// that can handle a GET request for what ever resource you'd like -// whatever url you want, and then navigate to that url in the browser and -// see if yuor resource is there. +var express = require('express'); +var app = express(); + +app.get('/', function(req, res){ + res.sendFile(__dirname + '/index.html', function(err) { + if (err) { + res.status(500).send(err); + } + }) +}); + + +var port = 3000; +app.listen(port, function(){ + console.log('listening on http://localhost:', port); +}); From de8a7df4c03ea00420ff062b15f78a8659869207 Mon Sep 17 00:00:00 2001 From: Hendrixer Date: Wed, 22 Jul 2015 03:18:20 -0500 Subject: [PATCH 02/22] chore --- server.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/server.js b/server.js index 62e12ab..65828b1 100644 --- a/server.js +++ b/server.js @@ -1,7 +1,11 @@ var express = require('express'); var app = express(); +var jsonData = {count: 12, message: 'hey'}; + app.get('/', function(req, res){ + // res.sendFile takes an absolute path to a file and + // sets the mime type based n the file extname res.sendFile(__dirname + '/index.html', function(err) { if (err) { res.status(500).send(err); @@ -9,6 +13,10 @@ app.get('/', function(req, res){ }) }); +app.get('/data', function(req, res) { + res.json(jsonData); +}); + var port = 3000; app.listen(port, function(){ From 1db5de0a76b0bb12d38137094c7349eb71e5de36 Mon Sep 17 00:00:00 2001 From: Hendrixer Date: Wed, 22 Jul 2015 04:36:20 -0500 Subject: [PATCH 03/22] chore --- client/app.js | 543 ++++++++++++++++++++++++++++++++++++++++++++++ client/index.html | 48 ++++ client/style.css | 542 +++++++++++++++++++++++++++++++++++++++++++++ index.html | 10 - server.js | 24 -- server/server.js | 49 +++++ 6 files changed, 1182 insertions(+), 34 deletions(-) create mode 100644 client/app.js create mode 100644 client/index.html create mode 100644 client/style.css delete mode 100644 index.html delete mode 100644 server.js create mode 100644 server/server.js diff --git a/client/app.js b/client/app.js new file mode 100644 index 0000000..1351400 --- /dev/null +++ b/client/app.js @@ -0,0 +1,543 @@ +/** + * @license + * lodash 3.10.1 (Custom Build) lodash.com/license | Underscore.js 1.8.3 underscorejs.org/LICENSE + * Build: `lodash modern -o ./lodash.js` + */ +;(function(){function n(n,t){if(n!==t){var r=null===n,e=n===w,u=n===n,o=null===t,i=t===w,f=t===t;if(n>t&&!o||!u||r&&!i&&f||e&&f)return 1;if(n=n&&9<=n&&13>=n||32==n||160==n||5760==n||6158==n||8192<=n&&(8202>=n||8232==n||8233==n||8239==n||8287==n||12288==n||65279==n); +}function v(n,t){for(var r=-1,e=n.length,u=-1,o=[];++r=F&&gu&&lu?new Dn(t):null,c=t.length;a&&(i=Mn,f=false,t=a);n:for(;++oi(t,a,0)&&u.push(a);return u}function at(n,t){var r=true;return Su(n,function(n,e,u){return r=!!t(n,e,u)}),r}function ct(n,t,r,e){var u=e,o=u;return Su(n,function(n,i,f){i=+t(n,i,f),(r(i,u)||i===e&&i===o)&&(u=i, +o=n)}),o}function lt(n,t){var r=[];return Su(n,function(n,e,u){t(n,e,u)&&r.push(n)}),r}function st(n,t,r,e){var u;return r(n,function(n,r,o){return t(n,r,o)?(u=e?r:n,false):void 0}),u}function pt(n,t,r,e){e||(e=[]);for(var u=-1,o=n.length;++ut&&(t=-t>u?0:u+t),r=r===w||r>u?u:+r||0,0>r&&(r+=u),u=t>r?0:r-t>>>0,t>>>=0,r=Be(u);++e=c)break n;o=e[o],u*="asc"===o||true===o?1:-1;break n}u=t.b-r.b}return u})}function $t(n,t){ +var r=0;return Su(n,function(n,e,u){r+=+t(n,e,u)||0}),r}function St(n,t){var e=-1,u=xr(),o=n.length,i=u===r,f=i&&o>=F,a=f&&gu&&lu?new Dn(void 0):null,c=[];a?(u=Mn,i=false):(f=false,a=t?[]:c);n:for(;++eu(a,s,0)&&((t||f)&&a.push(s),c.push(l))}return c}function Ft(n,t){for(var r=-1,e=t.length,u=Be(e);++r>>1,i=n[o];(r?i<=t:iu?w:o,u=1);++e=F)return t.plant(e).value();for(var u=0,n=r?o[u].apply(this,n):e;++uarguments.length;return typeof e=="function"&&o===w&&Oo(r)?n(r,e,u,i):Ot(r,wr(e,o,4),u,i,t)}}function sr(n,t,r,e,u,o,i,f,a,c){function l(){for(var m=arguments.length,b=m,j=Be(m);b--;)j[b]=arguments[b];if(e&&(j=Mt(j,e,u)),o&&(j=qt(j,o,i)),_||y){var b=l.placeholder,k=v(j,b),m=m-k.length;if(mt?0:t)):[]}function Pr(n,t,r){var e=n?n.length:0;return e?((r?Ur(n,t,r):null==t)&&(t=1),t=e-(+t||0),Et(n,0,0>t?0:t)):[]}function Kr(n){return n?n[0]:w}function Vr(n,t,e){var u=n?n.length:0;if(!u)return-1;if(typeof e=="number")e=0>e?bu(u+e,0):e;else if(e)return e=Lt(n,t), +er?bu(u+r,0):r||0,typeof n=="string"||!Oo(n)&&be(n)?r<=u&&-1t?0:+t||0,e);++r=n&&(t=w),r}}function ae(n,t,r){function e(t,r){r&&iu(r),a=p=h=w,t&&(_=ho(),c=n.apply(s,f),p||a||(f=s=w))}function u(){var n=t-(ho()-l);0>=n||n>t?e(h,a):p=su(u,n)}function o(){e(g,p); +}function i(){if(f=arguments,l=ho(),s=this,h=g&&(p||!y),false===v)var r=y&&!p;else{a||y||(_=l);var e=v-(l-_),i=0>=e||e>v;i?(a&&(a=iu(a)),_=l,c=n.apply(s,f)):a||(a=su(o,e))}return i&&p?p=iu(p):p||t===v||(p=su(u,t)),r&&(i=true,c=n.apply(s,f)),!i||p||a||(f=s=w),c}var f,a,c,l,s,p,h,_=0,v=false,g=true;if(typeof n!="function")throw new Ge(L);if(t=0>t?0:+t||0,true===r)var y=true,g=false;else ge(r)&&(y=!!r.leading,v="maxWait"in r&&bu(+r.maxWait||0,t),g="trailing"in r?!!r.trailing:g);return i.cancel=function(){p&&iu(p),a&&iu(a), +_=0,a=p=h=w},i}function ce(n,t){function r(){var e=arguments,u=t?t.apply(this,e):e[0],o=r.cache;return o.has(u)?o.get(u):(e=n.apply(this,e),r.cache=o.set(u,e),e)}if(typeof n!="function"||t&&typeof t!="function")throw new Ge(L);return r.cache=new ce.Cache,r}function le(n,t){if(typeof n!="function")throw new Ge(L);return t=bu(t===w?n.length-1:+t||0,0),function(){for(var r=arguments,e=-1,u=bu(r.length-t,0),o=Be(u);++et}function pe(n){return h(n)&&Er(n)&&nu.call(n,"callee")&&!cu.call(n,"callee")}function he(n,t,r,e){return e=(r=typeof r=="function"?Bt(r,e,3):w)?r(n,t):w,e===w?dt(n,t,r):!!e}function _e(n){return h(n)&&typeof n.message=="string"&&ru.call(n)==P}function ve(n){return ge(n)&&ru.call(n)==K}function ge(n){var t=typeof n;return!!n&&("object"==t||"function"==t)}function ye(n){ +return null==n?false:ve(n)?uu.test(Qe.call(n)):h(n)&&Rn.test(n)}function de(n){return typeof n=="number"||h(n)&&ru.call(n)==V}function me(n){var t;if(!h(n)||ru.call(n)!=Z||pe(n)||!(nu.call(n,"constructor")||(t=n.constructor,typeof t!="function"||t instanceof t)))return false;var r;return ht(n,function(n,t){r=t}),r===w||nu.call(n,r)}function we(n){return ge(n)&&ru.call(n)==Y}function be(n){return typeof n=="string"||h(n)&&ru.call(n)==G}function xe(n){return h(n)&&Sr(n.length)&&!!Sn[ru.call(n)]}function Ae(n,t){ +return nt||!n||!mu(t))return r;do t%2&&(r+=n),t=yu(t/2),n+=n;while(t);return r}function We(n,t,r){var e=n;return(n=u(n))?(r?Ur(e,t,r):null==t)?n.slice(g(n),y(n)+1):(t+="",n.slice(o(n,t),i(n,t)+1)):n}function $e(n,t,r){return r&&Ur(n,t,r)&&(t=w),n=u(n),n.match(t||Wn)||[]}function Se(n,t,r){return r&&Ur(n,t,r)&&(t=w),h(n)?Ne(n):ut(n,t)}function Fe(n){ +return n}function Ne(n){return bt(ot(n,true))}function Te(n,t,r){if(null==r){var e=ge(t),u=e?zo(t):w;((u=u&&u.length?gt(t,u):w)?u.length:e)||(u=false,r=t,t=n,n=this)}u||(u=gt(t,zo(t)));var o=true,e=-1,i=ve(n),f=u.length;false===r?o=false:ge(r)&&"chain"in r&&(o=r.chain);for(;++e=$)return r}else n=0;return Lu(r,e)}}(),Mu=le(function(n,t){ +return h(n)&&Er(n)?ft(n,pt(t,false,true)):[]}),qu=tr(),Pu=tr(true),Ku=le(function(n){for(var t=n.length,e=t,u=Be(l),o=xr(),i=o===r,f=[];e--;){var a=n[e]=Er(a=n[e])?a:[];u[e]=i&&120<=a.length&&gu&&lu?new Dn(e&&a):null}var i=n[0],c=-1,l=i?i.length:0,s=u[0];n:for(;++c(s?Mn(s,a):o(f,a,0))){for(e=t;--e;){var p=u[e];if(0>(p?Mn(p,a):o(n[e],a,0)))continue n}s&&s.push(a),f.push(a)}return f}),Vu=le(function(t,r){r=pt(r);var e=rt(t,r);return It(t,r.sort(n)),e}),Zu=vr(),Yu=vr(true),Gu=le(function(n){return St(pt(n,false,true)); +}),Ju=le(function(n,t){return Er(n)?ft(n,t):[]}),Xu=le(Jr),Hu=le(function(n){var t=n.length,r=2--n?t.apply(this,arguments):void 0}},Nn.ary=function(n,t,r){return r&&Ur(n,t,r)&&(t=w),t=n&&null==t?n.length:bu(+t||0,0),gr(n,E,w,w,w,w,t)},Nn.assign=Co,Nn.at=no,Nn.before=fe,Nn.bind=_o,Nn.bindAll=vo,Nn.bindKey=go,Nn.callback=Se,Nn.chain=Qr,Nn.chunk=function(n,t,r){t=(r?Ur(n,t,r):null==t)?1:bu(yu(t)||1,1),r=0;for(var e=n?n.length:0,u=-1,o=Be(vu(e/t));rr&&(r=-r>u?0:u+r),e=e===w||e>u?u:+e||0,0>e&&(e+=u),u=r>e?0:e>>>0,r>>>=0;rt?0:t)):[]},Nn.takeRight=function(n,t,r){var e=n?n.length:0;return e?((r?Ur(n,t,r):null==t)&&(t=1),t=e-(+t||0),Et(n,0>t?0:t)):[]},Nn.takeRightWhile=function(n,t,r){ +return n&&n.length?Nt(n,wr(t,r,3),false,true):[]},Nn.takeWhile=function(n,t,r){return n&&n.length?Nt(n,wr(t,r,3)):[]},Nn.tap=function(n,t,r){return t.call(r,n),n},Nn.throttle=function(n,t,r){var e=true,u=true;if(typeof n!="function")throw new Ge(L);return false===r?e=false:ge(r)&&(e="leading"in r?!!r.leading:e,u="trailing"in r?!!r.trailing:u),ae(n,t,{leading:e,maxWait:+t,trailing:u})},Nn.thru=ne,Nn.times=function(n,t,r){if(n=yu(n),1>n||!mu(n))return[];var e=-1,u=Be(xu(n,4294967295));for(t=Bt(t,r,1);++ee?u[e]=t(e):t(e); +return u},Nn.toArray=je,Nn.toPlainObject=ke,Nn.transform=function(n,t,r,e){var u=Oo(n)||xe(n);return t=wr(t,e,4),null==r&&(u||ge(n)?(e=n.constructor,r=u?Oo(n)?new e:[]:$u(ve(e)?e.prototype:w)):r={}),(u?Pn:_t)(n,function(n,e,u){return t(r,n,e,u)}),r},Nn.union=Gu,Nn.uniq=Gr,Nn.unzip=Jr,Nn.unzipWith=Xr,Nn.values=Ee,Nn.valuesIn=function(n){return Ft(n,Re(n))},Nn.where=function(n,t){return re(n,bt(t))},Nn.without=Ju,Nn.wrap=function(n,t){return t=null==t?Fe:t,gr(t,R,w,[n],[])},Nn.xor=function(){for(var n=-1,t=arguments.length;++nr?0:+r||0,e),r-=t.length,0<=r&&n.indexOf(t,r)==r},Nn.escape=function(n){return(n=u(n))&&hn.test(n)?n.replace(sn,c):n},Nn.escapeRegExp=function(n){return(n=u(n))&&bn.test(n)?n.replace(wn,l):n||"(?:)"},Nn.every=te,Nn.find=ro,Nn.findIndex=qu,Nn.findKey=$o,Nn.findLast=eo, +Nn.findLastIndex=Pu,Nn.findLastKey=So,Nn.findWhere=function(n,t){return ro(n,bt(t))},Nn.first=Kr,Nn.floor=ni,Nn.get=function(n,t,r){return n=null==n?w:yt(n,Dr(t),t+""),n===w?r:n},Nn.gt=se,Nn.gte=function(n,t){return n>=t},Nn.has=function(n,t){if(null==n)return false;var r=nu.call(n,t);if(!r&&!Wr(t)){if(t=Dr(t),n=1==t.length?n:yt(n,Et(t,0,-1)),null==n)return false;t=Zr(t),r=nu.call(n,t)}return r||Sr(n.length)&&Cr(t,n.length)&&(Oo(n)||pe(n))},Nn.identity=Fe,Nn.includes=ee,Nn.indexOf=Vr,Nn.inRange=function(n,t,r){ +return t=+t||0,r===w?(r=t,t=0):r=+r||0,n>=xu(t,r)&&nr?bu(e+r,0):xu(r||0,e-1))+1;else if(r)return u=Lt(n,t,true)-1,n=n[u],(t===t?t===n:n!==n)?u:-1; +if(t!==t)return p(n,u,true);for(;u--;)if(n[u]===t)return u;return-1},Nn.lt=Ae,Nn.lte=function(n,t){return n<=t},Nn.max=ti,Nn.min=ri,Nn.noConflict=function(){return Zn._=eu,this},Nn.noop=Le,Nn.now=ho,Nn.pad=function(n,t,r){n=u(n),t=+t;var e=n.length;return er?0:+r||0,n.length),n.lastIndexOf(t,r)==r},Nn.sum=function(n,t,r){if(r&&Ur(n,t,r)&&(t=w),t=wr(t,r,3),1==t.length){n=Oo(n)?n:zr(n),r=n.length;for(var e=0;r--;)e+=+t(n[r])||0;n=e}else n=$t(n,t);return n},Nn.template=function(n,t,r){var e=Nn.templateSettings;r&&Ur(n,t,r)&&(t=r=w),n=u(n),t=nt(tt({},r||t),e,Qn),r=nt(tt({},t.imports),e.imports,Qn); +var o,i,f=zo(r),a=Ft(r,f),c=0;r=t.interpolate||Cn;var l="__p+='";r=Ze((t.escape||Cn).source+"|"+r.source+"|"+(r===gn?jn:Cn).source+"|"+(t.evaluate||Cn).source+"|$","g");var p="sourceURL"in t?"//# sourceURL="+t.sourceURL+"\n":"";if(n.replace(r,function(t,r,e,u,f,a){return e||(e=u),l+=n.slice(c,a).replace(Un,s),r&&(o=true,l+="'+__e("+r+")+'"),f&&(i=true,l+="';"+f+";\n__p+='"),e&&(l+="'+((__t=("+e+"))==null?'':__t)+'"),c=a+t.length,t}),l+="';",(t=t.variable)||(l="with(obj){"+l+"}"),l=(i?l.replace(fn,""):l).replace(an,"$1").replace(cn,"$1;"), +l="function("+(t||"obj")+"){"+(t?"":"obj||(obj={});")+"var __t,__p=''"+(o?",__e=_.escape":"")+(i?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+l+"return __p}",t=Jo(function(){return qe(f,p+"return "+l).apply(w,a)}),t.source=l,_e(t))throw t;return t},Nn.trim=We,Nn.trimLeft=function(n,t,r){var e=n;return(n=u(n))?n.slice((r?Ur(e,t,r):null==t)?g(n):o(n,t+"")):n},Nn.trimRight=function(n,t,r){var e=n;return(n=u(n))?(r?Ur(e,t,r):null==t)?n.slice(0,y(n)+1):n.slice(0,i(n,t+"")+1):n; +},Nn.trunc=function(n,t,r){r&&Ur(n,t,r)&&(t=w);var e=U;if(r=W,null!=t)if(ge(t)){var o="separator"in t?t.separator:o,e="length"in t?+t.length||0:e;r="omission"in t?u(t.omission):r}else e=+t||0;if(n=u(n),e>=n.length)return n;if(e-=r.length,1>e)return r;if(t=n.slice(0,e),null==o)return t+r;if(we(o)){if(n.slice(e).search(o)){var i,f=n.slice(0,e);for(o.global||(o=Ze(o.source,(kn.exec(o)||"")+"g")),o.lastIndex=0;n=o.exec(f);)i=n.index;t=t.slice(0,null==i?e:i)}}else n.indexOf(o,e)!=e&&(o=t.lastIndexOf(o), +-1u.__dir__?"Right":"")}),u},zn.prototype[n+"Right"]=function(t){return this.reverse()[n](t).reverse()}}),Pn(["filter","map","takeWhile"],function(n,t){ +var r=t+1,e=r!=T;zn.prototype[n]=function(n,t){var u=this.clone();return u.__iteratees__.push({iteratee:wr(n,t,1),type:r}),u.__filtered__=u.__filtered__||e,u}}),Pn(["first","last"],function(n,t){var r="take"+(t?"Right":"");zn.prototype[n]=function(){return this[r](1).value()[0]}}),Pn(["initial","rest"],function(n,t){var r="drop"+(t?"":"Right");zn.prototype[n]=function(){return this.__filtered__?new zn(this):this[r](1)}}),Pn(["pluck","where"],function(n,t){var r=t?"filter":"map",e=t?bt:ze;zn.prototype[n]=function(n){ +return this[r](e(n))}}),zn.prototype.compact=function(){return this.filter(Fe)},zn.prototype.reject=function(n,t){return n=wr(n,t,1),this.filter(function(t){return!n(t)})},zn.prototype.slice=function(n,t){n=null==n?0:+n||0;var r=this;return r.__filtered__&&(0t)?new zn(r):(0>n?r=r.takeRight(-n):n&&(r=r.drop(n)),t!==w&&(t=+t||0,r=0>t?r.dropRight(-t):r.take(t-n)),r)},zn.prototype.takeRightWhile=function(n,t){return this.reverse().takeWhile(n,t).reverse()},zn.prototype.toArray=function(){return this.take(Ru); +},_t(zn.prototype,function(n,t){var r=/^(?:filter|map|reject)|While$/.test(t),e=/^(?:first|last)$/.test(t),u=Nn[e?"take"+("last"==t?"Right":""):t];u&&(Nn.prototype[t]=function(){function t(n){return e&&i?u(n,1)[0]:u.apply(w,Jn([n],o))}var o=e?[1]:arguments,i=this.__chain__,f=this.__wrapped__,a=!!this.__actions__.length,c=f instanceof zn,l=o[0],s=c||Oo(f);return s&&r&&typeof l=="function"&&1!=l.length&&(c=s=false),l={func:ne,args:[t],thisArg:w},a=c&&!a,e&&!i?a?(f=f.clone(),f.__actions__.push(l),n.call(f)):u.call(w,this.value())[0]:!e&&s?(f=a?f:new zn(this), +f=n.apply(f,o),f.__actions__.push(l),new Ln(f,i)):this.thru(t)})}),Pn("join pop push replace shift sort splice split unshift".split(" "),function(n){var t=(/^(?:replace|split)$/.test(n)?He:Je)[n],r=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",e=/^(?:join|pop|replace|shift)$/.test(n);Nn.prototype[n]=function(){var n=arguments;return e&&!this.__chain__?t.apply(this.value(),n):this[r](function(r){return t.apply(r,n)})}}),_t(zn.prototype,function(n,t){var r=Nn[t];if(r){var e=r.name+"";(Wu[e]||(Wu[e]=[])).push({ +name:t,func:r})}}),Wu[sr(w,A).name]=[{name:"wrapper",func:w}],zn.prototype.clone=function(){var n=new zn(this.__wrapped__);return n.__actions__=qn(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=qn(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=qn(this.__views__),n},zn.prototype.reverse=function(){if(this.__filtered__){var n=new zn(this);n.__dir__=-1,n.__filtered__=true}else n=this.clone(),n.__dir__*=-1;return n},zn.prototype.value=function(){ +var n,t=this.__wrapped__.value(),r=this.__dir__,e=Oo(t),u=0>r,o=e?t.length:0;n=o;for(var i=this.__views__,f=0,a=-1,c=i.length;++a"'`]/g,pn=RegExp(ln.source),hn=RegExp(sn.source),_n=/<%-([\s\S]+?)%>/g,vn=/<%([\s\S]+?)%>/g,gn=/<%=([\s\S]+?)%>/g,yn=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\n\\]|\\.)*?\1)\]/,dn=/^\w*$/,mn=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g,wn=/^[:!,]|[\\^$.*+?()[\]{}|\/]|(^[0-9a-fA-Fnrtuvx])|([\n\r\u2028\u2029])/g,bn=RegExp(wn.source),xn=/[\u0300-\u036f\ufe20-\ufe23]/g,An=/\\(\\)?/g,jn=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,kn=/\w*$/,In=/^0[xX]/,Rn=/^\[object .+?Constructor\]$/,On=/^\d+$/,En=/[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g,Cn=/($^)/,Un=/['\n\r\u2028\u2029\\]/g,Wn=RegExp("[A-Z\\xc0-\\xd6\\xd8-\\xde]+(?=[A-Z\\xc0-\\xd6\\xd8-\\xde][a-z\\xdf-\\xf6\\xf8-\\xff]+)|[A-Z\\xc0-\\xd6\\xd8-\\xde]?[a-z\\xdf-\\xf6\\xf8-\\xff]+|[A-Z\\xc0-\\xd6\\xd8-\\xde]+|[0-9]+","g"),$n="Array ArrayBuffer Date Error Float32Array Float64Array Function Int8Array Int16Array Int32Array Math Number Object RegExp Set String _ clearTimeout isFinite parseFloat parseInt setTimeout TypeError Uint8Array Uint8ClampedArray Uint16Array Uint32Array WeakMap".split(" "),Sn={}; +Sn[X]=Sn[H]=Sn[Q]=Sn[nn]=Sn[tn]=Sn[rn]=Sn[en]=Sn[un]=Sn[on]=true,Sn[B]=Sn[D]=Sn[J]=Sn[M]=Sn[q]=Sn[P]=Sn[K]=Sn["[object Map]"]=Sn[V]=Sn[Z]=Sn[Y]=Sn["[object Set]"]=Sn[G]=Sn["[object WeakMap]"]=false;var Fn={};Fn[B]=Fn[D]=Fn[J]=Fn[M]=Fn[q]=Fn[X]=Fn[H]=Fn[Q]=Fn[nn]=Fn[tn]=Fn[V]=Fn[Z]=Fn[Y]=Fn[G]=Fn[rn]=Fn[en]=Fn[un]=Fn[on]=true,Fn[P]=Fn[K]=Fn["[object Map]"]=Fn["[object Set]"]=Fn["[object WeakMap]"]=false;var Nn={"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a", +"\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y", +"\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss"},Tn={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},Ln={"&":"&","<":"<",">":">",""":'"',"'":"'","`":"`"},zn={"function":true,object:true},Bn={0:"x30",1:"x31",2:"x32",3:"x33",4:"x34",5:"x35",6:"x36",7:"x37",8:"x38",9:"x39",A:"x41",B:"x42",C:"x43",D:"x44",E:"x45",F:"x46",a:"x61",b:"x62",c:"x63",d:"x64",e:"x65",f:"x66",n:"x6e",r:"x72",t:"x74",u:"x75",v:"x76",x:"x78"},Dn={"\\":"\\", +"'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},Mn=zn[typeof exports]&&exports&&!exports.nodeType&&exports,qn=zn[typeof module]&&module&&!module.nodeType&&module,Pn=zn[typeof self]&&self&&self.Object&&self,Kn=zn[typeof window]&&window&&window.Object&&window,Vn=qn&&qn.exports===Mn&&Mn,Zn=Mn&&qn&&typeof global=="object"&&global&&global.Object&&global||Kn!==(this&&this.window)&&Kn||Pn||this,Yn=m();typeof define=="function"&&typeof define.amd=="object"&&define.amd?(Zn._=Yn, define(function(){ +return Yn})):Mn&&qn?Vn?(qn.exports=Yn)._=Yn:Mn._=Yn:Zn._=Yn}).call(this); +(function() { + 'use strict'; + + if (self.fetch) { + return + } + + function normalizeName(name) { + if (typeof name !== 'string') { + name = String(name) + } + if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) { + throw new TypeError('Invalid character in header field name') + } + return name.toLowerCase() + } + + function normalizeValue(value) { + if (typeof value !== 'string') { + value = String(value) + } + return value + } + + function Headers(headers) { + this.map = {} + + if (headers instanceof Headers) { + headers.forEach(function(value, name) { + this.append(name, value) + }, this) + + } else if (headers) { + Object.getOwnPropertyNames(headers).forEach(function(name) { + this.append(name, headers[name]) + }, this) + } + } + + Headers.prototype.append = function(name, value) { + name = normalizeName(name) + value = normalizeValue(value) + var list = this.map[name] + if (!list) { + list = [] + this.map[name] = list + } + list.push(value) + } + + Headers.prototype['delete'] = function(name) { + delete this.map[normalizeName(name)] + } + + Headers.prototype.get = function(name) { + var values = this.map[normalizeName(name)] + return values ? values[0] : null + } + + Headers.prototype.getAll = function(name) { + return this.map[normalizeName(name)] || [] + } + + Headers.prototype.has = function(name) { + return this.map.hasOwnProperty(normalizeName(name)) + } + + Headers.prototype.set = function(name, value) { + this.map[normalizeName(name)] = [normalizeValue(value)] + } + + Headers.prototype.forEach = function(callback, thisArg) { + Object.getOwnPropertyNames(this.map).forEach(function(name) { + this.map[name].forEach(function(value) { + callback.call(thisArg, value, name, this) + }, this) + }, this) + } + + function consumed(body) { + if (body.bodyUsed) { + return Promise.reject(new TypeError('Already read')) + } + body.bodyUsed = true + } + + function fileReaderReady(reader) { + return new Promise(function(resolve, reject) { + reader.onload = function() { + resolve(reader.result) + } + reader.onerror = function() { + reject(reader.error) + } + }) + } + + function readBlobAsArrayBuffer(blob) { + var reader = new FileReader() + reader.readAsArrayBuffer(blob) + return fileReaderReady(reader) + } + + function readBlobAsText(blob) { + var reader = new FileReader() + reader.readAsText(blob) + return fileReaderReady(reader) + } + + var support = { + blob: 'FileReader' in self && 'Blob' in self && (function() { + try { + new Blob(); + return true + } catch(e) { + return false + } + })(), + formData: 'FormData' in self + } + + function Body() { + this.bodyUsed = false + + + this._initBody = function(body) { + this._bodyInit = body + if (typeof body === 'string') { + this._bodyText = body + } else if (support.blob && Blob.prototype.isPrototypeOf(body)) { + this._bodyBlob = body + } else if (support.formData && FormData.prototype.isPrototypeOf(body)) { + this._bodyFormData = body + } else if (!body) { + this._bodyText = '' + } else { + throw new Error('unsupported BodyInit type') + } + } + + if (support.blob) { + this.blob = function() { + var rejected = consumed(this) + if (rejected) { + return rejected + } + + if (this._bodyBlob) { + return Promise.resolve(this._bodyBlob) + } else if (this._bodyFormData) { + throw new Error('could not read FormData body as blob') + } else { + return Promise.resolve(new Blob([this._bodyText])) + } + } + + this.arrayBuffer = function() { + return this.blob().then(readBlobAsArrayBuffer) + } + + this.text = function() { + var rejected = consumed(this) + if (rejected) { + return rejected + } + + if (this._bodyBlob) { + return readBlobAsText(this._bodyBlob) + } else if (this._bodyFormData) { + throw new Error('could not read FormData body as text') + } else { + return Promise.resolve(this._bodyText) + } + } + } else { + this.text = function() { + var rejected = consumed(this) + return rejected ? rejected : Promise.resolve(this._bodyText) + } + } + + if (support.formData) { + this.formData = function() { + return this.text().then(decode) + } + } + + this.json = function() { + return this.text().then(JSON.parse) + } + + return this + } + + // HTTP methods whose capitalization should be normalized + var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'] + + function normalizeMethod(method) { + var upcased = method.toUpperCase() + return (methods.indexOf(upcased) > -1) ? upcased : method + } + + function Request(url, options) { + options = options || {} + this.url = url + + this.credentials = options.credentials || 'omit' + this.headers = new Headers(options.headers) + this.method = normalizeMethod(options.method || 'GET') + this.mode = options.mode || null + this.referrer = null + + if ((this.method === 'GET' || this.method === 'HEAD') && options.body) { + throw new TypeError('Body not allowed for GET or HEAD requests') + } + this._initBody(options.body) + } + + function decode(body) { + var form = new FormData() + body.trim().split('&').forEach(function(bytes) { + if (bytes) { + var split = bytes.split('=') + var name = split.shift().replace(/\+/g, ' ') + var value = split.join('=').replace(/\+/g, ' ') + form.append(decodeURIComponent(name), decodeURIComponent(value)) + } + }) + return form + } + + function headers(xhr) { + var head = new Headers() + var pairs = xhr.getAllResponseHeaders().trim().split('\n') + pairs.forEach(function(header) { + var split = header.trim().split(':') + var key = split.shift().trim() + var value = split.join(':').trim() + head.append(key, value) + }) + return head + } + + Body.call(Request.prototype) + + function Response(bodyInit, options) { + if (!options) { + options = {} + } + + this._initBody(bodyInit) + this.type = 'default' + this.url = null + this.status = options.status + this.ok = this.status >= 200 && this.status < 300 + this.statusText = options.statusText + this.headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers) + this.url = options.url || '' + } + + Body.call(Response.prototype) + + self.Headers = Headers; + self.Request = Request; + self.Response = Response; + + self.fetch = function(input, init) { + // TODO: Request constructor should accept input, init + var request + if (Request.prototype.isPrototypeOf(input) && !init) { + request = input + } else { + request = new Request(input, init) + } + + return new Promise(function(resolve, reject) { + var xhr = new XMLHttpRequest() + + function responseURL() { + if ('responseURL' in xhr) { + return xhr.responseURL + } + + // Avoid security warnings on getResponseHeader when not allowed by CORS + if (/^X-Request-URL:/m.test(xhr.getAllResponseHeaders())) { + return xhr.getResponseHeader('X-Request-URL') + } + + return; + } + + xhr.onload = function() { + var status = (xhr.status === 1223) ? 204 : xhr.status + if (status < 100 || status > 599) { + reject(new TypeError('Network request failed')) + return + } + var options = { + status: status, + statusText: xhr.statusText, + headers: headers(xhr), + url: responseURL() + } + var body = 'response' in xhr ? xhr.response : xhr.responseText; + resolve(new Response(body, options)) + } + + xhr.onerror = function() { + reject(new TypeError('Network request failed')) + } + + xhr.open(request.method, request.url, true) + + if (request.credentials === 'include') { + xhr.withCredentials = true + } + + if ('responseType' in xhr && support.blob) { + xhr.responseType = 'blob' + } + + request.headers.forEach(function(value, name) { + xhr.setRequestHeader(name, value) + }) + + xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit) + }) + } + self.fetch.polyfill = true +})(); + + + + + + + + + + + + + + + + + + +function ready(fn) { + if (document.readyState != 'loading'){ + fn(); + } else { + document.addEventListener('DOMContentLoaded', fn); + } +} + +var getValues = function(){ + var name = document.querySelector('input[name=lion-name]').value; + var pride = document.querySelector('input[name=lion-pride]').value; + var age = document.querySelector('input[type=number').value; + var gender = document.querySelector('select'); + gender = gender.options[gender.selectedIndex].value; + + + document.querySelector('input[name=lion-name]').value = ''; + document.querySelector('input[name=lion-pride]').value = ''; + document.querySelector('input[type=number').value = ''; + + + return { + name: name, + pride: pride, + age: age, + gender: gender + }; +}; + + +var lionTemplate = '

<%= name %>'+ + '

<%= pride %>

'+ + 'age: <%= age %> '+ + '<%= gender %>'; + +var lions = []; + +var makeTemplate = function(data) { + var li = document.createElement('li'); + var lionList = document.querySelector('.lion-list'); + var compiled = _.template(lionTemplate); + var lionHtml = compiled(data); + li.innerHTML = lionHtml; + lionList.insertBefore(li, lionList.firstChild); +} + +var updateLionList = function(){ + var lionData = lions[lions.length-1]; + makeTemplate(lionData); +} + +var makeLionList = function() { + lions.forEach(function(lion) { + makeTemplate(lion); + }); +}; + +var getAllLions = function() { + fetch('/lions') + .then(function(resp) { + console.log(resp); + return resp.json(); + }) + .then(function(data) { + lions = lions.concat(data); + makeLionList(); + }); +} + +ready(function() { + getAllLions(); + var form = document.querySelector('form'); + + form.addEventListener('submit', function(e) { + e.preventDefault(); + + var values = getValues(); + console.log(values); + fetch('/lions', { + method: 'post', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + + body: JSON.stringify(values) + }) + .then(function(resp) { + return resp.json(); + }) + .then(function(createdLion){ + lions.push(createdLion); + updateLionList(); + }) + return false; + }) +}); diff --git a/client/index.html b/client/index.html new file mode 100644 index 0000000..e9987a7 --- /dev/null +++ b/client/index.html @@ -0,0 +1,48 @@ + + + + Lions + + + + +
+

Lions

+ +
+
+ + + + +
+ +
+ + + + +
+ + + + + +
+ +
+
    +
    +
    + + + diff --git a/client/style.css b/client/style.css new file mode 100644 index 0000000..08c888e --- /dev/null +++ b/client/style.css @@ -0,0 +1,542 @@ +/*! 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"], /* 1 */ +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; +} + + + +/**************************************************************/ +body, html { + height: 100%; +} + +main { + width: 80vw; + margin: 0 auto; +} +.textbox { + max-width: 200px; + margin-bottom: 40px; + position: relative; + width: 100%; +} +.textbox input { + font-size: 18px; + padding: 10px 10px 10px 5px; + display: block; + width: 100%; + background: transparent; + border: none; + border-bottom: 1px solid #bf0000; +} +.textbox input:focus { + outline: none; +} +.textbox input:focus ~ .highlight { + animation: inputHighlight 0.3s ease; +} +.textbox input:focus ~ .bar:before, +.textbox input:focus ~ .bar:after { + width: 50%; +} +.textbox input:focus ~ label, +.textbox input:valid ~ label { + top: -20px; + font-size: 14px; + color: #ff1a1a; +} +.textbox label { + color: #4d0000; + font-size: 18px; + font-weight: normal; + position: absolute; + pointer-events: none; + left: 5px; + top: 10px; + transition: all 0.2s ease; +} +.textbox .bar { + position: relative; + display: block; +} +.textbox .bar:before, +.textbox .bar:after { + content: ''; + height: 2px; + width: 0; + bottom: 1px; + position: absolute; + background: #f00; + transition: ease all 0.2s; +} +.textbox .bar:before { + left: 50%; +} +.textbox .bar:after { + right: 50%; +} +.textbox .highlight { + position: absolute; + height: 60%; + width: 100px; + top: 25%; + left: 0; + pointer-events: none; + opacity: 0.5; +} +@-moz-keyframes inputHighlight { + from { + background: #f00; + } + to { + background: transparent; + width: 0; + } +} +@-webkit-keyframes inputHighlight { + from { + background: #f00; + } + to { + background: transparent; + width: 0; + } +} +@-o-keyframes inputHighlight { + from { + background: #f00; + } + to { + background: transparent; + width: 0; + } +} +@keyframes inputHighlight { + from { + background: #f00; + } + to { + background: transparent; + width: 0; + } +} diff --git a/index.html b/index.html deleted file mode 100644 index 1667638..0000000 --- a/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - hello - - -

    hey there

    - - diff --git a/server.js b/server.js deleted file mode 100644 index 65828b1..0000000 --- a/server.js +++ /dev/null @@ -1,24 +0,0 @@ -var express = require('express'); -var app = express(); - -var jsonData = {count: 12, message: 'hey'}; - -app.get('/', function(req, res){ - // res.sendFile takes an absolute path to a file and - // sets the mime type based n the file extname - res.sendFile(__dirname + '/index.html', function(err) { - if (err) { - res.status(500).send(err); - } - }) -}); - -app.get('/data', function(req, res) { - res.json(jsonData); -}); - - -var port = 3000; -app.listen(port, function(){ - console.log('listening on http://localhost:', port); -}); diff --git a/server/server.js b/server/server.js new file mode 100644 index 0000000..1f15e38 --- /dev/null +++ b/server/server.js @@ -0,0 +1,49 @@ +var express = require('express'); +var bodyParser = require('body-parser'); +var app = express(); +var _ = require('lodash'); + +app.use(express.static('client')); +app.use(bodyParser.urlencoded({extended: true})); +app.use(bodyParser.json()); + +var lions = []; +var id = 0; + +app.get('/lions', function(req, res){ + res.json(lions); +}); + +app.get('/lions/:id', function(req, res){ + var lion = _.find(lions, {id: req.params.id}); + res.json(lion || {}); +}); + +app.post('/lions', function(req, res) { + var lion = req.body; + id++; + lion.id = id + ''; + + lions.push(lion); + + res.json(lion); +}); + + +app.put('/lions/:id', function(req, res) { + var update = req.body; + if (update.id) { + delete update.id + } + + var lion = _.findIndex(lions, {id: req.params.id}); + if (!lions[lion]) { + res.send(); + } else { + var updatedLion = _.assign(lions[lion], update); + res.json(updatedLion); + } +}); + +app.listen(3000); +console.log('on port 3000'); From 28698e2519d63855c4c6108cd4ede9396c5dbd6e Mon Sep 17 00:00:00 2001 From: Hendrixer Date: Wed, 22 Jul 2015 04:52:00 -0500 Subject: [PATCH 04/22] chore --- server/server.js | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/server/server.js b/server/server.js index 1f15e38..9a17611 100644 --- a/server/server.js +++ b/server/server.js @@ -2,27 +2,52 @@ var express = require('express'); var bodyParser = require('body-parser'); var app = express(); var _ = require('lodash'); +var morgan = require('morgan'); +var lions = []; +var id = 0; + +var updateId = function(req, res, next) { + if (!req.body.id) { + id++; + req.body.id = id + ''; + } + next(); +}; + +app.use(morgan('dev')) app.use(express.static('client')); app.use(bodyParser.urlencoded({extended: true})); app.use(bodyParser.json()); -var lions = []; -var id = 0; +app.use(function(err, req, res, next) { + if (err) { + res.status(500).send(error); + } +}); + +app.param('id', function(req, res, next, id) { + var todo = _.find(todos, {id: id}); + + if (todo) { + req.todo = todo; + next(); + } else { + res.send(); + } +}); app.get('/lions', function(req, res){ res.json(lions); }); app.get('/lions/:id', function(req, res){ - var lion = _.find(lions, {id: req.params.id}); + var lion = req.todo; res.json(lion || {}); }); -app.post('/lions', function(req, res) { +app.post('/lions', updateId, function(req, res) { var lion = req.body; - id++; - lion.id = id + ''; lions.push(lion); From fb9a2a4ff84fededf661d5c82eb99339bd171d46 Mon Sep 17 00:00:00 2001 From: Hendrixer Date: Wed, 22 Jul 2015 05:09:32 -0500 Subject: [PATCH 05/22] chore --- server/server.js | 58 +++++------------------------------------------- 1 file changed, 6 insertions(+), 52 deletions(-) diff --git a/server/server.js b/server/server.js index 9a17611..82316f8 100644 --- a/server/server.js +++ b/server/server.js @@ -4,21 +4,17 @@ var app = express(); var _ = require('lodash'); var morgan = require('morgan'); -var lions = []; -var id = 0; - -var updateId = function(req, res, next) { - if (!req.body.id) { - id++; - req.body.id = id + ''; - } - next(); -}; +var lionRouter = require('./lions'); +var tigerRouter = require('./tigers'); app.use(morgan('dev')) app.use(express.static('client')); app.use(bodyParser.urlencoded({extended: true})); app.use(bodyParser.json()); +// this is called mounting. when ever a req comes in for +// '/lion' we want to use this router +app.use('/lions', lionRouter); +app.use('/tigers', tigerRouter); app.use(function(err, req, res, next) { if (err) { @@ -26,49 +22,7 @@ app.use(function(err, req, res, next) { } }); -app.param('id', function(req, res, next, id) { - var todo = _.find(todos, {id: id}); - - if (todo) { - req.todo = todo; - next(); - } else { - res.send(); - } -}); - -app.get('/lions', function(req, res){ - res.json(lions); -}); - -app.get('/lions/:id', function(req, res){ - var lion = req.todo; - res.json(lion || {}); -}); - -app.post('/lions', updateId, function(req, res) { - var lion = req.body; - - lions.push(lion); - - res.json(lion); -}); - -app.put('/lions/:id', function(req, res) { - var update = req.body; - if (update.id) { - delete update.id - } - - var lion = _.findIndex(lions, {id: req.params.id}); - if (!lions[lion]) { - res.send(); - } else { - var updatedLion = _.assign(lions[lion], update); - res.json(updatedLion); - } -}); app.listen(3000); console.log('on port 3000'); From f482a9319e5b8387d2c588cdbdd9fdb70a824182 Mon Sep 17 00:00:00 2001 From: Hendrixer Date: Wed, 22 Jul 2015 05:09:42 -0500 Subject: [PATCH 06/22] chore --- server/lions.js | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ server/tigers.js | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 server/lions.js create mode 100644 server/tigers.js diff --git a/server/lions.js b/server/lions.js new file mode 100644 index 0000000..1b85c09 --- /dev/null +++ b/server/lions.js @@ -0,0 +1,58 @@ +var lionRouter = require('express').Router(); + +var lions = []; +var id = 0; + +var updateId = function(req, res, next) { + if (!req.body.id) { + id++; + req.body.id = id + ''; + } + next(); +}; + +lionRouter.param('id', function(req, res, next, id) { + var todo = _.find(todos, {id: id}); + + if (todo) { + req.todo = todo; + next(); + } else { + res.send(); + } +}); + +lionRouter.get('/', function(req, res){ + res.json(lions); +}); + +lionRouter.get('/:id', function(req, res){ + var lion = req.todo; + res.json(lion || {}); +}); + +lionRouter.post('/', updateId, function(req, res) { + var lion = req.body; + + lions.push(lion); + + res.json(lion); +}); + + +lionRouter.put('/:id', function(req, res) { + var update = req.body; + if (update.id) { + delete update.id + } + + var lion = _.findIndex(lions, {id: req.params.id}); + if (!lions[lion]) { + res.send(); + } else { + var updatedLion = _.assign(lions[lion], update); + res.json(updatedLion); + } +}); + +module.exports = lionRouter; diff --git a/server/tigers.js b/server/tigers.js new file mode 100644 index 0000000..a0e4578 --- /dev/null +++ b/server/tigers.js @@ -0,0 +1,58 @@ +var tigerRouter = require('express').Router(); + +var tigers = []; +var id = 0; + +var updateId = function(req, res, next) { + if (!req.body.id) { + id++; + req.body.id = id + ''; + } + next(); +}; + +tigerRouter.param('id', function(req, res, next, id) { + var todo = _.find(todos, {id: id}); + + if (todo) { + req.todo = todo; + next(); + } else { + res.send(); + } +}); + +tigerRouter.get('/', function(req, res){ + res.json(tigers); +}); + +tigerRouter.get('/:id', function(req, res){ + var tiger = req.todo; + res.json(tiger || {}); +}); + +tigerRouter.post('/', updateId, function(req, res) { + var tiger = req.body; + + tigers.push(tiger); + + res.json(tiger); +}); + + +tigerRouter.put('/:id', function(req, res) { + var update = req.body; + if (update.id) { + delete update.id + } + + var tiger = _.findIndex(tigers, {id: req.params.id}); + if (!tigers[tiger]) { + res.send(); + } else { + var updatedtiger = _.assign(tigers[tiger], update); + res.json(updatedtiger); + } +}); + +module.exports = tigerRouter; From 5850443cebd35eb5513f6a87f26c9605d68d8524 Mon Sep 17 00:00:00 2001 From: Hendrixer Date: Wed, 22 Jul 2015 05:43:08 -0500 Subject: [PATCH 07/22] chore --- index.js | 4 ++++ package.json | 4 ++++ server/lions.js | 15 ++++++++---- server/server.js | 5 ++-- server/spec.js | 59 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 index.js create mode 100644 server/spec.js diff --git a/index.js b/index.js new file mode 100644 index 0000000..68890cc --- /dev/null +++ b/index.js @@ -0,0 +1,4 @@ +var app = require('./server/server'); + +app.listen(3000); +console.log('on port 3000'); diff --git a/package.json b/package.json index ea99b7f..26c6562 100644 --- a/package.json +++ b/package.json @@ -13,5 +13,9 @@ "express": "^4.13.1", "lodash": "^3.10.0", "morgan": "^1.6.1" + }, + "devDependencies": { + "chai": "^3.2.0", + "supertest": "^1.0.1" } } diff --git a/server/lions.js b/server/lions.js index 1b85c09..15c4785 100644 --- a/server/lions.js +++ b/server/lions.js @@ -1,3 +1,4 @@ +var _ = require('lodash'); var lionRouter = require('express').Router(); var lions = []; @@ -12,10 +13,10 @@ var updateId = function(req, res, next) { }; lionRouter.param('id', function(req, res, next, id) { - var todo = _.find(todos, {id: id}); + var lion = _.find(lions, {id: id}) - if (todo) { - req.todo = todo; + if (lion) { + req.lion = lion; next(); } else { res.send(); @@ -27,7 +28,7 @@ lionRouter.get('/', function(req, res){ }); lionRouter.get('/:id', function(req, res){ - var lion = req.todo; + var lion = req.lion; res.json(lion || {}); }); @@ -39,6 +40,12 @@ lionRouter.post('/', updateId, function(req, res) { res.json(lion); }); +lionRouter.delete('/:id', function(req, res) { + var lion = _.findIndex(lions, {id: req.params.id}); + lions.splice(lion, 1); + + res.json(req.lion); +}); lionRouter.put('/:id', function(req, res) { var update = req.body; diff --git a/server/server.js b/server/server.js index 82316f8..fb1bfcb 100644 --- a/server/server.js +++ b/server/server.js @@ -18,11 +18,10 @@ app.use('/tigers', tigerRouter); app.use(function(err, req, res, next) { if (err) { - res.status(500).send(error); + res.status(500).send(err); } }); -app.listen(3000); -console.log('on port 3000'); +module.exports = app; diff --git a/server/spec.js b/server/spec.js new file mode 100644 index 0000000..762b9a7 --- /dev/null +++ b/server/spec.js @@ -0,0 +1,59 @@ +var app = require('./server'); +var request = require('supertest'); +var expect = require('chai').expect; + +describe('lions', function(){ + + it('should get all lions', function(done) { + request(app) + .get('/lions') + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(200) + .end(function(err, resp) { + expect(resp.body).to.be.an('array'); + done(); + }) + }); + + it('should create a lion', function(done) { + request(app) + .post('/lions') + .send({ + name: 'Mufasa', + age: 100, + pride: 'Evil lions', + gender:'male' + }) + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(201) + .end(function(err, resp) { + expect(resp.body).to.be.an('object'); + done(); + }) + }); + + it('should delete a lion', function(done) { + request(app) + .post('/lions') + .send({ + name: 'test lion', + age: 100, + pride: 'test lion', + gender:'female' + }) + .set('Accept', 'application/json') + .end(function(err, resp) { + var lion = resp.body; + request(app) + .delete('/lions/' + lion.id) + .end(function(err, resp) { + expect(resp.body).to.eql(lion); + done(); + }); + }) + }); +}); + + From b593bfc828eb82a0c4e6c016619352622b965d80 Mon Sep 17 00:00:00 2001 From: Hendrixer Date: Wed, 22 Jul 2015 05:47:05 -0500 Subject: [PATCH 08/22] chore --- server/spec.js | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/server/spec.js b/server/spec.js index 762b9a7..7a066e9 100644 --- a/server/spec.js +++ b/server/spec.js @@ -2,7 +2,7 @@ var app = require('./server'); var request = require('supertest'); var expect = require('chai').expect; -describe('lions', function(){ +describe('[LIONS]', function(){ it('should get all lions', function(done) { request(app) @@ -54,6 +54,30 @@ describe('lions', function(){ }); }) }); + + it('should update a lion', function(done) { + request(app) + .post('/lions') + .send({ + name: 'test lion', + age: 100, + pride: 'test lion', + gender:'female' + }) + .set('Accept', 'application/json') + .end(function(err, resp) { + var lion = resp.body; + request(app) + .put('/lions/' + lion.id) + .send({ + name: 'new name' + }) + .end(function(err, resp) { + expect(resp.body.name).to.equal('new name'); + done(); + }); + }) + }); }); From 15a975e72d193cf438b7cf1df9d079abcd911f6f Mon Sep 17 00:00:00 2001 From: Hendrixer Date: Wed, 22 Jul 2015 05:51:23 -0500 Subject: [PATCH 09/22] chore --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8bdf250..bf5d246 100644 --- a/README.md +++ b/README.md @@ -1 +1,5 @@ -##Solution to step-1 +##Testing our app + +We're going to use mocha and chai along with supertest to runt inegration test against our api. **Be sure to gloably install mocha**. `npm i -g mocha`. + +To run the test, run `mocha server/spec.js` or `npm test`; From 0a70576c22b16847a39bbedeb0801fcff3a652b3 Mon Sep 17 00:00:00 2001 From: Hendrixer Date: Wed, 22 Jul 2015 19:05:22 -0500 Subject: [PATCH 10/22] chore --- server/tigers.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/tigers.js b/server/tigers.js index a0e4578..08829b3 100644 --- a/server/tigers.js +++ b/server/tigers.js @@ -12,10 +12,10 @@ var updateId = function(req, res, next) { }; tigerRouter.param('id', function(req, res, next, id) { - var todo = _.find(todos, {id: id}); + var tiger = _.find(tigers, {id: id}); - if (todo) { - req.todo = todo; + if (tiger) { + req.tiger = tiger; next(); } else { res.send(); @@ -27,7 +27,7 @@ tigerRouter.get('/', function(req, res){ }); tigerRouter.get('/:id', function(req, res){ - var tiger = req.todo; + var tiger = req.tiger; res.json(tiger || {}); }); From c8976af4040c99d1337b9d4d095c0f5abdd6543a Mon Sep 17 00:00:00 2001 From: Hendrixer Date: Wed, 22 Jul 2015 20:37:12 -0500 Subject: [PATCH 11/22] chore --- README.md | 5 - client/app.js | 543 -------------------------- client/index.html | 48 --- client/style.css | 542 ------------------------- index.js | 15 +- package.json | 4 +- server/api/api.js | 9 + server/api/category/categoryRoutes.js | 12 + server/api/post/postRoutes.js | 12 + server/api/user/userRoutes.js | 12 + server/config/config.js | 29 ++ server/config/development.js | 4 + server/config/production.js | 4 + server/config/testing.js | 4 + server/lions.js | 65 --- server/middleware/appMiddlware.js | 9 + server/server.js | 28 +- server/spec.js | 83 ---- server/tigers.js | 58 --- server/util/logger.js | 40 ++ 20 files changed, 158 insertions(+), 1368 deletions(-) delete mode 100644 client/app.js delete mode 100644 client/index.html delete mode 100644 client/style.css create mode 100644 server/api/api.js create mode 100644 server/api/category/categoryRoutes.js create mode 100644 server/api/post/postRoutes.js create mode 100644 server/api/user/userRoutes.js create mode 100644 server/config/config.js create mode 100644 server/config/development.js create mode 100644 server/config/production.js create mode 100644 server/config/testing.js delete mode 100644 server/lions.js create mode 100644 server/middleware/appMiddlware.js delete mode 100644 server/spec.js delete mode 100644 server/tigers.js create mode 100644 server/util/logger.js diff --git a/README.md b/README.md index bf5d246..e69de29 100644 --- a/README.md +++ b/README.md @@ -1,5 +0,0 @@ -##Testing our app - -We're going to use mocha and chai along with supertest to runt inegration test against our api. **Be sure to gloably install mocha**. `npm i -g mocha`. - -To run the test, run `mocha server/spec.js` or `npm test`; diff --git a/client/app.js b/client/app.js deleted file mode 100644 index 1351400..0000000 --- a/client/app.js +++ /dev/null @@ -1,543 +0,0 @@ -/** - * @license - * lodash 3.10.1 (Custom Build) lodash.com/license | Underscore.js 1.8.3 underscorejs.org/LICENSE - * Build: `lodash modern -o ./lodash.js` - */ -;(function(){function n(n,t){if(n!==t){var r=null===n,e=n===w,u=n===n,o=null===t,i=t===w,f=t===t;if(n>t&&!o||!u||r&&!i&&f||e&&f)return 1;if(n=n&&9<=n&&13>=n||32==n||160==n||5760==n||6158==n||8192<=n&&(8202>=n||8232==n||8233==n||8239==n||8287==n||12288==n||65279==n); -}function v(n,t){for(var r=-1,e=n.length,u=-1,o=[];++r=F&&gu&&lu?new Dn(t):null,c=t.length;a&&(i=Mn,f=false,t=a);n:for(;++oi(t,a,0)&&u.push(a);return u}function at(n,t){var r=true;return Su(n,function(n,e,u){return r=!!t(n,e,u)}),r}function ct(n,t,r,e){var u=e,o=u;return Su(n,function(n,i,f){i=+t(n,i,f),(r(i,u)||i===e&&i===o)&&(u=i, -o=n)}),o}function lt(n,t){var r=[];return Su(n,function(n,e,u){t(n,e,u)&&r.push(n)}),r}function st(n,t,r,e){var u;return r(n,function(n,r,o){return t(n,r,o)?(u=e?r:n,false):void 0}),u}function pt(n,t,r,e){e||(e=[]);for(var u=-1,o=n.length;++ut&&(t=-t>u?0:u+t),r=r===w||r>u?u:+r||0,0>r&&(r+=u),u=t>r?0:r-t>>>0,t>>>=0,r=Be(u);++e=c)break n;o=e[o],u*="asc"===o||true===o?1:-1;break n}u=t.b-r.b}return u})}function $t(n,t){ -var r=0;return Su(n,function(n,e,u){r+=+t(n,e,u)||0}),r}function St(n,t){var e=-1,u=xr(),o=n.length,i=u===r,f=i&&o>=F,a=f&&gu&&lu?new Dn(void 0):null,c=[];a?(u=Mn,i=false):(f=false,a=t?[]:c);n:for(;++eu(a,s,0)&&((t||f)&&a.push(s),c.push(l))}return c}function Ft(n,t){for(var r=-1,e=t.length,u=Be(e);++r>>1,i=n[o];(r?i<=t:iu?w:o,u=1);++e=F)return t.plant(e).value();for(var u=0,n=r?o[u].apply(this,n):e;++uarguments.length;return typeof e=="function"&&o===w&&Oo(r)?n(r,e,u,i):Ot(r,wr(e,o,4),u,i,t)}}function sr(n,t,r,e,u,o,i,f,a,c){function l(){for(var m=arguments.length,b=m,j=Be(m);b--;)j[b]=arguments[b];if(e&&(j=Mt(j,e,u)),o&&(j=qt(j,o,i)),_||y){var b=l.placeholder,k=v(j,b),m=m-k.length;if(mt?0:t)):[]}function Pr(n,t,r){var e=n?n.length:0;return e?((r?Ur(n,t,r):null==t)&&(t=1),t=e-(+t||0),Et(n,0,0>t?0:t)):[]}function Kr(n){return n?n[0]:w}function Vr(n,t,e){var u=n?n.length:0;if(!u)return-1;if(typeof e=="number")e=0>e?bu(u+e,0):e;else if(e)return e=Lt(n,t), -er?bu(u+r,0):r||0,typeof n=="string"||!Oo(n)&&be(n)?r<=u&&-1t?0:+t||0,e);++r=n&&(t=w),r}}function ae(n,t,r){function e(t,r){r&&iu(r),a=p=h=w,t&&(_=ho(),c=n.apply(s,f),p||a||(f=s=w))}function u(){var n=t-(ho()-l);0>=n||n>t?e(h,a):p=su(u,n)}function o(){e(g,p); -}function i(){if(f=arguments,l=ho(),s=this,h=g&&(p||!y),false===v)var r=y&&!p;else{a||y||(_=l);var e=v-(l-_),i=0>=e||e>v;i?(a&&(a=iu(a)),_=l,c=n.apply(s,f)):a||(a=su(o,e))}return i&&p?p=iu(p):p||t===v||(p=su(u,t)),r&&(i=true,c=n.apply(s,f)),!i||p||a||(f=s=w),c}var f,a,c,l,s,p,h,_=0,v=false,g=true;if(typeof n!="function")throw new Ge(L);if(t=0>t?0:+t||0,true===r)var y=true,g=false;else ge(r)&&(y=!!r.leading,v="maxWait"in r&&bu(+r.maxWait||0,t),g="trailing"in r?!!r.trailing:g);return i.cancel=function(){p&&iu(p),a&&iu(a), -_=0,a=p=h=w},i}function ce(n,t){function r(){var e=arguments,u=t?t.apply(this,e):e[0],o=r.cache;return o.has(u)?o.get(u):(e=n.apply(this,e),r.cache=o.set(u,e),e)}if(typeof n!="function"||t&&typeof t!="function")throw new Ge(L);return r.cache=new ce.Cache,r}function le(n,t){if(typeof n!="function")throw new Ge(L);return t=bu(t===w?n.length-1:+t||0,0),function(){for(var r=arguments,e=-1,u=bu(r.length-t,0),o=Be(u);++et}function pe(n){return h(n)&&Er(n)&&nu.call(n,"callee")&&!cu.call(n,"callee")}function he(n,t,r,e){return e=(r=typeof r=="function"?Bt(r,e,3):w)?r(n,t):w,e===w?dt(n,t,r):!!e}function _e(n){return h(n)&&typeof n.message=="string"&&ru.call(n)==P}function ve(n){return ge(n)&&ru.call(n)==K}function ge(n){var t=typeof n;return!!n&&("object"==t||"function"==t)}function ye(n){ -return null==n?false:ve(n)?uu.test(Qe.call(n)):h(n)&&Rn.test(n)}function de(n){return typeof n=="number"||h(n)&&ru.call(n)==V}function me(n){var t;if(!h(n)||ru.call(n)!=Z||pe(n)||!(nu.call(n,"constructor")||(t=n.constructor,typeof t!="function"||t instanceof t)))return false;var r;return ht(n,function(n,t){r=t}),r===w||nu.call(n,r)}function we(n){return ge(n)&&ru.call(n)==Y}function be(n){return typeof n=="string"||h(n)&&ru.call(n)==G}function xe(n){return h(n)&&Sr(n.length)&&!!Sn[ru.call(n)]}function Ae(n,t){ -return nt||!n||!mu(t))return r;do t%2&&(r+=n),t=yu(t/2),n+=n;while(t);return r}function We(n,t,r){var e=n;return(n=u(n))?(r?Ur(e,t,r):null==t)?n.slice(g(n),y(n)+1):(t+="",n.slice(o(n,t),i(n,t)+1)):n}function $e(n,t,r){return r&&Ur(n,t,r)&&(t=w),n=u(n),n.match(t||Wn)||[]}function Se(n,t,r){return r&&Ur(n,t,r)&&(t=w),h(n)?Ne(n):ut(n,t)}function Fe(n){ -return n}function Ne(n){return bt(ot(n,true))}function Te(n,t,r){if(null==r){var e=ge(t),u=e?zo(t):w;((u=u&&u.length?gt(t,u):w)?u.length:e)||(u=false,r=t,t=n,n=this)}u||(u=gt(t,zo(t)));var o=true,e=-1,i=ve(n),f=u.length;false===r?o=false:ge(r)&&"chain"in r&&(o=r.chain);for(;++e=$)return r}else n=0;return Lu(r,e)}}(),Mu=le(function(n,t){ -return h(n)&&Er(n)?ft(n,pt(t,false,true)):[]}),qu=tr(),Pu=tr(true),Ku=le(function(n){for(var t=n.length,e=t,u=Be(l),o=xr(),i=o===r,f=[];e--;){var a=n[e]=Er(a=n[e])?a:[];u[e]=i&&120<=a.length&&gu&&lu?new Dn(e&&a):null}var i=n[0],c=-1,l=i?i.length:0,s=u[0];n:for(;++c(s?Mn(s,a):o(f,a,0))){for(e=t;--e;){var p=u[e];if(0>(p?Mn(p,a):o(n[e],a,0)))continue n}s&&s.push(a),f.push(a)}return f}),Vu=le(function(t,r){r=pt(r);var e=rt(t,r);return It(t,r.sort(n)),e}),Zu=vr(),Yu=vr(true),Gu=le(function(n){return St(pt(n,false,true)); -}),Ju=le(function(n,t){return Er(n)?ft(n,t):[]}),Xu=le(Jr),Hu=le(function(n){var t=n.length,r=2--n?t.apply(this,arguments):void 0}},Nn.ary=function(n,t,r){return r&&Ur(n,t,r)&&(t=w),t=n&&null==t?n.length:bu(+t||0,0),gr(n,E,w,w,w,w,t)},Nn.assign=Co,Nn.at=no,Nn.before=fe,Nn.bind=_o,Nn.bindAll=vo,Nn.bindKey=go,Nn.callback=Se,Nn.chain=Qr,Nn.chunk=function(n,t,r){t=(r?Ur(n,t,r):null==t)?1:bu(yu(t)||1,1),r=0;for(var e=n?n.length:0,u=-1,o=Be(vu(e/t));rr&&(r=-r>u?0:u+r),e=e===w||e>u?u:+e||0,0>e&&(e+=u),u=r>e?0:e>>>0,r>>>=0;rt?0:t)):[]},Nn.takeRight=function(n,t,r){var e=n?n.length:0;return e?((r?Ur(n,t,r):null==t)&&(t=1),t=e-(+t||0),Et(n,0>t?0:t)):[]},Nn.takeRightWhile=function(n,t,r){ -return n&&n.length?Nt(n,wr(t,r,3),false,true):[]},Nn.takeWhile=function(n,t,r){return n&&n.length?Nt(n,wr(t,r,3)):[]},Nn.tap=function(n,t,r){return t.call(r,n),n},Nn.throttle=function(n,t,r){var e=true,u=true;if(typeof n!="function")throw new Ge(L);return false===r?e=false:ge(r)&&(e="leading"in r?!!r.leading:e,u="trailing"in r?!!r.trailing:u),ae(n,t,{leading:e,maxWait:+t,trailing:u})},Nn.thru=ne,Nn.times=function(n,t,r){if(n=yu(n),1>n||!mu(n))return[];var e=-1,u=Be(xu(n,4294967295));for(t=Bt(t,r,1);++ee?u[e]=t(e):t(e); -return u},Nn.toArray=je,Nn.toPlainObject=ke,Nn.transform=function(n,t,r,e){var u=Oo(n)||xe(n);return t=wr(t,e,4),null==r&&(u||ge(n)?(e=n.constructor,r=u?Oo(n)?new e:[]:$u(ve(e)?e.prototype:w)):r={}),(u?Pn:_t)(n,function(n,e,u){return t(r,n,e,u)}),r},Nn.union=Gu,Nn.uniq=Gr,Nn.unzip=Jr,Nn.unzipWith=Xr,Nn.values=Ee,Nn.valuesIn=function(n){return Ft(n,Re(n))},Nn.where=function(n,t){return re(n,bt(t))},Nn.without=Ju,Nn.wrap=function(n,t){return t=null==t?Fe:t,gr(t,R,w,[n],[])},Nn.xor=function(){for(var n=-1,t=arguments.length;++nr?0:+r||0,e),r-=t.length,0<=r&&n.indexOf(t,r)==r},Nn.escape=function(n){return(n=u(n))&&hn.test(n)?n.replace(sn,c):n},Nn.escapeRegExp=function(n){return(n=u(n))&&bn.test(n)?n.replace(wn,l):n||"(?:)"},Nn.every=te,Nn.find=ro,Nn.findIndex=qu,Nn.findKey=$o,Nn.findLast=eo, -Nn.findLastIndex=Pu,Nn.findLastKey=So,Nn.findWhere=function(n,t){return ro(n,bt(t))},Nn.first=Kr,Nn.floor=ni,Nn.get=function(n,t,r){return n=null==n?w:yt(n,Dr(t),t+""),n===w?r:n},Nn.gt=se,Nn.gte=function(n,t){return n>=t},Nn.has=function(n,t){if(null==n)return false;var r=nu.call(n,t);if(!r&&!Wr(t)){if(t=Dr(t),n=1==t.length?n:yt(n,Et(t,0,-1)),null==n)return false;t=Zr(t),r=nu.call(n,t)}return r||Sr(n.length)&&Cr(t,n.length)&&(Oo(n)||pe(n))},Nn.identity=Fe,Nn.includes=ee,Nn.indexOf=Vr,Nn.inRange=function(n,t,r){ -return t=+t||0,r===w?(r=t,t=0):r=+r||0,n>=xu(t,r)&&nr?bu(e+r,0):xu(r||0,e-1))+1;else if(r)return u=Lt(n,t,true)-1,n=n[u],(t===t?t===n:n!==n)?u:-1; -if(t!==t)return p(n,u,true);for(;u--;)if(n[u]===t)return u;return-1},Nn.lt=Ae,Nn.lte=function(n,t){return n<=t},Nn.max=ti,Nn.min=ri,Nn.noConflict=function(){return Zn._=eu,this},Nn.noop=Le,Nn.now=ho,Nn.pad=function(n,t,r){n=u(n),t=+t;var e=n.length;return er?0:+r||0,n.length),n.lastIndexOf(t,r)==r},Nn.sum=function(n,t,r){if(r&&Ur(n,t,r)&&(t=w),t=wr(t,r,3),1==t.length){n=Oo(n)?n:zr(n),r=n.length;for(var e=0;r--;)e+=+t(n[r])||0;n=e}else n=$t(n,t);return n},Nn.template=function(n,t,r){var e=Nn.templateSettings;r&&Ur(n,t,r)&&(t=r=w),n=u(n),t=nt(tt({},r||t),e,Qn),r=nt(tt({},t.imports),e.imports,Qn); -var o,i,f=zo(r),a=Ft(r,f),c=0;r=t.interpolate||Cn;var l="__p+='";r=Ze((t.escape||Cn).source+"|"+r.source+"|"+(r===gn?jn:Cn).source+"|"+(t.evaluate||Cn).source+"|$","g");var p="sourceURL"in t?"//# sourceURL="+t.sourceURL+"\n":"";if(n.replace(r,function(t,r,e,u,f,a){return e||(e=u),l+=n.slice(c,a).replace(Un,s),r&&(o=true,l+="'+__e("+r+")+'"),f&&(i=true,l+="';"+f+";\n__p+='"),e&&(l+="'+((__t=("+e+"))==null?'':__t)+'"),c=a+t.length,t}),l+="';",(t=t.variable)||(l="with(obj){"+l+"}"),l=(i?l.replace(fn,""):l).replace(an,"$1").replace(cn,"$1;"), -l="function("+(t||"obj")+"){"+(t?"":"obj||(obj={});")+"var __t,__p=''"+(o?",__e=_.escape":"")+(i?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+l+"return __p}",t=Jo(function(){return qe(f,p+"return "+l).apply(w,a)}),t.source=l,_e(t))throw t;return t},Nn.trim=We,Nn.trimLeft=function(n,t,r){var e=n;return(n=u(n))?n.slice((r?Ur(e,t,r):null==t)?g(n):o(n,t+"")):n},Nn.trimRight=function(n,t,r){var e=n;return(n=u(n))?(r?Ur(e,t,r):null==t)?n.slice(0,y(n)+1):n.slice(0,i(n,t+"")+1):n; -},Nn.trunc=function(n,t,r){r&&Ur(n,t,r)&&(t=w);var e=U;if(r=W,null!=t)if(ge(t)){var o="separator"in t?t.separator:o,e="length"in t?+t.length||0:e;r="omission"in t?u(t.omission):r}else e=+t||0;if(n=u(n),e>=n.length)return n;if(e-=r.length,1>e)return r;if(t=n.slice(0,e),null==o)return t+r;if(we(o)){if(n.slice(e).search(o)){var i,f=n.slice(0,e);for(o.global||(o=Ze(o.source,(kn.exec(o)||"")+"g")),o.lastIndex=0;n=o.exec(f);)i=n.index;t=t.slice(0,null==i?e:i)}}else n.indexOf(o,e)!=e&&(o=t.lastIndexOf(o), --1u.__dir__?"Right":"")}),u},zn.prototype[n+"Right"]=function(t){return this.reverse()[n](t).reverse()}}),Pn(["filter","map","takeWhile"],function(n,t){ -var r=t+1,e=r!=T;zn.prototype[n]=function(n,t){var u=this.clone();return u.__iteratees__.push({iteratee:wr(n,t,1),type:r}),u.__filtered__=u.__filtered__||e,u}}),Pn(["first","last"],function(n,t){var r="take"+(t?"Right":"");zn.prototype[n]=function(){return this[r](1).value()[0]}}),Pn(["initial","rest"],function(n,t){var r="drop"+(t?"":"Right");zn.prototype[n]=function(){return this.__filtered__?new zn(this):this[r](1)}}),Pn(["pluck","where"],function(n,t){var r=t?"filter":"map",e=t?bt:ze;zn.prototype[n]=function(n){ -return this[r](e(n))}}),zn.prototype.compact=function(){return this.filter(Fe)},zn.prototype.reject=function(n,t){return n=wr(n,t,1),this.filter(function(t){return!n(t)})},zn.prototype.slice=function(n,t){n=null==n?0:+n||0;var r=this;return r.__filtered__&&(0t)?new zn(r):(0>n?r=r.takeRight(-n):n&&(r=r.drop(n)),t!==w&&(t=+t||0,r=0>t?r.dropRight(-t):r.take(t-n)),r)},zn.prototype.takeRightWhile=function(n,t){return this.reverse().takeWhile(n,t).reverse()},zn.prototype.toArray=function(){return this.take(Ru); -},_t(zn.prototype,function(n,t){var r=/^(?:filter|map|reject)|While$/.test(t),e=/^(?:first|last)$/.test(t),u=Nn[e?"take"+("last"==t?"Right":""):t];u&&(Nn.prototype[t]=function(){function t(n){return e&&i?u(n,1)[0]:u.apply(w,Jn([n],o))}var o=e?[1]:arguments,i=this.__chain__,f=this.__wrapped__,a=!!this.__actions__.length,c=f instanceof zn,l=o[0],s=c||Oo(f);return s&&r&&typeof l=="function"&&1!=l.length&&(c=s=false),l={func:ne,args:[t],thisArg:w},a=c&&!a,e&&!i?a?(f=f.clone(),f.__actions__.push(l),n.call(f)):u.call(w,this.value())[0]:!e&&s?(f=a?f:new zn(this), -f=n.apply(f,o),f.__actions__.push(l),new Ln(f,i)):this.thru(t)})}),Pn("join pop push replace shift sort splice split unshift".split(" "),function(n){var t=(/^(?:replace|split)$/.test(n)?He:Je)[n],r=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",e=/^(?:join|pop|replace|shift)$/.test(n);Nn.prototype[n]=function(){var n=arguments;return e&&!this.__chain__?t.apply(this.value(),n):this[r](function(r){return t.apply(r,n)})}}),_t(zn.prototype,function(n,t){var r=Nn[t];if(r){var e=r.name+"";(Wu[e]||(Wu[e]=[])).push({ -name:t,func:r})}}),Wu[sr(w,A).name]=[{name:"wrapper",func:w}],zn.prototype.clone=function(){var n=new zn(this.__wrapped__);return n.__actions__=qn(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=qn(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=qn(this.__views__),n},zn.prototype.reverse=function(){if(this.__filtered__){var n=new zn(this);n.__dir__=-1,n.__filtered__=true}else n=this.clone(),n.__dir__*=-1;return n},zn.prototype.value=function(){ -var n,t=this.__wrapped__.value(),r=this.__dir__,e=Oo(t),u=0>r,o=e?t.length:0;n=o;for(var i=this.__views__,f=0,a=-1,c=i.length;++a"'`]/g,pn=RegExp(ln.source),hn=RegExp(sn.source),_n=/<%-([\s\S]+?)%>/g,vn=/<%([\s\S]+?)%>/g,gn=/<%=([\s\S]+?)%>/g,yn=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\n\\]|\\.)*?\1)\]/,dn=/^\w*$/,mn=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g,wn=/^[:!,]|[\\^$.*+?()[\]{}|\/]|(^[0-9a-fA-Fnrtuvx])|([\n\r\u2028\u2029])/g,bn=RegExp(wn.source),xn=/[\u0300-\u036f\ufe20-\ufe23]/g,An=/\\(\\)?/g,jn=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,kn=/\w*$/,In=/^0[xX]/,Rn=/^\[object .+?Constructor\]$/,On=/^\d+$/,En=/[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g,Cn=/($^)/,Un=/['\n\r\u2028\u2029\\]/g,Wn=RegExp("[A-Z\\xc0-\\xd6\\xd8-\\xde]+(?=[A-Z\\xc0-\\xd6\\xd8-\\xde][a-z\\xdf-\\xf6\\xf8-\\xff]+)|[A-Z\\xc0-\\xd6\\xd8-\\xde]?[a-z\\xdf-\\xf6\\xf8-\\xff]+|[A-Z\\xc0-\\xd6\\xd8-\\xde]+|[0-9]+","g"),$n="Array ArrayBuffer Date Error Float32Array Float64Array Function Int8Array Int16Array Int32Array Math Number Object RegExp Set String _ clearTimeout isFinite parseFloat parseInt setTimeout TypeError Uint8Array Uint8ClampedArray Uint16Array Uint32Array WeakMap".split(" "),Sn={}; -Sn[X]=Sn[H]=Sn[Q]=Sn[nn]=Sn[tn]=Sn[rn]=Sn[en]=Sn[un]=Sn[on]=true,Sn[B]=Sn[D]=Sn[J]=Sn[M]=Sn[q]=Sn[P]=Sn[K]=Sn["[object Map]"]=Sn[V]=Sn[Z]=Sn[Y]=Sn["[object Set]"]=Sn[G]=Sn["[object WeakMap]"]=false;var Fn={};Fn[B]=Fn[D]=Fn[J]=Fn[M]=Fn[q]=Fn[X]=Fn[H]=Fn[Q]=Fn[nn]=Fn[tn]=Fn[V]=Fn[Z]=Fn[Y]=Fn[G]=Fn[rn]=Fn[en]=Fn[un]=Fn[on]=true,Fn[P]=Fn[K]=Fn["[object Map]"]=Fn["[object Set]"]=Fn["[object WeakMap]"]=false;var Nn={"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a", -"\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y", -"\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss"},Tn={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},Ln={"&":"&","<":"<",">":">",""":'"',"'":"'","`":"`"},zn={"function":true,object:true},Bn={0:"x30",1:"x31",2:"x32",3:"x33",4:"x34",5:"x35",6:"x36",7:"x37",8:"x38",9:"x39",A:"x41",B:"x42",C:"x43",D:"x44",E:"x45",F:"x46",a:"x61",b:"x62",c:"x63",d:"x64",e:"x65",f:"x66",n:"x6e",r:"x72",t:"x74",u:"x75",v:"x76",x:"x78"},Dn={"\\":"\\", -"'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},Mn=zn[typeof exports]&&exports&&!exports.nodeType&&exports,qn=zn[typeof module]&&module&&!module.nodeType&&module,Pn=zn[typeof self]&&self&&self.Object&&self,Kn=zn[typeof window]&&window&&window.Object&&window,Vn=qn&&qn.exports===Mn&&Mn,Zn=Mn&&qn&&typeof global=="object"&&global&&global.Object&&global||Kn!==(this&&this.window)&&Kn||Pn||this,Yn=m();typeof define=="function"&&typeof define.amd=="object"&&define.amd?(Zn._=Yn, define(function(){ -return Yn})):Mn&&qn?Vn?(qn.exports=Yn)._=Yn:Mn._=Yn:Zn._=Yn}).call(this); -(function() { - 'use strict'; - - if (self.fetch) { - return - } - - function normalizeName(name) { - if (typeof name !== 'string') { - name = String(name) - } - if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) { - throw new TypeError('Invalid character in header field name') - } - return name.toLowerCase() - } - - function normalizeValue(value) { - if (typeof value !== 'string') { - value = String(value) - } - return value - } - - function Headers(headers) { - this.map = {} - - if (headers instanceof Headers) { - headers.forEach(function(value, name) { - this.append(name, value) - }, this) - - } else if (headers) { - Object.getOwnPropertyNames(headers).forEach(function(name) { - this.append(name, headers[name]) - }, this) - } - } - - Headers.prototype.append = function(name, value) { - name = normalizeName(name) - value = normalizeValue(value) - var list = this.map[name] - if (!list) { - list = [] - this.map[name] = list - } - list.push(value) - } - - Headers.prototype['delete'] = function(name) { - delete this.map[normalizeName(name)] - } - - Headers.prototype.get = function(name) { - var values = this.map[normalizeName(name)] - return values ? values[0] : null - } - - Headers.prototype.getAll = function(name) { - return this.map[normalizeName(name)] || [] - } - - Headers.prototype.has = function(name) { - return this.map.hasOwnProperty(normalizeName(name)) - } - - Headers.prototype.set = function(name, value) { - this.map[normalizeName(name)] = [normalizeValue(value)] - } - - Headers.prototype.forEach = function(callback, thisArg) { - Object.getOwnPropertyNames(this.map).forEach(function(name) { - this.map[name].forEach(function(value) { - callback.call(thisArg, value, name, this) - }, this) - }, this) - } - - function consumed(body) { - if (body.bodyUsed) { - return Promise.reject(new TypeError('Already read')) - } - body.bodyUsed = true - } - - function fileReaderReady(reader) { - return new Promise(function(resolve, reject) { - reader.onload = function() { - resolve(reader.result) - } - reader.onerror = function() { - reject(reader.error) - } - }) - } - - function readBlobAsArrayBuffer(blob) { - var reader = new FileReader() - reader.readAsArrayBuffer(blob) - return fileReaderReady(reader) - } - - function readBlobAsText(blob) { - var reader = new FileReader() - reader.readAsText(blob) - return fileReaderReady(reader) - } - - var support = { - blob: 'FileReader' in self && 'Blob' in self && (function() { - try { - new Blob(); - return true - } catch(e) { - return false - } - })(), - formData: 'FormData' in self - } - - function Body() { - this.bodyUsed = false - - - this._initBody = function(body) { - this._bodyInit = body - if (typeof body === 'string') { - this._bodyText = body - } else if (support.blob && Blob.prototype.isPrototypeOf(body)) { - this._bodyBlob = body - } else if (support.formData && FormData.prototype.isPrototypeOf(body)) { - this._bodyFormData = body - } else if (!body) { - this._bodyText = '' - } else { - throw new Error('unsupported BodyInit type') - } - } - - if (support.blob) { - this.blob = function() { - var rejected = consumed(this) - if (rejected) { - return rejected - } - - if (this._bodyBlob) { - return Promise.resolve(this._bodyBlob) - } else if (this._bodyFormData) { - throw new Error('could not read FormData body as blob') - } else { - return Promise.resolve(new Blob([this._bodyText])) - } - } - - this.arrayBuffer = function() { - return this.blob().then(readBlobAsArrayBuffer) - } - - this.text = function() { - var rejected = consumed(this) - if (rejected) { - return rejected - } - - if (this._bodyBlob) { - return readBlobAsText(this._bodyBlob) - } else if (this._bodyFormData) { - throw new Error('could not read FormData body as text') - } else { - return Promise.resolve(this._bodyText) - } - } - } else { - this.text = function() { - var rejected = consumed(this) - return rejected ? rejected : Promise.resolve(this._bodyText) - } - } - - if (support.formData) { - this.formData = function() { - return this.text().then(decode) - } - } - - this.json = function() { - return this.text().then(JSON.parse) - } - - return this - } - - // HTTP methods whose capitalization should be normalized - var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'] - - function normalizeMethod(method) { - var upcased = method.toUpperCase() - return (methods.indexOf(upcased) > -1) ? upcased : method - } - - function Request(url, options) { - options = options || {} - this.url = url - - this.credentials = options.credentials || 'omit' - this.headers = new Headers(options.headers) - this.method = normalizeMethod(options.method || 'GET') - this.mode = options.mode || null - this.referrer = null - - if ((this.method === 'GET' || this.method === 'HEAD') && options.body) { - throw new TypeError('Body not allowed for GET or HEAD requests') - } - this._initBody(options.body) - } - - function decode(body) { - var form = new FormData() - body.trim().split('&').forEach(function(bytes) { - if (bytes) { - var split = bytes.split('=') - var name = split.shift().replace(/\+/g, ' ') - var value = split.join('=').replace(/\+/g, ' ') - form.append(decodeURIComponent(name), decodeURIComponent(value)) - } - }) - return form - } - - function headers(xhr) { - var head = new Headers() - var pairs = xhr.getAllResponseHeaders().trim().split('\n') - pairs.forEach(function(header) { - var split = header.trim().split(':') - var key = split.shift().trim() - var value = split.join(':').trim() - head.append(key, value) - }) - return head - } - - Body.call(Request.prototype) - - function Response(bodyInit, options) { - if (!options) { - options = {} - } - - this._initBody(bodyInit) - this.type = 'default' - this.url = null - this.status = options.status - this.ok = this.status >= 200 && this.status < 300 - this.statusText = options.statusText - this.headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers) - this.url = options.url || '' - } - - Body.call(Response.prototype) - - self.Headers = Headers; - self.Request = Request; - self.Response = Response; - - self.fetch = function(input, init) { - // TODO: Request constructor should accept input, init - var request - if (Request.prototype.isPrototypeOf(input) && !init) { - request = input - } else { - request = new Request(input, init) - } - - return new Promise(function(resolve, reject) { - var xhr = new XMLHttpRequest() - - function responseURL() { - if ('responseURL' in xhr) { - return xhr.responseURL - } - - // Avoid security warnings on getResponseHeader when not allowed by CORS - if (/^X-Request-URL:/m.test(xhr.getAllResponseHeaders())) { - return xhr.getResponseHeader('X-Request-URL') - } - - return; - } - - xhr.onload = function() { - var status = (xhr.status === 1223) ? 204 : xhr.status - if (status < 100 || status > 599) { - reject(new TypeError('Network request failed')) - return - } - var options = { - status: status, - statusText: xhr.statusText, - headers: headers(xhr), - url: responseURL() - } - var body = 'response' in xhr ? xhr.response : xhr.responseText; - resolve(new Response(body, options)) - } - - xhr.onerror = function() { - reject(new TypeError('Network request failed')) - } - - xhr.open(request.method, request.url, true) - - if (request.credentials === 'include') { - xhr.withCredentials = true - } - - if ('responseType' in xhr && support.blob) { - xhr.responseType = 'blob' - } - - request.headers.forEach(function(value, name) { - xhr.setRequestHeader(name, value) - }) - - xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit) - }) - } - self.fetch.polyfill = true -})(); - - - - - - - - - - - - - - - - - - -function ready(fn) { - if (document.readyState != 'loading'){ - fn(); - } else { - document.addEventListener('DOMContentLoaded', fn); - } -} - -var getValues = function(){ - var name = document.querySelector('input[name=lion-name]').value; - var pride = document.querySelector('input[name=lion-pride]').value; - var age = document.querySelector('input[type=number').value; - var gender = document.querySelector('select'); - gender = gender.options[gender.selectedIndex].value; - - - document.querySelector('input[name=lion-name]').value = ''; - document.querySelector('input[name=lion-pride]').value = ''; - document.querySelector('input[type=number').value = ''; - - - return { - name: name, - pride: pride, - age: age, - gender: gender - }; -}; - - -var lionTemplate = '

    <%= name %>'+ - '

    <%= pride %>

    '+ - 'age: <%= age %> '+ - '<%= gender %>'; - -var lions = []; - -var makeTemplate = function(data) { - var li = document.createElement('li'); - var lionList = document.querySelector('.lion-list'); - var compiled = _.template(lionTemplate); - var lionHtml = compiled(data); - li.innerHTML = lionHtml; - lionList.insertBefore(li, lionList.firstChild); -} - -var updateLionList = function(){ - var lionData = lions[lions.length-1]; - makeTemplate(lionData); -} - -var makeLionList = function() { - lions.forEach(function(lion) { - makeTemplate(lion); - }); -}; - -var getAllLions = function() { - fetch('/lions') - .then(function(resp) { - console.log(resp); - return resp.json(); - }) - .then(function(data) { - lions = lions.concat(data); - makeLionList(); - }); -} - -ready(function() { - getAllLions(); - var form = document.querySelector('form'); - - form.addEventListener('submit', function(e) { - e.preventDefault(); - - var values = getValues(); - console.log(values); - fetch('/lions', { - method: 'post', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - - body: JSON.stringify(values) - }) - .then(function(resp) { - return resp.json(); - }) - .then(function(createdLion){ - lions.push(createdLion); - updateLionList(); - }) - return false; - }) -}); diff --git a/client/index.html b/client/index.html deleted file mode 100644 index e9987a7..0000000 --- a/client/index.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - Lions - - - - -
    -

    Lions

    - -
    -
    - - - - -
    - -
    - - - - -
    - - - - - -
    - -
    -
      -
      -
      - - - diff --git a/client/style.css b/client/style.css deleted file mode 100644 index 08c888e..0000000 --- a/client/style.css +++ /dev/null @@ -1,542 +0,0 @@ -/*! 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"], /* 1 */ -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; -} - - - -/**************************************************************/ -body, html { - height: 100%; -} - -main { - width: 80vw; - margin: 0 auto; -} -.textbox { - max-width: 200px; - margin-bottom: 40px; - position: relative; - width: 100%; -} -.textbox input { - font-size: 18px; - padding: 10px 10px 10px 5px; - display: block; - width: 100%; - background: transparent; - border: none; - border-bottom: 1px solid #bf0000; -} -.textbox input:focus { - outline: none; -} -.textbox input:focus ~ .highlight { - animation: inputHighlight 0.3s ease; -} -.textbox input:focus ~ .bar:before, -.textbox input:focus ~ .bar:after { - width: 50%; -} -.textbox input:focus ~ label, -.textbox input:valid ~ label { - top: -20px; - font-size: 14px; - color: #ff1a1a; -} -.textbox label { - color: #4d0000; - font-size: 18px; - font-weight: normal; - position: absolute; - pointer-events: none; - left: 5px; - top: 10px; - transition: all 0.2s ease; -} -.textbox .bar { - position: relative; - display: block; -} -.textbox .bar:before, -.textbox .bar:after { - content: ''; - height: 2px; - width: 0; - bottom: 1px; - position: absolute; - background: #f00; - transition: ease all 0.2s; -} -.textbox .bar:before { - left: 50%; -} -.textbox .bar:after { - right: 50%; -} -.textbox .highlight { - position: absolute; - height: 60%; - width: 100px; - top: 25%; - left: 0; - pointer-events: none; - opacity: 0.5; -} -@-moz-keyframes inputHighlight { - from { - background: #f00; - } - to { - background: transparent; - width: 0; - } -} -@-webkit-keyframes inputHighlight { - from { - background: #f00; - } - to { - background: transparent; - width: 0; - } -} -@-o-keyframes inputHighlight { - from { - background: #f00; - } - to { - background: transparent; - width: 0; - } -} -@keyframes inputHighlight { - from { - background: #f00; - } - to { - background: transparent; - width: 0; - } -} diff --git a/index.js b/index.js index 68890cc..d164a97 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,15 @@ +// intro point for our server. +// PRO-TIP: if you have an index.js file +// on the root of a folder in node +// you can just require that folder and node will +// automatically require the index.js on the root + +// setup config first before anything by requiring it +var config = require('./server/config/config'); var app = require('./server/server'); +var logger = require('./server/util/logger'); + +app.listen(config.port); +logger.log('listening on http://localhost:' + config.port); + -app.listen(3000); -console.log('on port 3000'); diff --git a/package.json b/package.json index 26c6562..c91f153 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,14 @@ "description": "", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "start": "nodemon index.js", + "test": "" }, "author": "", "license": "ISC", "dependencies": { "body-parser": "^1.13.2", + "colors": "^1.1.2", "express": "^4.13.1", "lodash": "^3.10.0", "morgan": "^1.6.1" diff --git a/server/api/api.js b/server/api/api.js new file mode 100644 index 0000000..d438c24 --- /dev/null +++ b/server/api/api.js @@ -0,0 +1,9 @@ +var router = require('express').Router(); + +// api router will mount other routers +// for all our resources +router.use('/users', require('./user/userRoutes')); +router.use('/categories', require('./category/categoryRoutes')); +router.use('/posts', require('./post/postRoutes')); + +module.exports = router; diff --git a/server/api/category/categoryRoutes.js b/server/api/category/categoryRoutes.js new file mode 100644 index 0000000..865443a --- /dev/null +++ b/server/api/category/categoryRoutes.js @@ -0,0 +1,12 @@ +var router = require('express').Router(); +var logger = require('../../util/logger'); + +// setup boilerplate route jsut to satisfy a request +// for building +router.route('/') + .get(function(req, res){ + logger.log('Hey from user!!'); + res.send({ok: true}); + }); + +module.exports = router; diff --git a/server/api/post/postRoutes.js b/server/api/post/postRoutes.js new file mode 100644 index 0000000..3671e47 --- /dev/null +++ b/server/api/post/postRoutes.js @@ -0,0 +1,12 @@ +var router = require('express').Router(); +var logger = require('../../util/logger'); + +// setup boilerplate route jsut to satisfy a request +// for building +router.route('/') + .get(function(req, res){ + logger.log('Hey from post!!'); + res.send({ok: true}); + }); + +module.exports = router; diff --git a/server/api/user/userRoutes.js b/server/api/user/userRoutes.js new file mode 100644 index 0000000..865443a --- /dev/null +++ b/server/api/user/userRoutes.js @@ -0,0 +1,12 @@ +var router = require('express').Router(); +var logger = require('../../util/logger'); + +// setup boilerplate route jsut to satisfy a request +// for building +router.route('/') + .get(function(req, res){ + logger.log('Hey from user!!'); + res.send({ok: true}); + }); + +module.exports = router; diff --git a/server/config/config.js b/server/config/config.js new file mode 100644 index 0000000..2a1adf9 --- /dev/null +++ b/server/config/config.js @@ -0,0 +1,29 @@ +var _ = require('lodash'); + +var config = { + dev: 'development', + test: 'testing', + prod: 'production', + port: process.env.PORT || 3000 +}; + +process.env.NODE_ENV = process.env.NODE_ENV || config.dev; +config.env = process.env.NODE_ENV; + +var envConfig; +// require could error out if +// the file don't exist so lets try this statement +// and fallback to an empty object if it does error out +try { + envConfig = require('./' + config.env); + // just making sure the require actually + // got something back :) + envConfig = envConfig || {}; +} catch(e) { + envConfig = {}; +} + +// merge the two config files together +// the envConfig file will overwrite properties +// on the config object +module.exports = _.merge(config, envConfig); diff --git a/server/config/development.js b/server/config/development.js new file mode 100644 index 0000000..b882c8d --- /dev/null +++ b/server/config/development.js @@ -0,0 +1,4 @@ +module.exports = { + // enabled logging for development + logging: true +}; diff --git a/server/config/production.js b/server/config/production.js new file mode 100644 index 0000000..eab9e02 --- /dev/null +++ b/server/config/production.js @@ -0,0 +1,4 @@ +module.exports = { + // disbable logging for production + logging: false +}; diff --git a/server/config/testing.js b/server/config/testing.js new file mode 100644 index 0000000..72b4323 --- /dev/null +++ b/server/config/testing.js @@ -0,0 +1,4 @@ +module.exports = { + // disbable logging for testing + logging: false +}; diff --git a/server/lions.js b/server/lions.js deleted file mode 100644 index 15c4785..0000000 --- a/server/lions.js +++ /dev/null @@ -1,65 +0,0 @@ -var _ = require('lodash'); -var lionRouter = require('express').Router(); - -var lions = []; -var id = 0; - -var updateId = function(req, res, next) { - if (!req.body.id) { - id++; - req.body.id = id + ''; - } - next(); -}; - -lionRouter.param('id', function(req, res, next, id) { - var lion = _.find(lions, {id: id}) - - if (lion) { - req.lion = lion; - next(); - } else { - res.send(); - } -}); - -lionRouter.get('/', function(req, res){ - res.json(lions); -}); - -lionRouter.get('/:id', function(req, res){ - var lion = req.lion; - res.json(lion || {}); -}); - -lionRouter.post('/', updateId, function(req, res) { - var lion = req.body; - - lions.push(lion); - - res.json(lion); -}); - -lionRouter.delete('/:id', function(req, res) { - var lion = _.findIndex(lions, {id: req.params.id}); - lions.splice(lion, 1); - - res.json(req.lion); -}); - -lionRouter.put('/:id', function(req, res) { - var update = req.body; - if (update.id) { - delete update.id - } - - var lion = _.findIndex(lions, {id: req.params.id}); - if (!lions[lion]) { - res.send(); - } else { - var updatedLion = _.assign(lions[lion], update); - res.json(updatedLion); - } -}); - -module.exports = lionRouter; diff --git a/server/middleware/appMiddlware.js b/server/middleware/appMiddlware.js new file mode 100644 index 0000000..380a5d6 --- /dev/null +++ b/server/middleware/appMiddlware.js @@ -0,0 +1,9 @@ +var morgan = require('morgan'); +var bodyParser = require('body-parser'); +// setup global middleware here + +module.exports = function(app) { + app.use(morgan('dev')); + app.use(bodyParser.urlencoded({ extended: true })); + app.use(bodyParser.json()); +}; diff --git a/server/server.js b/server/server.js index fb1bfcb..2925a3f 100644 --- a/server/server.js +++ b/server/server.js @@ -1,27 +1,13 @@ var express = require('express'); -var bodyParser = require('body-parser'); var app = express(); -var _ = require('lodash'); -var morgan = require('morgan'); - -var lionRouter = require('./lions'); -var tigerRouter = require('./tigers'); - -app.use(morgan('dev')) -app.use(express.static('client')); -app.use(bodyParser.urlencoded({extended: true})); -app.use(bodyParser.json()); -// this is called mounting. when ever a req comes in for -// '/lion' we want to use this router -app.use('/lions', lionRouter); -app.use('/tigers', tigerRouter); - -app.use(function(err, req, res, next) { - if (err) { - res.status(500).send(err); - } -}); +var api = require('./api/api'); +// setup the app middlware +require('./middleware/appMiddlware')(app); +// setup the api +app.use('/api/', api); +// set up global error handling +// export the app for testing module.exports = app; diff --git a/server/spec.js b/server/spec.js deleted file mode 100644 index 7a066e9..0000000 --- a/server/spec.js +++ /dev/null @@ -1,83 +0,0 @@ -var app = require('./server'); -var request = require('supertest'); -var expect = require('chai').expect; - -describe('[LIONS]', function(){ - - it('should get all lions', function(done) { - request(app) - .get('/lions') - .set('Accept', 'application/json') - .expect('Content-Type', /json/) - .expect(200) - .end(function(err, resp) { - expect(resp.body).to.be.an('array'); - done(); - }) - }); - - it('should create a lion', function(done) { - request(app) - .post('/lions') - .send({ - name: 'Mufasa', - age: 100, - pride: 'Evil lions', - gender:'male' - }) - .set('Accept', 'application/json') - .expect('Content-Type', /json/) - .expect(201) - .end(function(err, resp) { - expect(resp.body).to.be.an('object'); - done(); - }) - }); - - it('should delete a lion', function(done) { - request(app) - .post('/lions') - .send({ - name: 'test lion', - age: 100, - pride: 'test lion', - gender:'female' - }) - .set('Accept', 'application/json') - .end(function(err, resp) { - var lion = resp.body; - request(app) - .delete('/lions/' + lion.id) - .end(function(err, resp) { - expect(resp.body).to.eql(lion); - done(); - }); - }) - }); - - it('should update a lion', function(done) { - request(app) - .post('/lions') - .send({ - name: 'test lion', - age: 100, - pride: 'test lion', - gender:'female' - }) - .set('Accept', 'application/json') - .end(function(err, resp) { - var lion = resp.body; - request(app) - .put('/lions/' + lion.id) - .send({ - name: 'new name' - }) - .end(function(err, resp) { - expect(resp.body.name).to.equal('new name'); - done(); - }); - }) - }); -}); - - diff --git a/server/tigers.js b/server/tigers.js deleted file mode 100644 index 08829b3..0000000 --- a/server/tigers.js +++ /dev/null @@ -1,58 +0,0 @@ -var tigerRouter = require('express').Router(); - -var tigers = []; -var id = 0; - -var updateId = function(req, res, next) { - if (!req.body.id) { - id++; - req.body.id = id + ''; - } - next(); -}; - -tigerRouter.param('id', function(req, res, next, id) { - var tiger = _.find(tigers, {id: id}); - - if (tiger) { - req.tiger = tiger; - next(); - } else { - res.send(); - } -}); - -tigerRouter.get('/', function(req, res){ - res.json(tigers); -}); - -tigerRouter.get('/:id', function(req, res){ - var tiger = req.tiger; - res.json(tiger || {}); -}); - -tigerRouter.post('/', updateId, function(req, res) { - var tiger = req.body; - - tigers.push(tiger); - - res.json(tiger); -}); - - -tigerRouter.put('/:id', function(req, res) { - var update = req.body; - if (update.id) { - delete update.id - } - - var tiger = _.findIndex(tigers, {id: req.params.id}); - if (!tigers[tiger]) { - res.send(); - } else { - var updatedtiger = _.assign(tigers[tiger], update); - res.json(updatedtiger); - } -}); - -module.exports = tigerRouter; diff --git a/server/util/logger.js b/server/util/logger.js new file mode 100644 index 0000000..3a311df --- /dev/null +++ b/server/util/logger.js @@ -0,0 +1,40 @@ +// no var needed here, colors will attached colors +// to String.prototype +require('colors'); +var _ = require('lodash'); + +var config = require('../config/config'); + +// create a noop (no operation) function for when loggin is disabled +var noop = function(){}; +// check if loggin is enabled in the config +// if it is, then use console.log +// if not then noop +var consoleLog = config.logging ? console.log.bind(console) : noop; + +var logger = { + log: function() { + // arguments is an array like object with all the passed + // in arguments to this function + var args = _.toArray(arguments) + .map(function(arg) { + if(typeof arg === 'object') { + // turn the object to a string so we + // can log all the properties and color it + var string = JSON.stringify(arg); + return string.magenta; + } else { + // coerce to string to color + arg+=''; + return arg.magenta; + } + }); + + // call either console.log or noop here + // with the console object as the context + // and the new colored args :) + consoleLog.apply(console, args); + } +}; + +module.exports = logger; From 9449deac036554efdf9d8e072933a9b927a381bc Mon Sep 17 00:00:00 2001 From: Hendrixer Date: Wed, 22 Jul 2015 20:53:40 -0500 Subject: [PATCH 12/22] chore --- server/util/logger.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/util/logger.js b/server/util/logger.js index 3a311df..a741055 100644 --- a/server/util/logger.js +++ b/server/util/logger.js @@ -21,7 +21,7 @@ var logger = { if(typeof arg === 'object') { // turn the object to a string so we // can log all the properties and color it - var string = JSON.stringify(arg); + var string = JSON.stringify(arg, 2); return string.magenta; } else { // coerce to string to color From ef7f2ec310f128f73047d378c526a903c37da5ce Mon Sep 17 00:00:00 2001 From: Hendrixer Date: Wed, 22 Jul 2015 21:49:33 -0500 Subject: [PATCH 13/22] chore --- package.json | 1 + server/dbTester.js | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 server/dbTester.js diff --git a/package.json b/package.json index c91f153..4f31f28 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "colors": "^1.1.2", "express": "^4.13.1", "lodash": "^3.10.0", + "mongoose": "^4.0.8", "morgan": "^1.6.1" }, "devDependencies": { diff --git a/server/dbTester.js b/server/dbTester.js new file mode 100644 index 0000000..589951c --- /dev/null +++ b/server/dbTester.js @@ -0,0 +1,21 @@ +var mongoose = require('mongoose'); +mongoose.connect('mongodb://127.0.0.1/sip'); +// connect to a database so the below will work. +// what's happening is that we're querying yor mongo db +// on the todos collection and +// logging the results. The todos collection +// will be created for you so no need to make that. +// So in the mongo shell in the terminal, +// or in here if you're feeling ambitions, +// you need to add some documents +// to the todos collection. +// run node server/db.Tester to execute this file +// MAKE SURE MONGOD is RUNNING + +var TodoSchema = new mongoose.Schema({}); + +var Todo = mongoose.model('todo', TodoSchema); + +Todo.find({}, function(err, todos) { + console.log(err, todos); +}); From c63842f3b4cd30de6eeda186b67d14103e7085f6 Mon Sep 17 00:00:00 2001 From: Hendrixer Date: Wed, 22 Jul 2015 21:51:12 -0500 Subject: [PATCH 14/22] chore --- package.json | 1 - server/dbTester.js | 21 --------------------- 2 files changed, 22 deletions(-) delete mode 100644 server/dbTester.js diff --git a/package.json b/package.json index 4f31f28..c91f153 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,6 @@ "colors": "^1.1.2", "express": "^4.13.1", "lodash": "^3.10.0", - "mongoose": "^4.0.8", "morgan": "^1.6.1" }, "devDependencies": { diff --git a/server/dbTester.js b/server/dbTester.js deleted file mode 100644 index 589951c..0000000 --- a/server/dbTester.js +++ /dev/null @@ -1,21 +0,0 @@ -var mongoose = require('mongoose'); -mongoose.connect('mongodb://127.0.0.1/sip'); -// connect to a database so the below will work. -// what's happening is that we're querying yor mongo db -// on the todos collection and -// logging the results. The todos collection -// will be created for you so no need to make that. -// So in the mongo shell in the terminal, -// or in here if you're feeling ambitions, -// you need to add some documents -// to the todos collection. -// run node server/db.Tester to execute this file -// MAKE SURE MONGOD is RUNNING - -var TodoSchema = new mongoose.Schema({}); - -var Todo = mongoose.model('todo', TodoSchema); - -Todo.find({}, function(err, todos) { - console.log(err, todos); -}); From 01a993d5000439a0c2b3f8c12ab5f381c9aec0d5 Mon Sep 17 00:00:00 2001 From: Hendrixer Date: Wed, 22 Jul 2015 21:52:17 -0500 Subject: [PATCH 15/22] chore --- dbTester.js | 21 +++++++++++++++++++++ package.json | 1 + 2 files changed, 22 insertions(+) create mode 100644 dbTester.js diff --git a/dbTester.js b/dbTester.js new file mode 100644 index 0000000..589951c --- /dev/null +++ b/dbTester.js @@ -0,0 +1,21 @@ +var mongoose = require('mongoose'); +mongoose.connect('mongodb://127.0.0.1/sip'); +// connect to a database so the below will work. +// what's happening is that we're querying yor mongo db +// on the todos collection and +// logging the results. The todos collection +// will be created for you so no need to make that. +// So in the mongo shell in the terminal, +// or in here if you're feeling ambitions, +// you need to add some documents +// to the todos collection. +// run node server/db.Tester to execute this file +// MAKE SURE MONGOD is RUNNING + +var TodoSchema = new mongoose.Schema({}); + +var Todo = mongoose.model('todo', TodoSchema); + +Todo.find({}, function(err, todos) { + console.log(err, todos); +}); diff --git a/package.json b/package.json index c91f153..4f31f28 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "colors": "^1.1.2", "express": "^4.13.1", "lodash": "^3.10.0", + "mongoose": "^4.0.8", "morgan": "^1.6.1" }, "devDependencies": { From b179f09bc0a202e12ed7073a44b557f33708973a Mon Sep 17 00:00:00 2001 From: Hendrixer Date: Wed, 22 Jul 2015 21:57:28 -0500 Subject: [PATCH 16/22] chore --- dbTester.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbTester.js b/dbTester.js index 589951c..37f66e2 100644 --- a/dbTester.js +++ b/dbTester.js @@ -1,5 +1,5 @@ var mongoose = require('mongoose'); -mongoose.connect('mongodb://127.0.0.1/sip'); + // connect to a database so the below will work. // what's happening is that we're querying yor mongo db // on the todos collection and From 8f9dced04f437c50b2464137f1c3ca78feabe5cf Mon Sep 17 00:00:00 2001 From: Hendrixer Date: Wed, 22 Jul 2015 22:09:01 -0500 Subject: [PATCH 17/22] chore --- dbTester.js | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/dbTester.js b/dbTester.js index 37f66e2..88e5930 100644 --- a/dbTester.js +++ b/dbTester.js @@ -1,21 +1,24 @@ var mongoose = require('mongoose'); // connect to a database so the below will work. -// what's happening is that we're querying yor mongo db -// on the todos collection and -// logging the results. The todos collection -// will be created for you so no need to make that. +// what's happening is that we're createing a new schema +// and making a todos collection and a Todo model. +// We then create new Todo. // So in the mongo shell in the terminal, -// or in here if you're feeling ambitions, -// you need to add some documents -// to the todos collection. +// connect to your database and uery it there +// and see if you see the todo below log in the terminal // run node server/db.Tester to execute this file // MAKE SURE MONGOD is RUNNING -var TodoSchema = new mongoose.Schema({}); +var TodoSchema = new mongoose.Schema({ + name: String, + completed: Boolean +}); var Todo = mongoose.model('todo', TodoSchema); - -Todo.find({}, function(err, todos) { - console.log(err, todos); +Todo.create({ + name: 'clean up your room!!!', + completed: false +}).then(function(err, todo) { + console.log(err, todo); }); From 55fe70142b0ab815a00bd6d84b2593429b839a05 Mon Sep 17 00:00:00 2001 From: Hendrixer Date: Wed, 22 Jul 2015 22:33:39 -0500 Subject: [PATCH 18/22] chore --- dbTester.js | 24 ------------------------ server/api/category/categoryModel.js | 12 ++++++++++++ server/api/post/postModel.js | 21 +++++++++++++++++++++ server/api/user/userModel.js | 12 ++++++++++++ server/config/development.js | 5 ++++- server/config/testing.js | 5 ++++- server/server.js | 3 +++ 7 files changed, 56 insertions(+), 26 deletions(-) delete mode 100644 dbTester.js create mode 100644 server/api/category/categoryModel.js create mode 100644 server/api/post/postModel.js create mode 100644 server/api/user/userModel.js diff --git a/dbTester.js b/dbTester.js deleted file mode 100644 index 88e5930..0000000 --- a/dbTester.js +++ /dev/null @@ -1,24 +0,0 @@ -var mongoose = require('mongoose'); - -// connect to a database so the below will work. -// what's happening is that we're createing a new schema -// and making a todos collection and a Todo model. -// We then create new Todo. -// So in the mongo shell in the terminal, -// connect to your database and uery it there -// and see if you see the todo below log in the terminal -// run node server/db.Tester to execute this file -// MAKE SURE MONGOD is RUNNING - -var TodoSchema = new mongoose.Schema({ - name: String, - completed: Boolean -}); - -var Todo = mongoose.model('todo', TodoSchema); -Todo.create({ - name: 'clean up your room!!!', - completed: false -}).then(function(err, todo) { - console.log(err, todo); -}); diff --git a/server/api/category/categoryModel.js b/server/api/category/categoryModel.js new file mode 100644 index 0000000..f974543 --- /dev/null +++ b/server/api/category/categoryModel.js @@ -0,0 +1,12 @@ +var mongoose = require('mongoose'); +var Schema = mongoose.Schema; + +var CategorySchema = new Schema({ + name: { + type: String, + required: true, + unique: true + } +}); + +module.exports = mongoose.model('category', CategorySchema); diff --git a/server/api/post/postModel.js b/server/api/post/postModel.js new file mode 100644 index 0000000..196a0f8 --- /dev/null +++ b/server/api/post/postModel.js @@ -0,0 +1,21 @@ +var mongoose = require('mongoose'); +var Schema = mongoose.Schema; + +var PostSchema = new Schema({ + title: { + type: String, + required: true, + unique: true + }, + + text: { + type: String, + required: true + }, + // array of ids from the users + author: [{type: Schema.Types.ObjectId, ref: 'user'}], + + categories: [type: Schema.Types.ObjectId, ref: 'category'] +}); + +module.exports = mongoose.model('post', PostSchema); diff --git a/server/api/user/userModel.js b/server/api/user/userModel.js new file mode 100644 index 0000000..a46b880 --- /dev/null +++ b/server/api/user/userModel.js @@ -0,0 +1,12 @@ +var mongoose = require('mongoose'); +var Schema = mongoose.Schema; + +var UserSchema = new Schema({ + username: { + type: String, + unique: true, + required: true + } +}); + +module.exports = mongoose.model('user', UserSchema); diff --git a/server/config/development.js b/server/config/development.js index b882c8d..1495217 100644 --- a/server/config/development.js +++ b/server/config/development.js @@ -1,4 +1,7 @@ module.exports = { // enabled logging for development - logging: true + logging: true, + db: { + url: 'mongodb://localhost/nodeblog' + } }; diff --git a/server/config/testing.js b/server/config/testing.js index 72b4323..d9ff459 100644 --- a/server/config/testing.js +++ b/server/config/testing.js @@ -1,4 +1,7 @@ module.exports = { // disbable logging for testing - logging: false + logging: false, + db: { + url: 'mongodb://localhost/nodeblog-test' + } }; diff --git a/server/server.js b/server/server.js index 2925a3f..8eda1f7 100644 --- a/server/server.js +++ b/server/server.js @@ -1,6 +1,9 @@ var express = require('express'); var app = express(); var api = require('./api/api'); +var config = require('./config/config'); +// db.url is different depending on NODE_ENV +require('mongoose').connect(config.db.url); // setup the app middlware require('./middleware/appMiddlware')(app); From 9375e0e3a613aaa4944da39059a26f938091dd8a Mon Sep 17 00:00:00 2001 From: Hendrixer Date: Thu, 23 Jul 2015 06:51:11 -0500 Subject: [PATCH 19/22] chore --- server/api/category/categoryController.js | 67 ++++++++++++++++++++++ server/api/post/postController.js | 69 +++++++++++++++++++++++ server/api/user/userController.js | 67 ++++++++++++++++++++++ 3 files changed, 203 insertions(+) create mode 100644 server/api/category/categoryController.js create mode 100644 server/api/post/postController.js create mode 100644 server/api/user/userController.js diff --git a/server/api/category/categoryController.js b/server/api/category/categoryController.js new file mode 100644 index 0000000..fe6fcbb --- /dev/null +++ b/server/api/category/categoryController.js @@ -0,0 +1,67 @@ +var Category = require('./categoryModel'); +var _ = require('lodash'); + +exports.params = function(req, res, next, id) { + Category.findById(id) + .then(function(category) { + if (!category) { + next(new Error('No category with that id')); + } else { + req.category = category; + next(); + } + }, function(err) { + next(err); + }); +}; + +exports.get = function(req, res, next) { + Category.find({}) + .then(function(categories){ + res.json(categories); + }, function(err){ + next(err); + }); +}; + +exports.getOne = function(req, res, next) { + var category = req.category; + res.json(category); +}; + +exports.put = function(req, res, next) { + var category = req.category; + + var update = req.body; + + _.merge(category, update); + + category.save(function(err, saved) { + if (err) { + next(err); + } else { + res.json(saved); + } + }) +}; + +exports.post = function(req, res, next) { + var newcategory = req.body; + + Category.create(newcategory) + .then(function(category) { + res.json(category); + }, function(err) { + next(err); + }); +}; + +exports.delete = function(req, res, next) { + req.category.remove(function(err, removed) { + if (err) { + next(err); + } else { + res.json(removed); + } + }); +}; diff --git a/server/api/post/postController.js b/server/api/post/postController.js new file mode 100644 index 0000000..9d95e26 --- /dev/null +++ b/server/api/post/postController.js @@ -0,0 +1,69 @@ +var Post = require('./postModel'); +var _ = require('lodash'); + +exports.params = function(req, res, next, id) { + Post.findById(id) + .then(function(post) { + if (!post) { + next(new Error('No post with that id')); + } else { + req.post = post; + next(); + } + }, function(err) { + next(err); + }); +}; + +exports.get = function(req, res, next) { + Post.find({}) + .populate('author categories') + .exec() + .then(function(posts){ + res.json(posts); + }, function(err){ + next(err); + }); +}; + +exports.getOne = function(req, res, next) { + var post = req.post; + res.json(post); +}; + +exports.put = function(req, res, next) { + var post = req.post; + + var update = req.body; + + _.merge(post, update); + + post.save(function(err, saved) { + if (err) { + next(err); + } else { + res.json(saved); + } + }) +}; + +exports.post = function(req, res, next) { + var newpost = req.body; + + Post.create(newpost) + .then(function(post) { + res.json(post); + }, function(err) { + next(err); + }); +}; + +exports.delete = function(req, res, next) { + req.post.remove(function(err, removed) { + if (err) { + next(err); + } else { + res.json(removed); + } + }); +}; diff --git a/server/api/user/userController.js b/server/api/user/userController.js new file mode 100644 index 0000000..8a7a2fc --- /dev/null +++ b/server/api/user/userController.js @@ -0,0 +1,67 @@ +var User = require('./userModel'); +var _ = require('lodash'); + +exports.params = function(req, res, next, id) { + User.findById(id) + .then(function(user) { + if (!user) { + next(new Error('No user with that id')); + } else { + req.user = user; + next(); + } + }, function(err) { + next(err); + }); +}; + +exports.get = function(req, res, next) { + User.find({}) + .then(function(users){ + res.json(users); + }, function(err){ + next(err); + }); +}; + +exports.getOne = function(req, res, next) { + var user = req.user; + res.json(user); +}; + +exports.put = function(req, res, next) { + var user = req.user; + + var update = req.body; + + _.merge(user, update); + + user.save(function(err, saved) { + if (err) { + next(err); + } else { + res.json(saved); + } + }) +}; + +exports.post = function(req, res, next) { + var newUser = req.body; + + User.create(newUser) + .then(function(user) { + res.json(user); + }, function(err) { + next(err); + }); +}; + +exports.delete = function(req, res, next) { + req.user.remove(function(err, removed) { + if (err) { + next(err); + } else { + res.json(removed); + } + }); +}; From 858f34a1cd89357593a148859445107a3debbbfa Mon Sep 17 00:00:00 2001 From: Hendrixer Date: Thu, 23 Jul 2015 07:13:27 -0500 Subject: [PATCH 20/22] chore --- server/api/category/categoryRoutes.js | 15 ++++++++++----- server/api/post/postController.js | 3 ++- server/api/post/postModel.js | 2 +- server/api/post/postRoutes.js | 15 ++++++++++----- server/api/user/userRoutes.js | 14 +++++++++----- server/util/logger.js | 4 ++++ 6 files changed, 36 insertions(+), 17 deletions(-) diff --git a/server/api/category/categoryRoutes.js b/server/api/category/categoryRoutes.js index 865443a..1433792 100644 --- a/server/api/category/categoryRoutes.js +++ b/server/api/category/categoryRoutes.js @@ -1,12 +1,17 @@ var router = require('express').Router(); var logger = require('../../util/logger'); - +var controller = require('./categoryController'); // setup boilerplate route jsut to satisfy a request // for building +router.param('id', controller.params); + router.route('/') - .get(function(req, res){ - logger.log('Hey from user!!'); - res.send({ok: true}); - }); + .get(controller.get) + .post(controller.post) + +router.route('/:id') + .get(controller.getOne) + .put(controller.put) + .delete(controller.delete) module.exports = router; diff --git a/server/api/post/postController.js b/server/api/post/postController.js index 9d95e26..9ff78d6 100644 --- a/server/api/post/postController.js +++ b/server/api/post/postController.js @@ -1,5 +1,6 @@ var Post = require('./postModel'); var _ = require('lodash'); +var logger = require('../../util/logger'); exports.params = function(req, res, next, id) { Post.findById(id) @@ -49,11 +50,11 @@ exports.put = function(req, res, next) { exports.post = function(req, res, next) { var newpost = req.body; - Post.create(newpost) .then(function(post) { res.json(post); }, function(err) { + logger.error(err); next(err); }); }; diff --git a/server/api/post/postModel.js b/server/api/post/postModel.js index 196a0f8..b2827eb 100644 --- a/server/api/post/postModel.js +++ b/server/api/post/postModel.js @@ -15,7 +15,7 @@ var PostSchema = new Schema({ // array of ids from the users author: [{type: Schema.Types.ObjectId, ref: 'user'}], - categories: [type: Schema.Types.ObjectId, ref: 'category'] + categories: [{type: Schema.Types.ObjectId, ref: 'category'}] }); module.exports = mongoose.model('post', PostSchema); diff --git a/server/api/post/postRoutes.js b/server/api/post/postRoutes.js index 3671e47..a9d67f5 100644 --- a/server/api/post/postRoutes.js +++ b/server/api/post/postRoutes.js @@ -1,12 +1,17 @@ var router = require('express').Router(); var logger = require('../../util/logger'); - +var controller = require('./postController'); // setup boilerplate route jsut to satisfy a request // for building +router.param('id', controller.params); + router.route('/') - .get(function(req, res){ - logger.log('Hey from post!!'); - res.send({ok: true}); - }); + .get(controller.get) + .post(controller.post) + +router.route('/:id') + .get(controller.getOne) + .put(controller.put) + .delete(controller.delete) module.exports = router; diff --git a/server/api/user/userRoutes.js b/server/api/user/userRoutes.js index 865443a..1399680 100644 --- a/server/api/user/userRoutes.js +++ b/server/api/user/userRoutes.js @@ -1,12 +1,16 @@ var router = require('express').Router(); var logger = require('../../util/logger'); - +var controller = require('./userController'); // setup boilerplate route jsut to satisfy a request // for building +router.param('id', controller.params); + router.route('/') - .get(function(req, res){ - logger.log('Hey from user!!'); - res.send({ok: true}); - }); + .get(controller.get) + .post(controller.post) +router.route('/:id') + .get(controller.getOne) + .put(controller.put) + .delete(controller.delete) module.exports = router; diff --git a/server/util/logger.js b/server/util/logger.js index a741055..2a858e0 100644 --- a/server/util/logger.js +++ b/server/util/logger.js @@ -34,6 +34,10 @@ var logger = { // with the console object as the context // and the new colored args :) consoleLog.apply(console, args); + }, + + error: function() { + consoleLog.apply(console, _.toArray(arguments)); } }; From dcc5a614e0e989043ad9c1150a41a6ac7dff50be Mon Sep 17 00:00:00 2001 From: Hendrixer Date: Thu, 23 Jul 2015 20:26:12 -0500 Subject: [PATCH 21/22] chore --- server/api/post/postController.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/api/post/postController.js b/server/api/post/postController.js index 9ff78d6..2ac1755 100644 --- a/server/api/post/postController.js +++ b/server/api/post/postController.js @@ -4,6 +4,8 @@ var logger = require('../../util/logger'); exports.params = function(req, res, next, id) { Post.findById(id) + .populate('author') + .exec() .then(function(post) { if (!post) { next(new Error('No post with that id')); From ad37e719f42933ee1704247822894958f14559aa Mon Sep 17 00:00:00 2001 From: Hendrixer Date: Fri, 24 Jul 2015 11:12:45 -0500 Subject: [PATCH 22/22] chore --- server/api/category/categoryRoutes.js | 14 ++------------ server/api/post/postModel.js | 4 ++-- server/api/post/postRoutes.js | 14 ++------------ server/api/user/userRoutes.js | 13 ++----------- server/util/createRoutes.js | 12 ++++++++++++ 5 files changed, 20 insertions(+), 37 deletions(-) create mode 100644 server/util/createRoutes.js diff --git a/server/api/category/categoryRoutes.js b/server/api/category/categoryRoutes.js index 1433792..5279eec 100644 --- a/server/api/category/categoryRoutes.js +++ b/server/api/category/categoryRoutes.js @@ -1,17 +1,7 @@ var router = require('express').Router(); var logger = require('../../util/logger'); var controller = require('./categoryController'); -// setup boilerplate route jsut to satisfy a request -// for building -router.param('id', controller.params); - -router.route('/') - .get(controller.get) - .post(controller.post) - -router.route('/:id') - .get(controller.getOne) - .put(controller.put) - .delete(controller.delete) +var createRoutes = require('../../util/createRoutes'); +createRoutes(controller, router); module.exports = router; diff --git a/server/api/post/postModel.js b/server/api/post/postModel.js index b2827eb..d0ae4ef 100644 --- a/server/api/post/postModel.js +++ b/server/api/post/postModel.js @@ -12,8 +12,8 @@ var PostSchema = new Schema({ type: String, required: true }, - // array of ids from the users - author: [{type: Schema.Types.ObjectId, ref: 'user'}], + + author: {type: Schema.Types.ObjectId, ref: 'user'}, categories: [{type: Schema.Types.ObjectId, ref: 'category'}] }); diff --git a/server/api/post/postRoutes.js b/server/api/post/postRoutes.js index a9d67f5..021b4e0 100644 --- a/server/api/post/postRoutes.js +++ b/server/api/post/postRoutes.js @@ -1,17 +1,7 @@ var router = require('express').Router(); var logger = require('../../util/logger'); var controller = require('./postController'); -// setup boilerplate route jsut to satisfy a request -// for building -router.param('id', controller.params); - -router.route('/') - .get(controller.get) - .post(controller.post) - -router.route('/:id') - .get(controller.getOne) - .put(controller.put) - .delete(controller.delete) +var createRoutes = require('../../util/createRoutes'); +createRoutes(controller, router); module.exports = router; diff --git a/server/api/user/userRoutes.js b/server/api/user/userRoutes.js index 1399680..fd3fdcb 100644 --- a/server/api/user/userRoutes.js +++ b/server/api/user/userRoutes.js @@ -1,16 +1,7 @@ var router = require('express').Router(); var logger = require('../../util/logger'); var controller = require('./userController'); -// setup boilerplate route jsut to satisfy a request -// for building -router.param('id', controller.params); +var createRoutes = require('../../util/createRoutes'); +createRoutes(controller, router); -router.route('/') - .get(controller.get) - .post(controller.post) - -router.route('/:id') - .get(controller.getOne) - .put(controller.put) - .delete(controller.delete) module.exports = router; diff --git a/server/util/createRoutes.js b/server/util/createRoutes.js new file mode 100644 index 0000000..8ac6b26 --- /dev/null +++ b/server/util/createRoutes.js @@ -0,0 +1,12 @@ +module.exports = function(controller, router) { + router.param('id', controller.params); + + router.route('/') + .get(controller.get) + .post(controller.post) + + router.route('/:id') + .get(controller.getOne) + .put(controller.put) + .delete(controller.delete) +};