diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..9256b26
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Y. Mayer
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/angular/Dockerfile b/angular/Dockerfile
new file mode 100644
index 0000000..c96bfae
--- /dev/null
+++ b/angular/Dockerfile
@@ -0,0 +1,56 @@
+# Install stage
+FROM node:8-alpine as install
+
+RUN mkdir -p /usr/src/app
+
+WORKDIR /usr/src/app
+
+RUN npm install -g npm@6.1.0
+
+COPY package.json package-lock.json ./
+
+RUN npm install
+
+COPY . ./
+
+
+# Build stage
+FROM node:8-alpine as build
+
+RUN mkdir -p /usr/src/app
+
+WORKDIR /usr/src/app
+
+COPY --from=install /usr/src/app /usr/src/app
+
+RUN npm run build:prod
+
+
+# Deployment stage
+FROM nginx:1.13.5-alpine as deploy
+
+# copy generated files
+RUN rm -rf /usr/share/nginx/html/*
+COPY --from=build /usr/src/app/dist /usr/share/nginx/html/
+
+# we need bash for adding the runtime envs
+RUN apk add --no-cache bash
+
+# dumb init (forwards process signals from docker - see https://github.com/Yelp/dumb-init)
+COPY prod/dumb-init_1.2.1_amd64 /usr/bin/dumb-init
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+# set ENVs for runtime builder
+ENV INDEX_HTML_PATH /usr/share/nginx/html/index.html
+ENV OUTPUT_PATH /usr/share/nginx/html/env.json
+
+# runtime builder
+COPY scripts/add-runtime-envs.sh /add-runtime-envs.sh
+
+# init script
+COPY scripts/init-nginx-with-runtime-envs.sh /init.sh
+
+# nginx conf
+COPY prod/nginx.conf /etc/nginx/conf.d/default.conf
+
+CMD ["/init.sh"]
diff --git a/angular/Dockerfile-nginx-dev b/angular/Dockerfile-nginx-dev
new file mode 100644
index 0000000..54bb4b5
--- /dev/null
+++ b/angular/Dockerfile-nginx-dev
@@ -0,0 +1,4 @@
+FROM nginx:1.13.5-alpine
+
+# we need bash for adding the runtime envs
+RUN apk add --no-cache bash
diff --git a/angular/docker-compose.test.yml b/angular/docker-compose.test.yml
new file mode 100644
index 0000000..32dee39
--- /dev/null
+++ b/angular/docker-compose.test.yml
@@ -0,0 +1,15 @@
+version: '2.3'
+
+services:
+ driver:
+ image: selenium/standalone-chrome:latest
+
+ test:
+ image: install
+ command: /bin/true
+ environment:
+ SELENIUM_ADDRESS: http://driver:4444/wd/hub
+ BASE_URL: http://deploy/
+
+ deploy:
+ image: deploy
diff --git a/angular/docker-compose.yml b/angular/docker-compose.yml
new file mode 100644
index 0000000..7fce657
--- /dev/null
+++ b/angular/docker-compose.yml
@@ -0,0 +1,74 @@
+version: '2.3'
+
+volumes:
+ dist:
+
+services:
+
+ # app builder
+ app:
+ build:
+ context: .
+ target: install
+ image: app
+ volumes:
+ - ./:/usr/src/app
+ - dist:/usr/src/app/dist
+ - /usr/src/app/node_modules
+ command: [npm, run, watch]
+ environment:
+ BASE_PATH: /demo/
+
+ #live:
+ # build: .
+ # environment:
+ # BASE_PATH: /demo/
+ # PEOPLE_PATH: https://jsonplaceholder.typicode.com/users
+ # UI_VARS: PEOPLE_PATH
+
+ # app delivery
+ app-nginx:
+ build:
+ context: .
+ dockerfile: Dockerfile-nginx-dev
+ volumes:
+ - ./local.nginx.conf:/etc/nginx/conf.d/default.conf
+ - ./scripts/init-nginx-with-runtime-envs.sh:/init.sh
+ - ./scripts/add-runtime-envs.sh:/add-runtime-envs.sh
+ - dist:/usr/share/nginx/html
+ command: /init.sh
+ init: true # forwards process signals - see https://github.com/Yelp/dumb-init
+ environment:
+ OUTPUT_PATH: /usr/share/nginx/html/env.json
+ VAR_A: A
+ VAR_B: B
+ #PEOPLE_PATH: https://jsonplaceholder.typicode.com/users
+ UI_VARS: BASE_PATH,VAR_B
+
+ # gateway
+ proxy:
+ image: nginx:1.13.5-alpine
+ volumes:
+ - ./proxy.nginx.conf:/etc/nginx/conf.d/default.conf
+ ports:
+ - 5000:80
+
+ # webdriver
+ chrome:
+ image: selenium/standalone-chrome:latest
+ volumes:
+ - /dev/shm:/dev/shm
+
+ # e2e testing
+ e2e:
+ build:
+ context: .
+ target: install
+ image: app
+ volumes_from:
+ - app
+ working_dir: /usr/src/app
+ command: /bin/true
+ environment:
+ SELENIUM_ADDRESS: http://chrome:4444/wd/hub
+ BASE_URL: http://proxy/demo/
diff --git a/angular/scripts/add-runtime-envs.sh b/angular/scripts/add-runtime-envs.sh
new file mode 100755
index 0000000..1068e50
--- /dev/null
+++ b/angular/scripts/add-runtime-envs.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+
+# setup default env values
+INDEX_HTML_PATH=${INDEX_HTML_PATH:-''}
+BASE_PATH=${BASE_PATH:-'/'}
+UI_VARS=${UI_VARS:-''}
+OUTPUT_PATH=${OUTPUT_PATH:-'env.json'}
+
+
+# Build environment JSON for App
+## transform comma-delimited list into array
+OLDIFS=$IFS
+IFS=","
+ENVS=($UI_VARS)
+IFS=$OLDIFS
+
+## build json string
+ENVIRONMENT=""
+for ((i=0; i<${#ENVS[@]}; ++i)); do
+
+ # if not the first iteration, add comma to end of string
+ if [ $i != 0 ]; then
+ ENVIRONMENT="${ENVIRONMENT}, "
+ fi
+
+ # get the ENV's value
+ VAL=$(eval "echo \$${ENVS[i]}")
+ # add to json string
+ ENVIRONMENT="${ENVIRONMENT}\"${ENVS[i]}\": \"${VAL}\""
+done
+## finalize json string
+ENVIRONMENT="{ ${ENVIRONMENT} }"
+
+## output env json
+echo $ENVIRONMENT > $OUTPUT_PATH
+echo "Built env.json with: ${UI_VARS}"
+
+
+# Update index.html file
+if [ -n "$INDEX_HTML_PATH" ]; then
+ sed -i.bak "s##;" $INDEX_HTML_PATH
+ echo "Updated index.html with BASE_PATH: ${BASE_PATH}"
+fi
diff --git a/angular/scripts/init-nginx-with-runtime-envs.sh b/angular/scripts/init-nginx-with-runtime-envs.sh
new file mode 100755
index 0000000..4fc5a74
--- /dev/null
+++ b/angular/scripts/init-nginx-with-runtime-envs.sh
@@ -0,0 +1,3 @@
+#!/usr/bin/env sh
+
+/add-runtime-envs.sh && nginx -g "daemon off;"
diff --git a/pure-js/Dockerfile b/pure-js/Dockerfile
new file mode 100644
index 0000000..11dba43
--- /dev/null
+++ b/pure-js/Dockerfile
@@ -0,0 +1,14 @@
+FROM nginx:1.13.5-alpine
+
+# we need bash for adding the runtime envs
+RUN apk add --no-cache bash
+
+RUN rm -rf /usr/share/nginx/html/*
+
+COPY . /usr/share/nginx/html
+
+COPY scripts /add-runtime-envs.sh
+
+COPY scripts /init.sh
+
+CMD ["/init.sh"]
diff --git a/pure-js/Dockerfile-nginx-dev b/pure-js/Dockerfile-nginx-dev
new file mode 100644
index 0000000..54bb4b5
--- /dev/null
+++ b/pure-js/Dockerfile-nginx-dev
@@ -0,0 +1,4 @@
+FROM nginx:1.13.5-alpine
+
+# we need bash for adding the runtime envs
+RUN apk add --no-cache bash
diff --git a/pure-js/docker-compose.yml b/pure-js/docker-compose.yml
new file mode 100644
index 0000000..cd84d46
--- /dev/null
+++ b/pure-js/docker-compose.yml
@@ -0,0 +1,24 @@
+version: '2.2'
+
+services:
+ nginx:
+ build:
+ context: .
+ dockerfile: Dockerfile-nginx-dev
+ volumes:
+ - ./:/usr/share/nginx/html
+ - ./local.nginx.conf:/etc/nginx/conf.d/default.conf
+ - ./scripts/add-runtime-envs.sh:/add-runtime-envs.sh
+ - ./scripts/init-nginx-with-runtime-envs.sh:/init.sh
+ working_dir: /usr/share/nginx/html
+ command: /init.sh
+ init: true
+ ports:
+ - 6050:80
+ environment:
+ INDEX_HTML_PATH: index.html
+ BASE_PATH: /
+ SOME_OTHER_VAR: Yo
+ SOME_PRIVATE_VAR: You can't see me
+ IMAGE: 1
+ UI_VARS: BASE_PATH,SOME_OTHER_VAR,IMAGE
diff --git a/pure-js/scripts/add-runtime-envs.sh b/pure-js/scripts/add-runtime-envs.sh
new file mode 100755
index 0000000..1068e50
--- /dev/null
+++ b/pure-js/scripts/add-runtime-envs.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+
+# setup default env values
+INDEX_HTML_PATH=${INDEX_HTML_PATH:-''}
+BASE_PATH=${BASE_PATH:-'/'}
+UI_VARS=${UI_VARS:-''}
+OUTPUT_PATH=${OUTPUT_PATH:-'env.json'}
+
+
+# Build environment JSON for App
+## transform comma-delimited list into array
+OLDIFS=$IFS
+IFS=","
+ENVS=($UI_VARS)
+IFS=$OLDIFS
+
+## build json string
+ENVIRONMENT=""
+for ((i=0; i<${#ENVS[@]}; ++i)); do
+
+ # if not the first iteration, add comma to end of string
+ if [ $i != 0 ]; then
+ ENVIRONMENT="${ENVIRONMENT}, "
+ fi
+
+ # get the ENV's value
+ VAL=$(eval "echo \$${ENVS[i]}")
+ # add to json string
+ ENVIRONMENT="${ENVIRONMENT}\"${ENVS[i]}\": \"${VAL}\""
+done
+## finalize json string
+ENVIRONMENT="{ ${ENVIRONMENT} }"
+
+## output env json
+echo $ENVIRONMENT > $OUTPUT_PATH
+echo "Built env.json with: ${UI_VARS}"
+
+
+# Update index.html file
+if [ -n "$INDEX_HTML_PATH" ]; then
+ sed -i.bak "s##;" $INDEX_HTML_PATH
+ echo "Updated index.html with BASE_PATH: ${BASE_PATH}"
+fi
diff --git a/pure-js/scripts/init-nginx-with-runtime-envs.sh b/pure-js/scripts/init-nginx-with-runtime-envs.sh
new file mode 100755
index 0000000..4fc5a74
--- /dev/null
+++ b/pure-js/scripts/init-nginx-with-runtime-envs.sh
@@ -0,0 +1,3 @@
+#!/usr/bin/env sh
+
+/add-runtime-envs.sh && nginx -g "daemon off;"