diff --git a/stefanie-hansen/.eslintignore b/stefanie-hansen/.eslintignore
new file mode 100644
index 00000000..0221e0a8
--- /dev/null
+++ b/stefanie-hansen/.eslintignore
@@ -0,0 +1,7 @@
+**/node_modules/*
+**/vendor/*
+**/*.min.js
+**/build/*
+**/test/*-bundle*
+*.md
+package.json
diff --git a/stefanie-hansen/.eslintrc b/stefanie-hansen/.eslintrc
new file mode 100644
index 00000000..25ff6a9a
--- /dev/null
+++ b/stefanie-hansen/.eslintrc
@@ -0,0 +1,45 @@
+{
+rules: {
+no-console: 0,
+indent: [
+2,
+2,
+{
+SwitchCase: 1
+}
+],
+quotes: [
+2,
+"single"
+],
+linebreak-style: [
+2,
+"unix"
+],
+semi: [
+2,
+"always"
+]
+},
+env: {
+es6: true,
+node: true,
+browser: true,
+mocha: true,
+jasmine: true
+},
+globals: {
+describe: false,
+it: false,
+beforeEach: false,
+afterEach: false,
+before: false,
+after: false
+},
+ecmaFeatures: {
+modules: true,
+experimentalObjectRestSpread: true,
+impliedStrict: true
+},
+extends: "eslint:recommended"
+}
diff --git a/stefanie-hansen/.gitignore b/stefanie-hansen/.gitignore
new file mode 100644
index 00000000..eba66d7d
--- /dev/null
+++ b/stefanie-hansen/.gitignore
@@ -0,0 +1,107 @@
+
+# Created by https://www.gitignore.io/api/node,osx,windows,vim
+
+db/
+build/
+
+### Node ###
+# Logs
+logs
+*.log
+npm-debug.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (http://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules
+jspm_packages
+
+# Optional npm cache directory
+.npm
+
+# Optional REPL history
+.node_repl_history
+
+
+### OSX ###
+*.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+
+### Windows ###
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+
+### Vim ###
+# swap
+[._]*.s[a-w][a-z]
+[._]s[a-w][a-z]
+# session
+Session.vim
+# temporary
+.netrwhist
+*~
+# auto-generated tag files
+tags
diff --git a/stefanie-hansen/app/index.html b/stefanie-hansen/app/index.html
new file mode 100644
index 00000000..8768e130
--- /dev/null
+++ b/stefanie-hansen/app/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Error Service
+
+
+
+
+
+
diff --git a/stefanie-hansen/app/js/client.js b/stefanie-hansen/app/js/client.js
new file mode 100644
index 00000000..558d4429
--- /dev/null
+++ b/stefanie-hansen/app/js/client.js
@@ -0,0 +1,6 @@
+const angular = require('angular');
+
+const app = angular.module('ErrorApp', []);
+
+require('./services/error-handling-service')(app);
+require('./controllers/error-controller')(app);
diff --git a/stefanie-hansen/app/js/controllers/error-controller.js b/stefanie-hansen/app/js/controllers/error-controller.js
new file mode 100644
index 00000000..52f58379
--- /dev/null
+++ b/stefanie-hansen/app/js/controllers/error-controller.js
@@ -0,0 +1,5 @@
+module.exports = function(app) {
+ app.controller('ErrorController', function(ErrorService) {
+ this.sendErr = ErrorService.sendErr();
+ });
+};
diff --git a/stefanie-hansen/app/js/services/error-handling-service.js b/stefanie-hansen/app/js/services/error-handling-service.js
new file mode 100644
index 00000000..3a212fe5
--- /dev/null
+++ b/stefanie-hansen/app/js/services/error-handling-service.js
@@ -0,0 +1,18 @@
+module.exports = function(app) {
+ app.factory('ErrorService', function() {
+ const service = {};
+ const errors = [];
+ service.sendErr = function(message) {
+ return function(err) {
+ errors.push(message);
+ console.log('error: ', err);
+ };
+ };
+
+ service.getErrors = function() {
+ return errors;
+ };
+
+ return service;
+ });
+};
diff --git a/stefanie-hansen/gulpfile.js b/stefanie-hansen/gulpfile.js
new file mode 100644
index 00000000..eeb42c38
--- /dev/null
+++ b/stefanie-hansen/gulpfile.js
@@ -0,0 +1,89 @@
+const gulp = require('gulp');
+const mocha = require('gulp-mocha');
+const webpack = require('webpack-stream');
+const lint = require('gulp-eslint');
+const opts = {
+ 'extends': 'eslint:recommended',
+ 'ecmaFeatures': {
+ 'modules': true
+ },
+ 'rules': {
+ 'no-alert': 0,
+ 'no-bitwise': 0,
+ 'camelcase': 1,
+ 'no-console': 1,
+ 'curly': 1,
+ 'eqeqeq': 0,
+ 'no-eq-null': 0,
+ 'guard-for-in': 1,
+ 'no-empty': 1,
+ 'no-use-before-define': 0,
+ 'no-obj-calls': 2,
+ 'no-unused-vars': 0,
+ 'new-cap': 1,
+ 'no-shadow': 0,
+ 'strict': 1,
+ 'no-invalid-regexp': 2,
+ 'comma-dangle': 2,
+ 'no-undef': 1,
+ 'no-new': 1,
+ 'no-extra-semi': 1,
+ 'no-debugger': 2,
+ 'no-caller': 1,
+ 'semi': 1,
+ 'quotes': 0,
+ 'no-unreachable': 2
+ },
+ 'globals': {
+ '$': false
+ },
+ 'env': {
+ 'node': true,
+ 'es6': true
+ }
+};
+
+
+gulp.task('linter', () => {
+ return gulp.src(['./*.js', './model/*.js', './route/*.js', './test/*.js', './lib/*.js'])
+ .pipe(lint(opts))
+ .pipe(lint.format());
+});
+
+gulp.task('tests', () => {
+ return gulp.src(['./test/*.js'], {read: false})
+ .pipe(mocha({reporter: 'nyan'}));
+});
+
+gulp.task('copy', () => {
+ return gulp.src(__dirname + '/app/index.html')
+ .pipe(gulp.dest(__dirname + '/build'));
+});
+
+gulp.task('bundle', () => {
+ return gulp.src(__dirname + '/app/js/client.js')
+ .pipe(webpack({
+ output: {
+ filename: 'bundle.js'
+ }
+ }))
+ .pipe(gulp.dest(__dirname + '/build'));
+});
+
+gulp.task('bundle:test', () => {
+ return gulp.src(__dirname + '/test/controller-test.js')
+ .pipe(webpack({
+ output: {
+ filename: 'test-bundle.js'
+ }
+ }))
+ .pipe(gulp.dest(__dirname + '/test'));
+});
+
+
+gulp.task('watch', () => {
+ gulp.watch(['./*.js', './model/*.js', './route/*.js', './test/*.js', './lib/*.js'], ['linter', 'tests']);
+});
+
+gulp.task('default', ['linter', 'bundle', 'copy'], () => {
+});