diff --git a/dustin/.eslintrc b/dustin/.eslintrc
new file mode 100644
index 0000000..468db4e
--- /dev/null
+++ b/dustin/.eslintrc
@@ -0,0 +1,28 @@
+{
+ "env": {
+ "es6": true,
+ "node": true
+ },
+ "extends": "eslint:recommended",
+ "parserOptions": {
+ "sourceType": "module"
+ },
+ "rules": {
+ "indent": [
+ "error",
+ 2
+ ],
+ "linebreak-style": [
+ "error",
+ "unix"
+ ],
+ "quotes": [
+ "error",
+ "single"
+ ],
+ "semi": [
+ "error",
+ "always"
+ ]
+ }
+}
diff --git a/dustin/gulpfile.js b/dustin/gulpfile.js
new file mode 100644
index 0000000..205ef66
--- /dev/null
+++ b/dustin/gulpfile.js
@@ -0,0 +1,25 @@
+var gulp = require('gulp');
+var eslint = require('gulp-eslint');
+var mocha = require('gulp-mocha');
+
+
+gulp.task('watch', function () {
+ gulp.watch(['*.js', '../test/*.js'], ['lint', 'mocha']);
+});
+
+gulp.task('default', ['mocha', 'lint', 'watch'], function () {});
+
+gulp.task('lint', function () {
+ gulp.src(['./*.js', './test/*.js', './lib/*.js'])
+ .pipe(eslint()) //{} pass in rules
+ .pipe(eslint.format());
+});
+
+gulp.task('mocha', function () {
+ return gulp.src('./test/*.js', {
+ read: false
+ })
+ .pipe(mocha({
+ reporter: 'nyan'
+ }));
+});
diff --git a/dustin/lib/getnextid.js b/dustin/lib/getnextid.js
new file mode 100644
index 0000000..3d5d39a
--- /dev/null
+++ b/dustin/lib/getnextid.js
@@ -0,0 +1,15 @@
+module.exports = function (dataPath) {
+ var fs = require('fs');
+
+ // fs.readdir(dataPath, function (err, files) {
+ // return files.map(function (f) {
+ // return f.split('.')[0];
+ // });
+ // });
+
+ var files = fs.readdirSync(dataPath);
+ var nums = files.map(function (f) {
+ return f.split('.')[0];
+ });
+ return Math.max.apply(null,nums) + 1;
+};
diff --git a/dustin/package.json b/dustin/package.json
new file mode 100644
index 0000000..25f5c1f
--- /dev/null
+++ b/dustin/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "basic_http_server",
+ "version": "1.0.0",
+ "description": "",
+ "main": "server.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "ISC",
+ "devDependencies": {
+ "chai": "^3.5.0",
+ "chai-http": "^2.0.1",
+ "gulp": "^3.9.1",
+ "gulp-eslint": "^2.0.0",
+ "gulp-mocha": "^2.2.0",
+ "gulp-watch": "^4.3.5",
+ "mocha": "^2.4.5"
+ }
+}
diff --git a/dustin/server.js b/dustin/server.js
new file mode 100644
index 0000000..483e85e
--- /dev/null
+++ b/dustin/server.js
@@ -0,0 +1,80 @@
+'use strict';
+
+const http = require('http');
+const noteDataPath = (__dirname + '/data');
+var fs = require('fs');
+var getNextId = require('./lib/getnextid');
+var stream = require('stream');
+var header = fs.readFileSync('./view/_header.html');
+var footer = fs.readFileSync('./view/_footer.html');
+var nextNoteId = getNextId(noteDataPath);
+
+http.createServer(function (req, res) {
+
+ res.processed = false;
+ var url_array = req.url.split('/');
+
+ if (req.method === 'GET' && url_array[1] === 'notes') notesIndex(res);
+ if (req.method === 'GET' && url_array[1] === 'notes' && (url_array[2])) notesShow(res);
+ if (req.method === 'POST' && url_array[1] === 'notes') notesPost(res, req);
+ if (res.processed === false) url404(res);
+
+}).listen(3000);
+
+var notesIndex = function (res) {
+ res.processed = true;
+ fs.readdir(noteDataPath, function (err, files) {
+ var payload = '';
+ files.forEach(function (f) {
+ payload = payload + f + '
';
+ });
+ renderLayout(res, payload);
+ });
+};
+
+var notesShow = function (res) {
+ res.write('works');
+ res.end();
+};
+
+var notesPost = function (res, req) {
+ res.processed = true;
+ var body = '';
+ req.on('data', function (data) {
+ body += data;
+ });
+ req.on('end', function () {
+ if (req.headers['content-type'] === 'application/json') {
+ var file = fs.createWriteStream(noteDataPath + '/' + nextNoteId + '.json');
+ var bufferStream = new stream.PassThrough();
+ var inBuf = new Buffer(JSON.stringify(body));
+ bufferStream.end(inBuf);
+ bufferStream.pipe(file);
+ res.end();
+ } else {
+ badRequest(res);
+ }
+ });
+};
+
+var url404 = function (res) {
+ res.writeHead(404, {
+ 'Content-Type': 'text/html'
+ });
+ res.write('Not found');
+ res.end();
+};
+
+var badRequest = function (res) {
+ res.processed = true;
+ res.writeHead(400, {
+ 'Content-Type': 'text/html'
+ });
+ res.write('BAD REQUEST');
+ res.end();
+};
+
+var renderLayout = function (res, payload) {
+ res.write(header + payload + footer);
+ res.end();
+};
diff --git a/dustin/test/server_test.js b/dustin/test/server_test.js
new file mode 100644
index 0000000..2eb8bf4
--- /dev/null
+++ b/dustin/test/server_test.js
@@ -0,0 +1,95 @@
+var chai = require('chai');
+var chaiHTTP = require('chai-http');
+var fs = require('fs');
+var expect = chai.expect;
+chai.use(chaiHTTP);
+var request = chai.request;
+
+var getNextId = require('../lib/getnextid');
+var noteDataPath = (__dirname + '/../data');
+var nextNoteId = getNextId(noteDataPath);
+
+var header = fs.readFileSync('./view/_header.html');
+var footer = fs.readFileSync('./view/_footer.html');
+
+require('../server');
+
+describe('HTTP server', function () {
+ it('/notes should respond with a list of all of the json files', function (done) {
+ files = fs.readdirSync('./data');
+ request('localhost:3000')
+ .get('/notes')
+ .end(function (err, res) {
+ expect(err).to.eql(null);
+ expect(res).to.have.status(200);
+ var payload = '';
+ files.forEach(function (f) {
+ payload = payload + f + '
';
+ });
+ expect(res.text).to.eql(header + payload + footer);
+ done();
+ });
+ });
+
+ it('accept a POST request to /notes with proper headers and payload and be saved correctly', function (done) {
+ var noteJSON = "{'noteBody': 'buy milk'}";
+ var filename = noteDataPath + '/' + (nextNoteId - 1) + '.json';
+ var fileBirthtime = fs.statSync(filename)['birthtime'];
+ request('localhost:3000')
+ .post('/notes')
+ .set('Content-Type', 'application/json')
+ .send(noteJSON)
+ .end(function (err, res) {
+ expect(err).to.eql(null);
+ expect(res).to.have.status(200);
+ expect(Date.now() - Date.parse(fileBirthtime)).to.be.below(100000);
+ expect(noteJSON).to.eql(JSON.parse(fs.readFileSync(filename)));
+ done();
+ });
+ });
+
+ it('return a 404 when no route is found', function (done) {
+ request('localhost:3000')
+ .get('/nothere')
+ .end(function (err, res) {
+ expect(res).to.have.status(404);
+ done();
+ });
+ });
+
+ // it('return an error to a POST request to /notes without proper headers', function (done) {
+ // request('localhost:3000')
+ // .post('/greet')
+ // .set('Content-Type', 'text/html')
+ // .send({
+ // 'name': 'walter sobchak'
+ // })
+ // .end(function (err, res) {
+ // expect(err).to.eql(null);
+ // expect(res).to.have.status(200);
+ // expect(savedJSON).to.eql([{
+ // 'name': 'walter sobchak'
+ // }]);
+ // done();
+ // });
+ // });
+
+ // it('return an error to a POST request to /notes without proper payload', function (done) {
+ // request('localhost:3000')
+ // .post('/greet')
+ // .set('Content-Type', 'application/json')
+ // .send({
+ // 'name': 'walter sobchak'
+ // })
+ // .end(function (err, res) {
+ // expect(err).to.eql(null);
+ // expect(res).to.have.status(200);
+ // expect(savedJSON).to.eql([{
+ // 'name': 'walter sobchak'
+ // }]);
+ // done();
+ // });
+ // });
+ //
+
+});
diff --git a/dustin/view/_footer.html b/dustin/view/_footer.html
new file mode 100644
index 0000000..44b22a9
--- /dev/null
+++ b/dustin/view/_footer.html
@@ -0,0 +1 @@
+