From ace2fa6eb98935c373c4c794255b249ce09478c6 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 17 Feb 2019 17:43:06 +0100
Subject: [PATCH 01/54] Move project files to root directory

---
 dal/{dal => }/__init__.py                           |   0
 .../font-awesome/css/font-awesome.min.css           |   4 ----
 dal/{dal => }/env.sample                            |   0
 dal/{dal => }/models.py                             |   0
 dal/{dal => }/settings.py                           |   6 +++---
 .../datacenterlight/css/bootstrap-3.3.7.min.css     |   0
 dal/{dal => }/static/datacenterlight/css/cms.css    |   0
 dal/{dal => }/static/datacenterlight/css/common.css |   0
 .../static/datacenterlight/css/header-slider.css    |   0
 .../static/datacenterlight/css/hosting.css          |   0
 .../static/datacenterlight/css/landing-page.css     |   0
 .../font-awesome/css/font-awesome.min.css           |   4 ++++
 .../font-awesome/fonts/FontAwesome.otf              | Bin
 .../font-awesome/fonts/fontawesome-webfont.eot      | Bin
 .../font-awesome/fonts/fontawesome-webfont.svg      |   0
 .../font-awesome/fonts/fontawesome-webfont.ttf      | Bin
 .../font-awesome/fonts/fontawesome-webfont.woff     | Bin
 .../font-awesome/fonts/fontawesome-webfont.woff2    | Bin
 .../font-awesome/less/bordered-pulled.less          |   0
 .../datacenterlight/font-awesome/less/core.less     |   0
 .../font-awesome/less/fixed-width.less              |   0
 .../font-awesome/less/font-awesome.less             |   0
 .../datacenterlight/font-awesome/less/icons.less    |   0
 .../datacenterlight/font-awesome/less/larger.less   |   0
 .../datacenterlight/font-awesome/less/list.less     |   0
 .../datacenterlight/font-awesome/less/mixins.less   |   0
 .../datacenterlight/font-awesome/less/path.less     |   0
 .../font-awesome/less/rotated-flipped.less          |   0
 .../datacenterlight/font-awesome/less/spinning.less |   0
 .../datacenterlight/font-awesome/less/stacked.less  |   0
 .../font-awesome/less/variables.less                |   0
 .../font-awesome/scss/_bordered-pulled.scss         |   0
 .../datacenterlight/font-awesome/scss/_core.scss    |   0
 .../font-awesome/scss/_fixed-width.scss             |   0
 .../datacenterlight/font-awesome/scss/_icons.scss   |   0
 .../datacenterlight/font-awesome/scss/_larger.scss  |   0
 .../datacenterlight/font-awesome/scss/_list.scss    |   0
 .../datacenterlight/font-awesome/scss/_mixins.scss  |   0
 .../datacenterlight/font-awesome/scss/_path.scss    |   0
 .../font-awesome/scss/_rotated-flipped.scss         |   0
 .../font-awesome/scss/_spinning.scss                |   0
 .../datacenterlight/font-awesome/scss/_stacked.scss |   0
 .../font-awesome/scss/_variables.scss               |   0
 .../font-awesome/scss/font-awesome.scss             |   0
 .../fonts/Montserrat/Montserrat-Black.ttf           | Bin
 .../fonts/Montserrat/Montserrat-BlackItalic.ttf     | Bin
 .../fonts/Montserrat/Montserrat-Bold.ttf            | Bin
 .../fonts/Montserrat/Montserrat-BoldItalic.ttf      | Bin
 .../fonts/Montserrat/Montserrat-ExtraBold.ttf       | Bin
 .../fonts/Montserrat/Montserrat-ExtraBoldItalic.ttf | Bin
 .../fonts/Montserrat/Montserrat-ExtraLight.ttf      | Bin
 .../Montserrat/Montserrat-ExtraLightItalic.ttf      | Bin
 .../fonts/Montserrat/Montserrat-Italic.ttf          | Bin
 .../fonts/Montserrat/Montserrat-Light.ttf           | Bin
 .../fonts/Montserrat/Montserrat-LightItalic.ttf     | Bin
 .../fonts/Montserrat/Montserrat-Medium.ttf          | Bin
 .../fonts/Montserrat/Montserrat-MediumItalic.ttf    | Bin
 .../fonts/Montserrat/Montserrat-Regular.ttf         | Bin
 .../fonts/Montserrat/Montserrat-SemiBold.ttf        | Bin
 .../fonts/Montserrat/Montserrat-SemiBoldItalic.ttf  | Bin
 .../fonts/Montserrat/Montserrat-Thin.ttf            | Bin
 .../fonts/Montserrat/Montserrat-ThinItalic.ttf      | Bin
 .../static/datacenterlight/fonts/Montserrat/OFL.txt |   0
 .../fonts/glyphicons-halflings-regular.eot          | Bin
 .../fonts/glyphicons-halflings-regular.svg          |   0
 .../fonts/glyphicons-halflings-regular.ttf          | Bin
 .../fonts/glyphicons-halflings-regular.woff         | Bin
 .../fonts/glyphicons-halflings-regular.woff2        | Bin
 .../static/datacenterlight/img/Ceph_Logo.png        | Bin
 .../static/datacenterlight/img/banner-bg copy.jpg   | Bin
 .../static/datacenterlight/img/banner-bg.jpg        | Bin
 dal/{dal => }/static/datacenterlight/img/bg.png     | Bin
 .../static/datacenterlight/img/cdistbyungleich.png  | Bin
 .../static/datacenterlight/img/checkmark.png        | Bin
 .../static/datacenterlight/img/configure.jpg        | Bin
 .../static/datacenterlight/img/datacenterlight.png  | Bin
 .../static/datacenterlight/img/dcl-email-bg.jpg     | Bin
 .../static/datacenterlight/img/deluxeroom.jpg       | Bin
 dal/{dal => }/static/datacenterlight/img/devuan.png | Bin
 dal/{dal => }/static/datacenterlight/img/django.png | Bin
 dal/{dal => }/static/datacenterlight/img/dog.png    | Bin
 .../static/datacenterlight/img/economy.jpg          | Bin
 .../static/datacenterlight/img/facebook_logo.svg    |   0
 .../static/datacenterlight/img/favicon.ico          | Bin
 .../static/datacenterlight/img/header-bg.jpg        | Bin
 dal/{dal => }/static/datacenterlight/img/home.png   | Bin
 dal/{dal => }/static/datacenterlight/img/how.png    | Bin
 dal/{dal => }/static/datacenterlight/img/how1.png   | Bin
 dal/{dal => }/static/datacenterlight/img/how2.png   | Bin
 dal/{dal => }/static/datacenterlight/img/how3.png   | Bin
 dal/{dal => }/static/datacenterlight/img/how4.png   | Bin
 .../static/datacenterlight/img/intro-bg.jpg         | Bin
 dal/{dal => }/static/datacenterlight/img/ipad.png   | Bin
 .../static/datacenterlight/img/loading.gif          | Bin
 .../static/datacenterlight/img/logo_black.png       | Bin
 .../static/datacenterlight/img/logo_black.svg       |   0
 .../static/datacenterlight/img/logo_white.svg       |   0
 .../static/datacenterlight/img/opennebula.png       | Bin
 .../static/datacenterlight/img/pattern.jpg          | Bin
 dal/{dal => }/static/datacenterlight/img/phones.png | Bin
 .../static/datacenterlight/img/presidentialroom.jpg | Bin
 .../static/datacenterlight/img/prometheus.png       | Bin
 .../static/datacenterlight/img/python-logo.png      | Bin
 dal/{dal => }/static/datacenterlight/img/ssd.jpg    | Bin
 .../static/datacenterlight/img/standardroom.jpg     | Bin
 dal/{dal => }/static/datacenterlight/img/tayga.png  | Bin
 dal/{dal => }/static/datacenterlight/img/ubuntu.png | Bin
 .../datacenterlight/js/bootstrap-3.3.7.min.js       |   0
 dal/{dal => }/static/datacenterlight/js/form.js     |   0
 .../static/datacenterlight/js/jquery-2.2.4.min.js   |   0
 dal/{dal => }/static/datacenterlight/js/main.js     |   0
 dal/{dal => }/static/hosting/card-django.png        | Bin
 dal/{dal => }/static/hosting/card-nodejs.png        | Bin
 dal/{dal => }/static/hosting/card-rails.png         | Bin
 dal/{dal => }/static/hosting/css/commons.css        |   0
 dal/{dal => }/static/hosting/css/dashboard.css      |   0
 dal/{dal => }/static/hosting/css/landing-page.css   |   0
 dal/{dal => }/static/hosting/css/nodejshosting.css  |   0
 dal/{dal => }/static/hosting/css/order.css          |   0
 dal/{dal => }/static/hosting/css/orders.css         |   0
 dal/{dal => }/static/hosting/css/payment.css        |   0
 .../static/hosting/css/price_calculator.css         |   0
 dal/{dal => }/static/hosting/css/pricing.css        |   0
 dal/{dal => }/static/hosting/css/user_keys.css      |   0
 .../static/hosting/css/virtual-machine.css          |   0
 dal/{dal => }/static/hosting/django-intro-bg.png    | Bin
 .../static/hosting/img/24-hours-support.svg         |   0
 dal/{dal => }/static/hosting/img/CH_flag.png        | Bin
 dal/{dal => }/static/hosting/img/DE_flag.png        | Bin
 dal/{dal => }/static/hosting/img/ajax-loader.gif    | Bin
 dal/{dal => }/static/hosting/img/auth-bg-sm.jpg     | Bin
 dal/{dal => }/static/hosting/img/auth-bg.jpg        | Bin
 dal/{dal => }/static/hosting/img/banner-bg copy.jpg | Bin
 dal/{dal => }/static/hosting/img/banner-bg.jpg      | Bin
 dal/{dal => }/static/hosting/img/billing.svg        |   0
 dal/{dal => }/static/hosting/img/card-django.png    | Bin
 dal/{dal => }/static/hosting/img/card-nodejs.png    | Bin
 dal/{dal => }/static/hosting/img/card-rails.png     | Bin
 dal/{dal => }/static/hosting/img/checkmark.png      | Bin
 dal/{dal => }/static/hosting/img/configure.jpg      | Bin
 dal/{dal => }/static/hosting/img/connected.svg      |   0
 dal/{dal => }/static/hosting/img/copy.svg           |   0
 .../static/hosting/img/dashboard_settings.svg       |   0
 dal/{dal => }/static/hosting/img/delete.svg         |   0
 dal/{dal => }/static/hosting/img/deluxeroom.jpg     | Bin
 .../static/hosting/img/django-intro-bg.png          | Bin
 dal/{dal => }/static/hosting/img/dog.png            | Bin
 dal/{dal => }/static/hosting/img/economy.jpg        | Bin
 dal/{dal => }/static/hosting/img/favicon.ico        | Bin
 dal/{dal => }/static/hosting/img/g222.png           | Bin
 dal/{dal => }/static/hosting/img/header-bg.jpg      | Bin
 dal/{dal => }/static/hosting/img/home.png           | Bin
 dal/{dal => }/static/hosting/img/how.png            | Bin
 dal/{dal => }/static/hosting/img/how1.png           | Bin
 dal/{dal => }/static/hosting/img/how2.png           | Bin
 dal/{dal => }/static/hosting/img/how4.png           | Bin
 dal/{dal => }/static/hosting/img/icon-pdf.svg       |   0
 dal/{dal => }/static/hosting/img/icon-print.svg     |   0
 dal/{dal => }/static/hosting/img/intro-bg.jpg       | Bin
 dal/{dal => }/static/hosting/img/ipad.png           | Bin
 dal/{dal => }/static/hosting/img/key.svg            |   0
 dal/{dal => }/static/hosting/img/login-bg.jpg       | Bin
 dal/{dal => }/static/hosting/img/logo_black.png     | Bin
 dal/{dal => }/static/hosting/img/logo_black.svg     |   0
 dal/{dal => }/static/hosting/img/logo_white.svg     |   0
 .../static/hosting/img/nodejs-intro-bg.png          | Bin
 dal/{dal => }/static/hosting/img/pattern.jpg        | Bin
 .../static/hosting/img/pattern_original.jpg         | Bin
 dal/{dal => }/static/hosting/img/phones.png         | Bin
 dal/{dal => }/static/hosting/img/plusVM.svg         |   0
 .../static/hosting/img/presidentialroom.jpg         | Bin
 dal/{dal => }/static/hosting/img/rails-intro-bg.png | Bin
 dal/{dal => }/static/hosting/img/settings.svg       |   0
 dal/{dal => }/static/hosting/img/shopping-cart.svg  |   0
 dal/{dal => }/static/hosting/img/signup-bg.png      | Bin
 dal/{dal => }/static/hosting/img/standardroom.jpg   | Bin
 dal/{dal => }/static/hosting/img/ubuntu.png         | Bin
 dal/{dal => }/static/hosting/img/vm.svg             |   0
 dal/{dal => }/static/hosting/js/createvm.js         |   0
 dal/{dal => }/static/hosting/js/gen-ssh-key.js      |   0
 dal/{dal => }/static/hosting/js/html2canvas.min.js  |   0
 dal/{dal => }/static/hosting/js/html2pdf.min.js     |   0
 dal/{dal => }/static/hosting/js/initial.js          |   0
 dal/{dal => }/static/hosting/js/order.js            |   0
 dal/{dal => }/static/hosting/js/payment.js          |   0
 dal/{dal => }/static/hosting/js/pricing.js          |   0
 .../static/hosting/js/virtual_machine_detail.js     |   0
 dal/{dal => }/static/hosting/nodejs-intro-bg.png    | Bin
 dal/{dal => }/static/hosting/rails-intro-bg.png     | Bin
 dal/{dal => }/templates/base.html                   |   0
 dal/{dal => }/templates/base_short.html             |   0
 dal/{dal => }/templates/changeddata.html            |   0
 dal/{dal => }/templates/changedpassword.html        |   0
 dal/{dal => }/templates/changepassword.html         |   0
 dal/{dal => }/templates/changeuserdata.html         |   0
 dal/{dal => }/templates/deleteaccount.html          |   0
 dal/{dal => }/templates/deleteduser.html            |   0
 dal/{dal => }/templates/error.html                  |   0
 dal/{dal => }/templates/hosting_login.html          |   0
 dal/{dal => }/templates/includes/_card_input.html   |   0
 dal/{dal => }/templates/includes/_contact.html      |   0
 dal/{dal => }/templates/includes/_footer.html       |   0
 dal/{dal => }/templates/includes/_header.html       |   0
 dal/{dal => }/templates/includes/_messages.html     |   0
 dal/{dal => }/templates/includes/_navbar.html       |   0
 .../templates/includes/_navbar_transparent.html     |   0
 dal/{dal => }/templates/includes/_navbar_user.html  |   0
 .../templates/includes/_our_infrastructure.html     |   0
 dal/{dal => }/templates/includes/_pricing.html      |   0
 .../templates/includes/_your_infrastructure.html    |   0
 dal/{dal => }/templates/landing.html                |   0
 dal/{dal => }/templates/loginfailed.html            |   0
 dal/{dal => }/templates/mustbeloggedin.html         |   0
 dal/{dal => }/templates/registeruser.html           |   0
 dal/{dal => }/templates/resetpassword.html          |   0
 dal/{dal => }/templates/resetpasswordnew.html       |   0
 dal/{dal => }/templates/send_resetrequest.html      |   0
 dal/{dal => }/templates/usercreated.html            |   0
 dal/{dal => }/templates/useroptions.html            |   0
 dal/{dal => }/urls.py                               |   0
 dal/{dal => }/views.py                              |   0
 dal/{dal => }/wsgi.py                               |   0
 dal/manage.py => manage.py                          |   0
 223 files changed, 7 insertions(+), 7 deletions(-)
 rename dal/{dal => }/__init__.py (100%)
 delete mode 100644 dal/dal/static/datacenterlight/font-awesome/css/font-awesome.min.css
 rename dal/{dal => }/env.sample (100%)
 rename dal/{dal => }/models.py (100%)
 rename dal/{dal => }/settings.py (95%)
 rename dal/{dal => }/static/datacenterlight/css/bootstrap-3.3.7.min.css (100%)
 rename dal/{dal => }/static/datacenterlight/css/cms.css (100%)
 rename dal/{dal => }/static/datacenterlight/css/common.css (100%)
 rename dal/{dal => }/static/datacenterlight/css/header-slider.css (100%)
 rename dal/{dal => }/static/datacenterlight/css/hosting.css (100%)
 rename dal/{dal => }/static/datacenterlight/css/landing-page.css (100%)
 create mode 100644 dal/static/datacenterlight/font-awesome/css/font-awesome.min.css
 rename dal/{dal => }/static/datacenterlight/font-awesome/fonts/FontAwesome.otf (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.eot (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.svg (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.ttf (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.woff (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.woff2 (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/less/bordered-pulled.less (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/less/core.less (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/less/fixed-width.less (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/less/font-awesome.less (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/less/icons.less (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/less/larger.less (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/less/list.less (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/less/mixins.less (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/less/path.less (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/less/rotated-flipped.less (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/less/spinning.less (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/less/stacked.less (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/less/variables.less (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_bordered-pulled.scss (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_core.scss (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_fixed-width.scss (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_icons.scss (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_larger.scss (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_list.scss (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_mixins.scss (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_path.scss (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_rotated-flipped.scss (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_spinning.scss (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_stacked.scss (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_variables.scss (100%)
 rename dal/{dal => }/static/datacenterlight/font-awesome/scss/font-awesome.scss (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-Black.ttf (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-BlackItalic.ttf (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-Bold.ttf (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-BoldItalic.ttf (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraBold.ttf (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraBoldItalic.ttf (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraLight.ttf (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraLightItalic.ttf (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-Italic.ttf (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-Light.ttf (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-LightItalic.ttf (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-Medium.ttf (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-MediumItalic.ttf (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-Regular.ttf (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-SemiBold.ttf (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-SemiBoldItalic.ttf (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-Thin.ttf (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-ThinItalic.ttf (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/OFL.txt (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/glyphicons-halflings-regular.eot (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/glyphicons-halflings-regular.svg (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/glyphicons-halflings-regular.ttf (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/glyphicons-halflings-regular.woff (100%)
 rename dal/{dal => }/static/datacenterlight/fonts/glyphicons-halflings-regular.woff2 (100%)
 rename dal/{dal => }/static/datacenterlight/img/Ceph_Logo.png (100%)
 rename dal/{dal => }/static/datacenterlight/img/banner-bg copy.jpg (100%)
 rename dal/{dal => }/static/datacenterlight/img/banner-bg.jpg (100%)
 rename dal/{dal => }/static/datacenterlight/img/bg.png (100%)
 rename dal/{dal => }/static/datacenterlight/img/cdistbyungleich.png (100%)
 rename dal/{dal => }/static/datacenterlight/img/checkmark.png (100%)
 rename dal/{dal => }/static/datacenterlight/img/configure.jpg (100%)
 rename dal/{dal => }/static/datacenterlight/img/datacenterlight.png (100%)
 rename dal/{dal => }/static/datacenterlight/img/dcl-email-bg.jpg (100%)
 rename dal/{dal => }/static/datacenterlight/img/deluxeroom.jpg (100%)
 rename dal/{dal => }/static/datacenterlight/img/devuan.png (100%)
 rename dal/{dal => }/static/datacenterlight/img/django.png (100%)
 rename dal/{dal => }/static/datacenterlight/img/dog.png (100%)
 rename dal/{dal => }/static/datacenterlight/img/economy.jpg (100%)
 rename dal/{dal => }/static/datacenterlight/img/facebook_logo.svg (100%)
 rename dal/{dal => }/static/datacenterlight/img/favicon.ico (100%)
 rename dal/{dal => }/static/datacenterlight/img/header-bg.jpg (100%)
 rename dal/{dal => }/static/datacenterlight/img/home.png (100%)
 rename dal/{dal => }/static/datacenterlight/img/how.png (100%)
 rename dal/{dal => }/static/datacenterlight/img/how1.png (100%)
 rename dal/{dal => }/static/datacenterlight/img/how2.png (100%)
 rename dal/{dal => }/static/datacenterlight/img/how3.png (100%)
 rename dal/{dal => }/static/datacenterlight/img/how4.png (100%)
 rename dal/{dal => }/static/datacenterlight/img/intro-bg.jpg (100%)
 rename dal/{dal => }/static/datacenterlight/img/ipad.png (100%)
 rename dal/{dal => }/static/datacenterlight/img/loading.gif (100%)
 rename dal/{dal => }/static/datacenterlight/img/logo_black.png (100%)
 rename dal/{dal => }/static/datacenterlight/img/logo_black.svg (100%)
 rename dal/{dal => }/static/datacenterlight/img/logo_white.svg (100%)
 rename dal/{dal => }/static/datacenterlight/img/opennebula.png (100%)
 rename dal/{dal => }/static/datacenterlight/img/pattern.jpg (100%)
 rename dal/{dal => }/static/datacenterlight/img/phones.png (100%)
 rename dal/{dal => }/static/datacenterlight/img/presidentialroom.jpg (100%)
 rename dal/{dal => }/static/datacenterlight/img/prometheus.png (100%)
 rename dal/{dal => }/static/datacenterlight/img/python-logo.png (100%)
 rename dal/{dal => }/static/datacenterlight/img/ssd.jpg (100%)
 rename dal/{dal => }/static/datacenterlight/img/standardroom.jpg (100%)
 rename dal/{dal => }/static/datacenterlight/img/tayga.png (100%)
 rename dal/{dal => }/static/datacenterlight/img/ubuntu.png (100%)
 rename dal/{dal => }/static/datacenterlight/js/bootstrap-3.3.7.min.js (100%)
 rename dal/{dal => }/static/datacenterlight/js/form.js (100%)
 rename dal/{dal => }/static/datacenterlight/js/jquery-2.2.4.min.js (100%)
 rename dal/{dal => }/static/datacenterlight/js/main.js (100%)
 rename dal/{dal => }/static/hosting/card-django.png (100%)
 rename dal/{dal => }/static/hosting/card-nodejs.png (100%)
 rename dal/{dal => }/static/hosting/card-rails.png (100%)
 rename dal/{dal => }/static/hosting/css/commons.css (100%)
 rename dal/{dal => }/static/hosting/css/dashboard.css (100%)
 rename dal/{dal => }/static/hosting/css/landing-page.css (100%)
 rename dal/{dal => }/static/hosting/css/nodejshosting.css (100%)
 rename dal/{dal => }/static/hosting/css/order.css (100%)
 rename dal/{dal => }/static/hosting/css/orders.css (100%)
 rename dal/{dal => }/static/hosting/css/payment.css (100%)
 rename dal/{dal => }/static/hosting/css/price_calculator.css (100%)
 rename dal/{dal => }/static/hosting/css/pricing.css (100%)
 rename dal/{dal => }/static/hosting/css/user_keys.css (100%)
 rename dal/{dal => }/static/hosting/css/virtual-machine.css (100%)
 rename dal/{dal => }/static/hosting/django-intro-bg.png (100%)
 rename dal/{dal => }/static/hosting/img/24-hours-support.svg (100%)
 rename dal/{dal => }/static/hosting/img/CH_flag.png (100%)
 rename dal/{dal => }/static/hosting/img/DE_flag.png (100%)
 rename dal/{dal => }/static/hosting/img/ajax-loader.gif (100%)
 rename dal/{dal => }/static/hosting/img/auth-bg-sm.jpg (100%)
 rename dal/{dal => }/static/hosting/img/auth-bg.jpg (100%)
 rename dal/{dal => }/static/hosting/img/banner-bg copy.jpg (100%)
 rename dal/{dal => }/static/hosting/img/banner-bg.jpg (100%)
 rename dal/{dal => }/static/hosting/img/billing.svg (100%)
 rename dal/{dal => }/static/hosting/img/card-django.png (100%)
 rename dal/{dal => }/static/hosting/img/card-nodejs.png (100%)
 rename dal/{dal => }/static/hosting/img/card-rails.png (100%)
 rename dal/{dal => }/static/hosting/img/checkmark.png (100%)
 rename dal/{dal => }/static/hosting/img/configure.jpg (100%)
 rename dal/{dal => }/static/hosting/img/connected.svg (100%)
 rename dal/{dal => }/static/hosting/img/copy.svg (100%)
 rename dal/{dal => }/static/hosting/img/dashboard_settings.svg (100%)
 rename dal/{dal => }/static/hosting/img/delete.svg (100%)
 rename dal/{dal => }/static/hosting/img/deluxeroom.jpg (100%)
 rename dal/{dal => }/static/hosting/img/django-intro-bg.png (100%)
 rename dal/{dal => }/static/hosting/img/dog.png (100%)
 rename dal/{dal => }/static/hosting/img/economy.jpg (100%)
 rename dal/{dal => }/static/hosting/img/favicon.ico (100%)
 rename dal/{dal => }/static/hosting/img/g222.png (100%)
 rename dal/{dal => }/static/hosting/img/header-bg.jpg (100%)
 rename dal/{dal => }/static/hosting/img/home.png (100%)
 rename dal/{dal => }/static/hosting/img/how.png (100%)
 rename dal/{dal => }/static/hosting/img/how1.png (100%)
 rename dal/{dal => }/static/hosting/img/how2.png (100%)
 rename dal/{dal => }/static/hosting/img/how4.png (100%)
 rename dal/{dal => }/static/hosting/img/icon-pdf.svg (100%)
 rename dal/{dal => }/static/hosting/img/icon-print.svg (100%)
 rename dal/{dal => }/static/hosting/img/intro-bg.jpg (100%)
 rename dal/{dal => }/static/hosting/img/ipad.png (100%)
 rename dal/{dal => }/static/hosting/img/key.svg (100%)
 rename dal/{dal => }/static/hosting/img/login-bg.jpg (100%)
 rename dal/{dal => }/static/hosting/img/logo_black.png (100%)
 rename dal/{dal => }/static/hosting/img/logo_black.svg (100%)
 rename dal/{dal => }/static/hosting/img/logo_white.svg (100%)
 rename dal/{dal => }/static/hosting/img/nodejs-intro-bg.png (100%)
 rename dal/{dal => }/static/hosting/img/pattern.jpg (100%)
 rename dal/{dal => }/static/hosting/img/pattern_original.jpg (100%)
 rename dal/{dal => }/static/hosting/img/phones.png (100%)
 rename dal/{dal => }/static/hosting/img/plusVM.svg (100%)
 rename dal/{dal => }/static/hosting/img/presidentialroom.jpg (100%)
 rename dal/{dal => }/static/hosting/img/rails-intro-bg.png (100%)
 rename dal/{dal => }/static/hosting/img/settings.svg (100%)
 rename dal/{dal => }/static/hosting/img/shopping-cart.svg (100%)
 rename dal/{dal => }/static/hosting/img/signup-bg.png (100%)
 rename dal/{dal => }/static/hosting/img/standardroom.jpg (100%)
 rename dal/{dal => }/static/hosting/img/ubuntu.png (100%)
 rename dal/{dal => }/static/hosting/img/vm.svg (100%)
 rename dal/{dal => }/static/hosting/js/createvm.js (100%)
 rename dal/{dal => }/static/hosting/js/gen-ssh-key.js (100%)
 rename dal/{dal => }/static/hosting/js/html2canvas.min.js (100%)
 rename dal/{dal => }/static/hosting/js/html2pdf.min.js (100%)
 rename dal/{dal => }/static/hosting/js/initial.js (100%)
 rename dal/{dal => }/static/hosting/js/order.js (100%)
 rename dal/{dal => }/static/hosting/js/payment.js (100%)
 rename dal/{dal => }/static/hosting/js/pricing.js (100%)
 rename dal/{dal => }/static/hosting/js/virtual_machine_detail.js (100%)
 rename dal/{dal => }/static/hosting/nodejs-intro-bg.png (100%)
 rename dal/{dal => }/static/hosting/rails-intro-bg.png (100%)
 rename dal/{dal => }/templates/base.html (100%)
 rename dal/{dal => }/templates/base_short.html (100%)
 rename dal/{dal => }/templates/changeddata.html (100%)
 rename dal/{dal => }/templates/changedpassword.html (100%)
 rename dal/{dal => }/templates/changepassword.html (100%)
 rename dal/{dal => }/templates/changeuserdata.html (100%)
 rename dal/{dal => }/templates/deleteaccount.html (100%)
 rename dal/{dal => }/templates/deleteduser.html (100%)
 rename dal/{dal => }/templates/error.html (100%)
 rename dal/{dal => }/templates/hosting_login.html (100%)
 rename dal/{dal => }/templates/includes/_card_input.html (100%)
 rename dal/{dal => }/templates/includes/_contact.html (100%)
 rename dal/{dal => }/templates/includes/_footer.html (100%)
 rename dal/{dal => }/templates/includes/_header.html (100%)
 rename dal/{dal => }/templates/includes/_messages.html (100%)
 rename dal/{dal => }/templates/includes/_navbar.html (100%)
 rename dal/{dal => }/templates/includes/_navbar_transparent.html (100%)
 rename dal/{dal => }/templates/includes/_navbar_user.html (100%)
 rename dal/{dal => }/templates/includes/_our_infrastructure.html (100%)
 rename dal/{dal => }/templates/includes/_pricing.html (100%)
 rename dal/{dal => }/templates/includes/_your_infrastructure.html (100%)
 rename dal/{dal => }/templates/landing.html (100%)
 rename dal/{dal => }/templates/loginfailed.html (100%)
 rename dal/{dal => }/templates/mustbeloggedin.html (100%)
 rename dal/{dal => }/templates/registeruser.html (100%)
 rename dal/{dal => }/templates/resetpassword.html (100%)
 rename dal/{dal => }/templates/resetpasswordnew.html (100%)
 rename dal/{dal => }/templates/send_resetrequest.html (100%)
 rename dal/{dal => }/templates/usercreated.html (100%)
 rename dal/{dal => }/templates/useroptions.html (100%)
 rename dal/{dal => }/urls.py (100%)
 rename dal/{dal => }/views.py (100%)
 rename dal/{dal => }/wsgi.py (100%)
 rename dal/manage.py => manage.py (100%)

diff --git a/dal/dal/__init__.py b/dal/__init__.py
similarity index 100%
rename from dal/dal/__init__.py
rename to dal/__init__.py
diff --git a/dal/dal/static/datacenterlight/font-awesome/css/font-awesome.min.css b/dal/dal/static/datacenterlight/font-awesome/css/font-awesome.min.css
deleted file mode 100644
index 540440c..0000000
--- a/dal/dal/static/datacenterlight/font-awesome/css/font-awesome.min.css
+++ /dev/null
@@ -1,4 +0,0 @@
-/*!
- *  Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
- *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
- */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}
diff --git a/dal/dal/env.sample b/dal/env.sample
similarity index 100%
rename from dal/dal/env.sample
rename to dal/env.sample
diff --git a/dal/dal/models.py b/dal/models.py
similarity index 100%
rename from dal/dal/models.py
rename to dal/models.py
diff --git a/dal/dal/settings.py b/dal/settings.py
similarity index 95%
rename from dal/dal/settings.py
rename to dal/settings.py
index a284663..7c30a2a 100644
--- a/dal/dal/settings.py
+++ b/dal/settings.py
@@ -120,7 +120,7 @@ STATIC_URL = '/static/'
 
 ############################# To be fixed
 
-STATIC_ROOT = os.path.dirname('/home/downhill/ungleich/vuejsuserservice/dal/dal/static/')
+STATIC_ROOT= os.path.join(BASE_DIR, 'static/')
 
 # Database
 # https://docs.djangoproject.com/en/1.10/ref/settings/#databases
@@ -131,7 +131,7 @@ DATABASES = {
         'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
     }
 }
-SECRET_KEY = 'rn=f&ecp#&#escxpk!0e%a$i3sbm$z@5+g4h9q+w7-83*f2f-i'
+SECRET_KEY = os.environ.get('SECRET_KEY')
 
 # SECURITY WARNING: don't run with debug turned on in production!
-DEBUG = True
+DEBUG = os.environ.get('DEBUG', False)
diff --git a/dal/dal/static/datacenterlight/css/bootstrap-3.3.7.min.css b/dal/static/datacenterlight/css/bootstrap-3.3.7.min.css
similarity index 100%
rename from dal/dal/static/datacenterlight/css/bootstrap-3.3.7.min.css
rename to dal/static/datacenterlight/css/bootstrap-3.3.7.min.css
diff --git a/dal/dal/static/datacenterlight/css/cms.css b/dal/static/datacenterlight/css/cms.css
similarity index 100%
rename from dal/dal/static/datacenterlight/css/cms.css
rename to dal/static/datacenterlight/css/cms.css
diff --git a/dal/dal/static/datacenterlight/css/common.css b/dal/static/datacenterlight/css/common.css
similarity index 100%
rename from dal/dal/static/datacenterlight/css/common.css
rename to dal/static/datacenterlight/css/common.css
diff --git a/dal/dal/static/datacenterlight/css/header-slider.css b/dal/static/datacenterlight/css/header-slider.css
similarity index 100%
rename from dal/dal/static/datacenterlight/css/header-slider.css
rename to dal/static/datacenterlight/css/header-slider.css
diff --git a/dal/dal/static/datacenterlight/css/hosting.css b/dal/static/datacenterlight/css/hosting.css
similarity index 100%
rename from dal/dal/static/datacenterlight/css/hosting.css
rename to dal/static/datacenterlight/css/hosting.css
diff --git a/dal/dal/static/datacenterlight/css/landing-page.css b/dal/static/datacenterlight/css/landing-page.css
similarity index 100%
rename from dal/dal/static/datacenterlight/css/landing-page.css
rename to dal/static/datacenterlight/css/landing-page.css
diff --git a/dal/static/datacenterlight/font-awesome/css/font-awesome.min.css b/dal/static/datacenterlight/font-awesome/css/font-awesome.min.css
new file mode 100644
index 0000000..248ea7a
--- /dev/null
+++ b/dal/static/datacenterlight/font-awesome/css/font-awesome.min.css
@@ -0,0 +1,4 @@
+/*!
+ *  Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
+ *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
+ */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}  .fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}  .fa-2x{font-size:2em}  .fa-3x{font-size:3em}  .fa-4x{font-size:4em}  .fa-5x{font-size:5em}  .fa-fw{width:1.28571429em;text-align:center}  .fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}  .fa-ul>li{position:relative}  .fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}  .fa-li.fa-lg{left:-1.85714286em}  .fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}  .fa-pull-left{float:left}  .fa-pull-right{float:right}  .fa.fa-pull-left{margin-right:.3em}  .fa.fa-pull-right{margin-left:.3em}  .pull-right{float:right}  .pull-left{float:left}  .fa.pull-left{margin-right:.3em}  .fa.pull-right{margin-left:.3em}  .fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}  .fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}  @-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}  @keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}  .fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}  .fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}  .fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}  .fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}  .fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}  :root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}  .fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}  .fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}  .fa-stack-1x{line-height:inherit}  .fa-stack-2x{font-size:2em}  .fa-inverse{color:#fff}  .fa-glass:before{content:"\f000"}  .fa-music:before{content:"\f001"}  .fa-search:before{content:"\f002"}  .fa-envelope-o:before{content:"\f003"}  .fa-heart:before{content:"\f004"}  .fa-star:before{content:"\f005"}  .fa-star-o:before{content:"\f006"}  .fa-user:before{content:"\f007"}  .fa-film:before{content:"\f008"}  .fa-th-large:before{content:"\f009"}  .fa-th:before{content:"\f00a"}  .fa-th-list:before{content:"\f00b"}  .fa-check:before{content:"\f00c"}  .fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}  .fa-search-plus:before{content:"\f00e"}  .fa-search-minus:before{content:"\f010"}  .fa-power-off:before{content:"\f011"}  .fa-signal:before{content:"\f012"}  .fa-gear:before,.fa-cog:before{content:"\f013"}  .fa-trash-o:before{content:"\f014"}  .fa-home:before{content:"\f015"}  .fa-file-o:before{content:"\f016"}  .fa-clock-o:before{content:"\f017"}  .fa-road:before{content:"\f018"}  .fa-download:before{content:"\f019"}  .fa-arrow-circle-o-down:before{content:"\f01a"}  .fa-arrow-circle-o-up:before{content:"\f01b"}  .fa-inbox:before{content:"\f01c"}  .fa-play-circle-o:before{content:"\f01d"}  .fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}  .fa-refresh:before{content:"\f021"}  .fa-list-alt:before{content:"\f022"}  .fa-lock:before{content:"\f023"}  .fa-flag:before{content:"\f024"}  .fa-headphones:before{content:"\f025"}  .fa-volume-off:before{content:"\f026"}  .fa-volume-down:before{content:"\f027"}  .fa-volume-up:before{content:"\f028"}  .fa-qrcode:before{content:"\f029"}  .fa-barcode:before{content:"\f02a"}  .fa-tag:before{content:"\f02b"}  .fa-tags:before{content:"\f02c"}  .fa-book:before{content:"\f02d"}  .fa-bookmark:before{content:"\f02e"}  .fa-print:before{content:"\f02f"}  .fa-camera:before{content:"\f030"}  .fa-font:before{content:"\f031"}  .fa-bold:before{content:"\f032"}  .fa-italic:before{content:"\f033"}  .fa-text-height:before{content:"\f034"}  .fa-text-width:before{content:"\f035"}  .fa-align-left:before{content:"\f036"}  .fa-align-center:before{content:"\f037"}  .fa-align-right:before{content:"\f038"}  .fa-align-justify:before{content:"\f039"}  .fa-list:before{content:"\f03a"}  .fa-dedent:before,.fa-outdent:before{content:"\f03b"}  .fa-indent:before{content:"\f03c"}  .fa-video-camera:before{content:"\f03d"}  .fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}  .fa-pencil:before{content:"\f040"}  .fa-map-marker:before{content:"\f041"}  .fa-adjust:before{content:"\f042"}  .fa-tint:before{content:"\f043"}  .fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}  .fa-share-square-o:before{content:"\f045"}  .fa-check-square-o:before{content:"\f046"}  .fa-arrows:before{content:"\f047"}  .fa-step-backward:before{content:"\f048"}  .fa-fast-backward:before{content:"\f049"}  .fa-backward:before{content:"\f04a"}  .fa-play:before{content:"\f04b"}  .fa-pause:before{content:"\f04c"}  .fa-stop:before{content:"\f04d"}  .fa-forward:before{content:"\f04e"}  .fa-fast-forward:before{content:"\f050"}  .fa-step-forward:before{content:"\f051"}  .fa-eject:before{content:"\f052"}  .fa-chevron-left:before{content:"\f053"}  .fa-chevron-right:before{content:"\f054"}  .fa-plus-circle:before{content:"\f055"}  .fa-minus-circle:before{content:"\f056"}  .fa-times-circle:before{content:"\f057"}  .fa-check-circle:before{content:"\f058"}  .fa-question-circle:before{content:"\f059"}  .fa-info-circle:before{content:"\f05a"}  .fa-crosshairs:before{content:"\f05b"}  .fa-times-circle-o:before{content:"\f05c"}  .fa-check-circle-o:before{content:"\f05d"}  .fa-ban:before{content:"\f05e"}  .fa-arrow-left:before{content:"\f060"}  .fa-arrow-right:before{content:"\f061"}  .fa-arrow-up:before{content:"\f062"}  .fa-arrow-down:before{content:"\f063"}  .fa-mail-forward:before,.fa-share:before{content:"\f064"}  .fa-expand:before{content:"\f065"}  .fa-compress:before{content:"\f066"}  .fa-plus:before{content:"\f067"}  .fa-minus:before{content:"\f068"}  .fa-asterisk:before{content:"\f069"}  .fa-exclamation-circle:before{content:"\f06a"}  .fa-gift:before{content:"\f06b"}  .fa-leaf:before{content:"\f06c"}  .fa-fire:before{content:"\f06d"}  .fa-eye:before{content:"\f06e"}  .fa-eye-slash:before{content:"\f070"}  .fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}  .fa-plane:before{content:"\f072"}  .fa-calendar:before{content:"\f073"}  .fa-random:before{content:"\f074"}  .fa-comment:before{content:"\f075"}  .fa-magnet:before{content:"\f076"}  .fa-chevron-up:before{content:"\f077"}  .fa-chevron-down:before{content:"\f078"}  .fa-retweet:before{content:"\f079"}  .fa-shopping-cart:before{content:"\f07a"}  .fa-folder:before{content:"\f07b"}  .fa-folder-open:before{content:"\f07c"}  .fa-arrows-v:before{content:"\f07d"}  .fa-arrows-h:before{content:"\f07e"}  .fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}  .fa-twitter-square:before{content:"\f081"}  .fa-facebook-square:before{content:"\f082"}  .fa-camera-retro:before{content:"\f083"}  .fa-key:before{content:"\f084"}  .fa-gears:before,.fa-cogs:before{content:"\f085"}  .fa-comments:before{content:"\f086"}  .fa-thumbs-o-up:before{content:"\f087"}  .fa-thumbs-o-down:before{content:"\f088"}  .fa-star-half:before{content:"\f089"}  .fa-heart-o:before{content:"\f08a"}  .fa-sign-out:before{content:"\f08b"}  .fa-linkedin-square:before{content:"\f08c"}  .fa-thumb-tack:before{content:"\f08d"}  .fa-external-link:before{content:"\f08e"}  .fa-sign-in:before{content:"\f090"}  .fa-trophy:before{content:"\f091"}  .fa-github-square:before{content:"\f092"}  .fa-upload:before{content:"\f093"}  .fa-lemon-o:before{content:"\f094"}  .fa-phone:before{content:"\f095"}  .fa-square-o:before{content:"\f096"}  .fa-bookmark-o:before{content:"\f097"}  .fa-phone-square:before{content:"\f098"}  .fa-twitter:before{content:"\f099"}  .fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}  .fa-github:before{content:"\f09b"}  .fa-unlock:before{content:"\f09c"}  .fa-credit-card:before{content:"\f09d"}  .fa-feed:before,.fa-rss:before{content:"\f09e"}  .fa-hdd-o:before{content:"\f0a0"}  .fa-bullhorn:before{content:"\f0a1"}  .fa-bell:before{content:"\f0f3"}  .fa-certificate:before{content:"\f0a3"}  .fa-hand-o-right:before{content:"\f0a4"}  .fa-hand-o-left:before{content:"\f0a5"}  .fa-hand-o-up:before{content:"\f0a6"}  .fa-hand-o-down:before{content:"\f0a7"}  .fa-arrow-circle-left:before{content:"\f0a8"}  .fa-arrow-circle-right:before{content:"\f0a9"}  .fa-arrow-circle-up:before{content:"\f0aa"}  .fa-arrow-circle-down:before{content:"\f0ab"}  .fa-globe:before{content:"\f0ac"}  .fa-wrench:before{content:"\f0ad"}  .fa-tasks:before{content:"\f0ae"}  .fa-filter:before{content:"\f0b0"}  .fa-briefcase:before{content:"\f0b1"}  .fa-arrows-alt:before{content:"\f0b2"}  .fa-group:before,.fa-users:before{content:"\f0c0"}  .fa-chain:before,.fa-link:before{content:"\f0c1"}  .fa-cloud:before{content:"\f0c2"}  .fa-flask:before{content:"\f0c3"}  .fa-cut:before,.fa-scissors:before{content:"\f0c4"}  .fa-copy:before,.fa-files-o:before{content:"\f0c5"}  .fa-paperclip:before{content:"\f0c6"}  .fa-save:before,.fa-floppy-o:before{content:"\f0c7"}  .fa-square:before{content:"\f0c8"}  .fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}  .fa-list-ul:before{content:"\f0ca"}  .fa-list-ol:before{content:"\f0cb"}  .fa-strikethrough:before{content:"\f0cc"}  .fa-underline:before{content:"\f0cd"}  .fa-table:before{content:"\f0ce"}  .fa-magic:before{content:"\f0d0"}  .fa-truck:before{content:"\f0d1"}  .fa-pinterest:before{content:"\f0d2"}  .fa-pinterest-square:before{content:"\f0d3"}  .fa-google-plus-square:before{content:"\f0d4"}  .fa-google-plus:before{content:"\f0d5"}  .fa-money:before{content:"\f0d6"}  .fa-caret-down:before{content:"\f0d7"}  .fa-caret-up:before{content:"\f0d8"}  .fa-caret-left:before{content:"\f0d9"}  .fa-caret-right:before{content:"\f0da"}  .fa-columns:before{content:"\f0db"}  .fa-unsorted:before,.fa-sort:before{content:"\f0dc"}  .fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}  .fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}  .fa-envelope:before{content:"\f0e0"}  .fa-linkedin:before{content:"\f0e1"}  .fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}  .fa-legal:before,.fa-gavel:before{content:"\f0e3"}  .fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}  .fa-comment-o:before{content:"\f0e5"}  .fa-comments-o:before{content:"\f0e6"}  .fa-flash:before,.fa-bolt:before{content:"\f0e7"}  .fa-sitemap:before{content:"\f0e8"}  .fa-umbrella:before{content:"\f0e9"}  .fa-paste:before,.fa-clipboard:before{content:"\f0ea"}  .fa-lightbulb-o:before{content:"\f0eb"}  .fa-exchange:before{content:"\f0ec"}  .fa-cloud-download:before{content:"\f0ed"}  .fa-cloud-upload:before{content:"\f0ee"}  .fa-user-md:before{content:"\f0f0"}  .fa-stethoscope:before{content:"\f0f1"}  .fa-suitcase:before{content:"\f0f2"}  .fa-bell-o:before{content:"\f0a2"}  .fa-coffee:before{content:"\f0f4"}  .fa-cutlery:before{content:"\f0f5"}  .fa-file-text-o:before{content:"\f0f6"}  .fa-building-o:before{content:"\f0f7"}  .fa-hospital-o:before{content:"\f0f8"}  .fa-ambulance:before{content:"\f0f9"}  .fa-medkit:before{content:"\f0fa"}  .fa-fighter-jet:before{content:"\f0fb"}  .fa-beer:before{content:"\f0fc"}  .fa-h-square:before{content:"\f0fd"}  .fa-plus-square:before{content:"\f0fe"}  .fa-angle-double-left:before{content:"\f100"}  .fa-angle-double-right:before{content:"\f101"}  .fa-angle-double-up:before{content:"\f102"}  .fa-angle-double-down:before{content:"\f103"}  .fa-angle-left:before{content:"\f104"}  .fa-angle-right:before{content:"\f105"}  .fa-angle-up:before{content:"\f106"}  .fa-angle-down:before{content:"\f107"}  .fa-desktop:before{content:"\f108"}  .fa-laptop:before{content:"\f109"}  .fa-tablet:before{content:"\f10a"}  .fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}  .fa-circle-o:before{content:"\f10c"}  .fa-quote-left:before{content:"\f10d"}  .fa-quote-right:before{content:"\f10e"}  .fa-spinner:before{content:"\f110"}  .fa-circle:before{content:"\f111"}  .fa-mail-reply:before,.fa-reply:before{content:"\f112"}  .fa-github-alt:before{content:"\f113"}  .fa-folder-o:before{content:"\f114"}  .fa-folder-open-o:before{content:"\f115"}  .fa-smile-o:before{content:"\f118"}  .fa-frown-o:before{content:"\f119"}  .fa-meh-o:before{content:"\f11a"}  .fa-gamepad:before{content:"\f11b"}  .fa-keyboard-o:before{content:"\f11c"}  .fa-flag-o:before{content:"\f11d"}  .fa-flag-checkered:before{content:"\f11e"}  .fa-terminal:before{content:"\f120"}  .fa-code:before{content:"\f121"}  .fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}  .fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}  .fa-location-arrow:before{content:"\f124"}  .fa-crop:before{content:"\f125"}  .fa-code-fork:before{content:"\f126"}  .fa-unlink:before,.fa-chain-broken:before{content:"\f127"}  .fa-question:before{content:"\f128"}  .fa-info:before{content:"\f129"}  .fa-exclamation:before{content:"\f12a"}  .fa-superscript:before{content:"\f12b"}  .fa-subscript:before{content:"\f12c"}  .fa-eraser:before{content:"\f12d"}  .fa-puzzle-piece:before{content:"\f12e"}  .fa-microphone:before{content:"\f130"}  .fa-microphone-slash:before{content:"\f131"}  .fa-shield:before{content:"\f132"}  .fa-calendar-o:before{content:"\f133"}  .fa-fire-extinguisher:before{content:"\f134"}  .fa-rocket:before{content:"\f135"}  .fa-maxcdn:before{content:"\f136"}  .fa-chevron-circle-left:before{content:"\f137"}  .fa-chevron-circle-right:before{content:"\f138"}  .fa-chevron-circle-up:before{content:"\f139"}  .fa-chevron-circle-down:before{content:"\f13a"}  .fa-html5:before{content:"\f13b"}  .fa-css3:before{content:"\f13c"}  .fa-anchor:before{content:"\f13d"}  .fa-unlock-alt:before{content:"\f13e"}  .fa-bullseye:before{content:"\f140"}  .fa-ellipsis-h:before{content:"\f141"}  .fa-ellipsis-v:before{content:"\f142"}  .fa-rss-square:before{content:"\f143"}  .fa-play-circle:before{content:"\f144"}  .fa-ticket:before{content:"\f145"}  .fa-minus-square:before{content:"\f146"}  .fa-minus-square-o:before{content:"\f147"}  .fa-level-up:before{content:"\f148"}  .fa-level-down:before{content:"\f149"}  .fa-check-square:before{content:"\f14a"}  .fa-pencil-square:before{content:"\f14b"}  .fa-external-link-square:before{content:"\f14c"}  .fa-share-square:before{content:"\f14d"}  .fa-compass:before{content:"\f14e"}  .fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}  .fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}  .fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}  .fa-euro:before,.fa-eur:before{content:"\f153"}  .fa-gbp:before{content:"\f154"}  .fa-dollar:before,.fa-usd:before{content:"\f155"}  .fa-rupee:before,.fa-inr:before{content:"\f156"}  .fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}  .fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}  .fa-won:before,.fa-krw:before{content:"\f159"}  .fa-bitcoin:before,.fa-btc:before{content:"\f15a"}  .fa-file:before{content:"\f15b"}  .fa-file-text:before{content:"\f15c"}  .fa-sort-alpha-asc:before{content:"\f15d"}  .fa-sort-alpha-desc:before{content:"\f15e"}  .fa-sort-amount-asc:before{content:"\f160"}  .fa-sort-amount-desc:before{content:"\f161"}  .fa-sort-numeric-asc:before{content:"\f162"}  .fa-sort-numeric-desc:before{content:"\f163"}  .fa-thumbs-up:before{content:"\f164"}  .fa-thumbs-down:before{content:"\f165"}  .fa-youtube-square:before{content:"\f166"}  .fa-youtube:before{content:"\f167"}  .fa-xing:before{content:"\f168"}  .fa-xing-square:before{content:"\f169"}  .fa-youtube-play:before{content:"\f16a"}  .fa-dropbox:before{content:"\f16b"}  .fa-stack-overflow:before{content:"\f16c"}  .fa-instagram:before{content:"\f16d"}  .fa-flickr:before{content:"\f16e"}  .fa-adn:before{content:"\f170"}  .fa-bitbucket:before{content:"\f171"}  .fa-bitbucket-square:before{content:"\f172"}  .fa-tumblr:before{content:"\f173"}  .fa-tumblr-square:before{content:"\f174"}  .fa-long-arrow-down:before{content:"\f175"}  .fa-long-arrow-up:before{content:"\f176"}  .fa-long-arrow-left:before{content:"\f177"}  .fa-long-arrow-right:before{content:"\f178"}  .fa-apple:before{content:"\f179"}  .fa-windows:before{content:"\f17a"}  .fa-android:before{content:"\f17b"}  .fa-linux:before{content:"\f17c"}  .fa-dribbble:before{content:"\f17d"}  .fa-skype:before{content:"\f17e"}  .fa-foursquare:before{content:"\f180"}  .fa-trello:before{content:"\f181"}  .fa-female:before{content:"\f182"}  .fa-male:before{content:"\f183"}  .fa-gittip:before,.fa-gratipay:before{content:"\f184"}  .fa-sun-o:before{content:"\f185"}  .fa-moon-o:before{content:"\f186"}  .fa-archive:before{content:"\f187"}  .fa-bug:before{content:"\f188"}  .fa-vk:before{content:"\f189"}  .fa-weibo:before{content:"\f18a"}  .fa-renren:before{content:"\f18b"}  .fa-pagelines:before{content:"\f18c"}  .fa-stack-exchange:before{content:"\f18d"}  .fa-arrow-circle-o-right:before{content:"\f18e"}  .fa-arrow-circle-o-left:before{content:"\f190"}  .fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}  .fa-dot-circle-o:before{content:"\f192"}  .fa-wheelchair:before{content:"\f193"}  .fa-vimeo-square:before{content:"\f194"}  .fa-turkish-lira:before,.fa-try:before{content:"\f195"}  .fa-plus-square-o:before{content:"\f196"}  .fa-space-shuttle:before{content:"\f197"}  .fa-slack:before{content:"\f198"}  .fa-envelope-square:before{content:"\f199"}  .fa-wordpress:before{content:"\f19a"}  .fa-openid:before{content:"\f19b"}  .fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}  .fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}  .fa-yahoo:before{content:"\f19e"}  .fa-google:before{content:"\f1a0"}  .fa-reddit:before{content:"\f1a1"}  .fa-reddit-square:before{content:"\f1a2"}  .fa-stumbleupon-circle:before{content:"\f1a3"}  .fa-stumbleupon:before{content:"\f1a4"}  .fa-delicious:before{content:"\f1a5"}  .fa-digg:before{content:"\f1a6"}  .fa-pied-piper-pp:before{content:"\f1a7"}  .fa-pied-piper-alt:before{content:"\f1a8"}  .fa-drupal:before{content:"\f1a9"}  .fa-joomla:before{content:"\f1aa"}  .fa-language:before{content:"\f1ab"}  .fa-fax:before{content:"\f1ac"}  .fa-building:before{content:"\f1ad"}  .fa-child:before{content:"\f1ae"}  .fa-paw:before{content:"\f1b0"}  .fa-spoon:before{content:"\f1b1"}  .fa-cube:before{content:"\f1b2"}  .fa-cubes:before{content:"\f1b3"}  .fa-behance:before{content:"\f1b4"}  .fa-behance-square:before{content:"\f1b5"}  .fa-steam:before{content:"\f1b6"}  .fa-steam-square:before{content:"\f1b7"}  .fa-recycle:before{content:"\f1b8"}  .fa-automobile:before,.fa-car:before{content:"\f1b9"}  .fa-cab:before,.fa-taxi:before{content:"\f1ba"}  .fa-tree:before{content:"\f1bb"}  .fa-spotify:before{content:"\f1bc"}  .fa-deviantart:before{content:"\f1bd"}  .fa-soundcloud:before{content:"\f1be"}  .fa-database:before{content:"\f1c0"}  .fa-file-pdf-o:before{content:"\f1c1"}  .fa-file-word-o:before{content:"\f1c2"}  .fa-file-excel-o:before{content:"\f1c3"}  .fa-file-powerpoint-o:before{content:"\f1c4"}  .fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}  .fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}  .fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}  .fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}  .fa-file-code-o:before{content:"\f1c9"}  .fa-vine:before{content:"\f1ca"}  .fa-codepen:before{content:"\f1cb"}  .fa-jsfiddle:before{content:"\f1cc"}  .fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}  .fa-circle-o-notch:before{content:"\f1ce"}  .fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}  .fa-ge:before,.fa-empire:before{content:"\f1d1"}  .fa-git-square:before{content:"\f1d2"}  .fa-git:before{content:"\f1d3"}  .fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}  .fa-tencent-weibo:before{content:"\f1d5"}  .fa-qq:before{content:"\f1d6"}  .fa-wechat:before,.fa-weixin:before{content:"\f1d7"}  .fa-send:before,.fa-paper-plane:before{content:"\f1d8"}  .fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}  .fa-history:before{content:"\f1da"}  .fa-circle-thin:before{content:"\f1db"}  .fa-header:before{content:"\f1dc"}  .fa-paragraph:before{content:"\f1dd"}  .fa-sliders:before{content:"\f1de"}  .fa-share-alt:before{content:"\f1e0"}  .fa-share-alt-square:before{content:"\f1e1"}  .fa-bomb:before{content:"\f1e2"}  .fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}  .fa-tty:before{content:"\f1e4"}  .fa-binoculars:before{content:"\f1e5"}  .fa-plug:before{content:"\f1e6"}  .fa-slideshare:before{content:"\f1e7"}  .fa-twitch:before{content:"\f1e8"}  .fa-yelp:before{content:"\f1e9"}  .fa-newspaper-o:before{content:"\f1ea"}  .fa-wifi:before{content:"\f1eb"}  .fa-calculator:before{content:"\f1ec"}  .fa-paypal:before{content:"\f1ed"}  .fa-google-wallet:before{content:"\f1ee"}  .fa-cc-visa:before{content:"\f1f0"}  .fa-cc-mastercard:before{content:"\f1f1"}  .fa-cc-discover:before{content:"\f1f2"}  .fa-cc-amex:before{content:"\f1f3"}  .fa-cc-paypal:before{content:"\f1f4"}  .fa-cc-stripe:before{content:"\f1f5"}  .fa-bell-slash:before{content:"\f1f6"}  .fa-bell-slash-o:before{content:"\f1f7"}  .fa-trash:before{content:"\f1f8"}  .fa-copyright:before{content:"\f1f9"}  .fa-at:before{content:"\f1fa"}  .fa-eyedropper:before{content:"\f1fb"}  .fa-paint-brush:before{content:"\f1fc"}  .fa-birthday-cake:before{content:"\f1fd"}  .fa-area-chart:before{content:"\f1fe"}  .fa-pie-chart:before{content:"\f200"}  .fa-line-chart:before{content:"\f201"}  .fa-lastfm:before{content:"\f202"}  .fa-lastfm-square:before{content:"\f203"}  .fa-toggle-off:before{content:"\f204"}  .fa-toggle-on:before{content:"\f205"}  .fa-bicycle:before{content:"\f206"}  .fa-bus:before{content:"\f207"}  .fa-ioxhost:before{content:"\f208"}  .fa-angellist:before{content:"\f209"}  .fa-cc:before{content:"\f20a"}  .fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}  .fa-meanpath:before{content:"\f20c"}  .fa-buysellads:before{content:"\f20d"}  .fa-connectdevelop:before{content:"\f20e"}  .fa-dashcube:before{content:"\f210"}  .fa-forumbee:before{content:"\f211"}  .fa-leanpub:before{content:"\f212"}  .fa-sellsy:before{content:"\f213"}  .fa-shirtsinbulk:before{content:"\f214"}  .fa-simplybuilt:before{content:"\f215"}  .fa-skyatlas:before{content:"\f216"}  .fa-cart-plus:before{content:"\f217"}  .fa-cart-arrow-down:before{content:"\f218"}  .fa-diamond:before{content:"\f219"}  .fa-ship:before{content:"\f21a"}  .fa-user-secret:before{content:"\f21b"}  .fa-motorcycle:before{content:"\f21c"}  .fa-street-view:before{content:"\f21d"}  .fa-heartbeat:before{content:"\f21e"}  .fa-venus:before{content:"\f221"}  .fa-mars:before{content:"\f222"}  .fa-mercury:before{content:"\f223"}  .fa-intersex:before,.fa-transgender:before{content:"\f224"}  .fa-transgender-alt:before{content:"\f225"}  .fa-venus-double:before{content:"\f226"}  .fa-mars-double:before{content:"\f227"}  .fa-venus-mars:before{content:"\f228"}  .fa-mars-stroke:before{content:"\f229"}  .fa-mars-stroke-v:before{content:"\f22a"}  .fa-mars-stroke-h:before{content:"\f22b"}  .fa-neuter:before{content:"\f22c"}  .fa-genderless:before{content:"\f22d"}  .fa-facebook-official:before{content:"\f230"}  .fa-pinterest-p:before{content:"\f231"}  .fa-whatsapp:before{content:"\f232"}  .fa-server:before{content:"\f233"}  .fa-user-plus:before{content:"\f234"}  .fa-user-times:before{content:"\f235"}  .fa-hotel:before,.fa-bed:before{content:"\f236"}  .fa-viacoin:before{content:"\f237"}  .fa-train:before{content:"\f238"}  .fa-subway:before{content:"\f239"}  .fa-medium:before{content:"\f23a"}  .fa-yc:before,.fa-y-combinator:before{content:"\f23b"}  .fa-optin-monster:before{content:"\f23c"}  .fa-opencart:before{content:"\f23d"}  .fa-expeditedssl:before{content:"\f23e"}  .fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}  .fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}  .fa-battery-2:before,.fa-battery-half:before{content:"\f242"}  .fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}  .fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}  .fa-mouse-pointer:before{content:"\f245"}  .fa-i-cursor:before{content:"\f246"}  .fa-object-group:before{content:"\f247"}  .fa-object-ungroup:before{content:"\f248"}  .fa-sticky-note:before{content:"\f249"}  .fa-sticky-note-o:before{content:"\f24a"}  .fa-cc-jcb:before{content:"\f24b"}  .fa-cc-diners-club:before{content:"\f24c"}  .fa-clone:before{content:"\f24d"}  .fa-balance-scale:before{content:"\f24e"}  .fa-hourglass-o:before{content:"\f250"}  .fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}  .fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}  .fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}  .fa-hourglass:before{content:"\f254"}  .fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}  .fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}  .fa-hand-scissors-o:before{content:"\f257"}  .fa-hand-lizard-o:before{content:"\f258"}  .fa-hand-spock-o:before{content:"\f259"}  .fa-hand-pointer-o:before{content:"\f25a"}  .fa-hand-peace-o:before{content:"\f25b"}  .fa-trademark:before{content:"\f25c"}  .fa-registered:before{content:"\f25d"}  .fa-creative-commons:before{content:"\f25e"}  .fa-gg:before{content:"\f260"}  .fa-gg-circle:before{content:"\f261"}  .fa-tripadvisor:before{content:"\f262"}  .fa-odnoklassniki:before{content:"\f263"}  .fa-odnoklassniki-square:before{content:"\f264"}  .fa-get-pocket:before{content:"\f265"}  .fa-wikipedia-w:before{content:"\f266"}  .fa-safari:before{content:"\f267"}  .fa-chrome:before{content:"\f268"}  .fa-firefox:before{content:"\f269"}  .fa-opera:before{content:"\f26a"}  .fa-internet-explorer:before{content:"\f26b"}  .fa-tv:before,.fa-television:before{content:"\f26c"}  .fa-contao:before{content:"\f26d"}  .fa-500px:before{content:"\f26e"}  .fa-amazon:before{content:"\f270"}  .fa-calendar-plus-o:before{content:"\f271"}  .fa-calendar-minus-o:before{content:"\f272"}  .fa-calendar-times-o:before{content:"\f273"}  .fa-calendar-check-o:before{content:"\f274"}  .fa-industry:before{content:"\f275"}  .fa-map-pin:before{content:"\f276"}  .fa-map-signs:before{content:"\f277"}  .fa-map-o:before{content:"\f278"}  .fa-map:before{content:"\f279"}  .fa-commenting:before{content:"\f27a"}  .fa-commenting-o:before{content:"\f27b"}  .fa-houzz:before{content:"\f27c"}  .fa-vimeo:before{content:"\f27d"}  .fa-black-tie:before{content:"\f27e"}  .fa-fonticons:before{content:"\f280"}  .fa-reddit-alien:before{content:"\f281"}  .fa-edge:before{content:"\f282"}  .fa-credit-card-alt:before{content:"\f283"}  .fa-codiepie:before{content:"\f284"}  .fa-modx:before{content:"\f285"}  .fa-fort-awesome:before{content:"\f286"}  .fa-usb:before{content:"\f287"}  .fa-product-hunt:before{content:"\f288"}  .fa-mixcloud:before{content:"\f289"}  .fa-scribd:before{content:"\f28a"}  .fa-pause-circle:before{content:"\f28b"}  .fa-pause-circle-o:before{content:"\f28c"}  .fa-stop-circle:before{content:"\f28d"}  .fa-stop-circle-o:before{content:"\f28e"}  .fa-shopping-bag:before{content:"\f290"}  .fa-shopping-basket:before{content:"\f291"}  .fa-hashtag:before{content:"\f292"}  .fa-bluetooth:before{content:"\f293"}  .fa-bluetooth-b:before{content:"\f294"}  .fa-percent:before{content:"\f295"}  .fa-gitlab:before{content:"\f296"}  .fa-wpbeginner:before{content:"\f297"}  .fa-wpforms:before{content:"\f298"}  .fa-envira:before{content:"\f299"}  .fa-universal-access:before{content:"\f29a"}  .fa-wheelchair-alt:before{content:"\f29b"}  .fa-question-circle-o:before{content:"\f29c"}  .fa-blind:before{content:"\f29d"}  .fa-audio-description:before{content:"\f29e"}  .fa-volume-control-phone:before{content:"\f2a0"}  .fa-braille:before{content:"\f2a1"}  .fa-assistive-listening-systems:before{content:"\f2a2"}  .fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}  .fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}  .fa-glide:before{content:"\f2a5"}  .fa-glide-g:before{content:"\f2a6"}  .fa-signing:before,.fa-sign-language:before{content:"\f2a7"}  .fa-low-vision:before{content:"\f2a8"}  .fa-viadeo:before{content:"\f2a9"}  .fa-viadeo-square:before{content:"\f2aa"}  .fa-snapchat:before{content:"\f2ab"}  .fa-snapchat-ghost:before{content:"\f2ac"}  .fa-snapchat-square:before{content:"\f2ad"}  .fa-pied-piper:before{content:"\f2ae"}  .fa-first-order:before{content:"\f2b0"}  .fa-yoast:before{content:"\f2b1"}  .fa-themeisle:before{content:"\f2b2"}  .fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}  .fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}  .fa-handshake-o:before{content:"\f2b5"}  .fa-envelope-open:before{content:"\f2b6"}  .fa-envelope-open-o:before{content:"\f2b7"}  .fa-linode:before{content:"\f2b8"}  .fa-address-book:before{content:"\f2b9"}  .fa-address-book-o:before{content:"\f2ba"}  .fa-vcard:before,.fa-address-card:before{content:"\f2bb"}  .fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}  .fa-user-circle:before{content:"\f2bd"}  .fa-user-circle-o:before{content:"\f2be"}  .fa-user-o:before{content:"\f2c0"}  .fa-id-badge:before{content:"\f2c1"}  .fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}  .fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}  .fa-quora:before{content:"\f2c4"}  .fa-free-code-camp:before{content:"\f2c5"}  .fa-telegram:before{content:"\f2c6"}  .fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}  .fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}  .fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}  .fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}  .fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}  .fa-shower:before{content:"\f2cc"}  .fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}  .fa-podcast:before{content:"\f2ce"}  .fa-window-maximize:before{content:"\f2d0"}  .fa-window-minimize:before{content:"\f2d1"}  .fa-window-restore:before{content:"\f2d2"}  .fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}  .fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}  .fa-bandcamp:before{content:"\f2d5"}  .fa-grav:before{content:"\f2d6"}  .fa-etsy:before{content:"\f2d7"}  .fa-imdb:before{content:"\f2d8"}  .fa-ravelry:before{content:"\f2d9"}  .fa-eercast:before{content:"\f2da"}  .fa-microchip:before{content:"\f2db"}  .fa-snowflake-o:before{content:"\f2dc"}  .fa-superpowers:before{content:"\f2dd"}  .fa-wpexplorer:before{content:"\f2de"}  .fa-meetup:before{content:"\f2e0"}  .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}  .sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}
diff --git a/dal/dal/static/datacenterlight/font-awesome/fonts/FontAwesome.otf b/dal/static/datacenterlight/font-awesome/fonts/FontAwesome.otf
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/fonts/FontAwesome.otf
rename to dal/static/datacenterlight/font-awesome/fonts/FontAwesome.otf
diff --git a/dal/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.eot b/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.eot
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.eot
rename to dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.eot
diff --git a/dal/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.svg b/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.svg
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.svg
rename to dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.svg
diff --git a/dal/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.ttf b/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.ttf
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.ttf
rename to dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.ttf
diff --git a/dal/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.woff b/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.woff
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.woff
rename to dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.woff
diff --git a/dal/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.woff2 b/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.woff2
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.woff2
rename to dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.woff2
diff --git a/dal/dal/static/datacenterlight/font-awesome/less/bordered-pulled.less b/dal/static/datacenterlight/font-awesome/less/bordered-pulled.less
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/less/bordered-pulled.less
rename to dal/static/datacenterlight/font-awesome/less/bordered-pulled.less
diff --git a/dal/dal/static/datacenterlight/font-awesome/less/core.less b/dal/static/datacenterlight/font-awesome/less/core.less
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/less/core.less
rename to dal/static/datacenterlight/font-awesome/less/core.less
diff --git a/dal/dal/static/datacenterlight/font-awesome/less/fixed-width.less b/dal/static/datacenterlight/font-awesome/less/fixed-width.less
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/less/fixed-width.less
rename to dal/static/datacenterlight/font-awesome/less/fixed-width.less
diff --git a/dal/dal/static/datacenterlight/font-awesome/less/font-awesome.less b/dal/static/datacenterlight/font-awesome/less/font-awesome.less
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/less/font-awesome.less
rename to dal/static/datacenterlight/font-awesome/less/font-awesome.less
diff --git a/dal/dal/static/datacenterlight/font-awesome/less/icons.less b/dal/static/datacenterlight/font-awesome/less/icons.less
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/less/icons.less
rename to dal/static/datacenterlight/font-awesome/less/icons.less
diff --git a/dal/dal/static/datacenterlight/font-awesome/less/larger.less b/dal/static/datacenterlight/font-awesome/less/larger.less
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/less/larger.less
rename to dal/static/datacenterlight/font-awesome/less/larger.less
diff --git a/dal/dal/static/datacenterlight/font-awesome/less/list.less b/dal/static/datacenterlight/font-awesome/less/list.less
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/less/list.less
rename to dal/static/datacenterlight/font-awesome/less/list.less
diff --git a/dal/dal/static/datacenterlight/font-awesome/less/mixins.less b/dal/static/datacenterlight/font-awesome/less/mixins.less
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/less/mixins.less
rename to dal/static/datacenterlight/font-awesome/less/mixins.less
diff --git a/dal/dal/static/datacenterlight/font-awesome/less/path.less b/dal/static/datacenterlight/font-awesome/less/path.less
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/less/path.less
rename to dal/static/datacenterlight/font-awesome/less/path.less
diff --git a/dal/dal/static/datacenterlight/font-awesome/less/rotated-flipped.less b/dal/static/datacenterlight/font-awesome/less/rotated-flipped.less
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/less/rotated-flipped.less
rename to dal/static/datacenterlight/font-awesome/less/rotated-flipped.less
diff --git a/dal/dal/static/datacenterlight/font-awesome/less/spinning.less b/dal/static/datacenterlight/font-awesome/less/spinning.less
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/less/spinning.less
rename to dal/static/datacenterlight/font-awesome/less/spinning.less
diff --git a/dal/dal/static/datacenterlight/font-awesome/less/stacked.less b/dal/static/datacenterlight/font-awesome/less/stacked.less
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/less/stacked.less
rename to dal/static/datacenterlight/font-awesome/less/stacked.less
diff --git a/dal/dal/static/datacenterlight/font-awesome/less/variables.less b/dal/static/datacenterlight/font-awesome/less/variables.less
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/less/variables.less
rename to dal/static/datacenterlight/font-awesome/less/variables.less
diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_bordered-pulled.scss b/dal/static/datacenterlight/font-awesome/scss/_bordered-pulled.scss
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/scss/_bordered-pulled.scss
rename to dal/static/datacenterlight/font-awesome/scss/_bordered-pulled.scss
diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_core.scss b/dal/static/datacenterlight/font-awesome/scss/_core.scss
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/scss/_core.scss
rename to dal/static/datacenterlight/font-awesome/scss/_core.scss
diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_fixed-width.scss b/dal/static/datacenterlight/font-awesome/scss/_fixed-width.scss
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/scss/_fixed-width.scss
rename to dal/static/datacenterlight/font-awesome/scss/_fixed-width.scss
diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_icons.scss b/dal/static/datacenterlight/font-awesome/scss/_icons.scss
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/scss/_icons.scss
rename to dal/static/datacenterlight/font-awesome/scss/_icons.scss
diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_larger.scss b/dal/static/datacenterlight/font-awesome/scss/_larger.scss
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/scss/_larger.scss
rename to dal/static/datacenterlight/font-awesome/scss/_larger.scss
diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_list.scss b/dal/static/datacenterlight/font-awesome/scss/_list.scss
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/scss/_list.scss
rename to dal/static/datacenterlight/font-awesome/scss/_list.scss
diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_mixins.scss b/dal/static/datacenterlight/font-awesome/scss/_mixins.scss
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/scss/_mixins.scss
rename to dal/static/datacenterlight/font-awesome/scss/_mixins.scss
diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_path.scss b/dal/static/datacenterlight/font-awesome/scss/_path.scss
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/scss/_path.scss
rename to dal/static/datacenterlight/font-awesome/scss/_path.scss
diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_rotated-flipped.scss b/dal/static/datacenterlight/font-awesome/scss/_rotated-flipped.scss
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/scss/_rotated-flipped.scss
rename to dal/static/datacenterlight/font-awesome/scss/_rotated-flipped.scss
diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_spinning.scss b/dal/static/datacenterlight/font-awesome/scss/_spinning.scss
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/scss/_spinning.scss
rename to dal/static/datacenterlight/font-awesome/scss/_spinning.scss
diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_stacked.scss b/dal/static/datacenterlight/font-awesome/scss/_stacked.scss
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/scss/_stacked.scss
rename to dal/static/datacenterlight/font-awesome/scss/_stacked.scss
diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_variables.scss b/dal/static/datacenterlight/font-awesome/scss/_variables.scss
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/scss/_variables.scss
rename to dal/static/datacenterlight/font-awesome/scss/_variables.scss
diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/font-awesome.scss b/dal/static/datacenterlight/font-awesome/scss/font-awesome.scss
similarity index 100%
rename from dal/dal/static/datacenterlight/font-awesome/scss/font-awesome.scss
rename to dal/static/datacenterlight/font-awesome/scss/font-awesome.scss
diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Black.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Black.ttf
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Black.ttf
rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-Black.ttf
diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-BlackItalic.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-BlackItalic.ttf
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-BlackItalic.ttf
rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-BlackItalic.ttf
diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Bold.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Bold.ttf
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Bold.ttf
rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-Bold.ttf
diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-BoldItalic.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-BoldItalic.ttf
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-BoldItalic.ttf
rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-BoldItalic.ttf
diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraBold.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraBold.ttf
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraBold.ttf
rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraBold.ttf
diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraBoldItalic.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraBoldItalic.ttf
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraBoldItalic.ttf
rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraBoldItalic.ttf
diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraLight.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraLight.ttf
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraLight.ttf
rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraLight.ttf
diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraLightItalic.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraLightItalic.ttf
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraLightItalic.ttf
rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraLightItalic.ttf
diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Italic.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Italic.ttf
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Italic.ttf
rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-Italic.ttf
diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Light.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Light.ttf
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Light.ttf
rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-Light.ttf
diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-LightItalic.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-LightItalic.ttf
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-LightItalic.ttf
rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-LightItalic.ttf
diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Medium.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Medium.ttf
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Medium.ttf
rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-Medium.ttf
diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-MediumItalic.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-MediumItalic.ttf
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-MediumItalic.ttf
rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-MediumItalic.ttf
diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Regular.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Regular.ttf
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Regular.ttf
rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-Regular.ttf
diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-SemiBold.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-SemiBold.ttf
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-SemiBold.ttf
rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-SemiBold.ttf
diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-SemiBoldItalic.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-SemiBoldItalic.ttf
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-SemiBoldItalic.ttf
rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-SemiBoldItalic.ttf
diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Thin.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Thin.ttf
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Thin.ttf
rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-Thin.ttf
diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ThinItalic.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ThinItalic.ttf
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ThinItalic.ttf
rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-ThinItalic.ttf
diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/OFL.txt b/dal/static/datacenterlight/fonts/Montserrat/OFL.txt
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/Montserrat/OFL.txt
rename to dal/static/datacenterlight/fonts/Montserrat/OFL.txt
diff --git a/dal/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.eot b/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.eot
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.eot
rename to dal/static/datacenterlight/fonts/glyphicons-halflings-regular.eot
diff --git a/dal/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.svg b/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.svg
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.svg
rename to dal/static/datacenterlight/fonts/glyphicons-halflings-regular.svg
diff --git a/dal/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.ttf b/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.ttf
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.ttf
rename to dal/static/datacenterlight/fonts/glyphicons-halflings-regular.ttf
diff --git a/dal/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.woff b/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.woff
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.woff
rename to dal/static/datacenterlight/fonts/glyphicons-halflings-regular.woff
diff --git a/dal/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.woff2 b/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.woff2
similarity index 100%
rename from dal/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.woff2
rename to dal/static/datacenterlight/fonts/glyphicons-halflings-regular.woff2
diff --git a/dal/dal/static/datacenterlight/img/Ceph_Logo.png b/dal/static/datacenterlight/img/Ceph_Logo.png
similarity index 100%
rename from dal/dal/static/datacenterlight/img/Ceph_Logo.png
rename to dal/static/datacenterlight/img/Ceph_Logo.png
diff --git a/dal/dal/static/datacenterlight/img/banner-bg copy.jpg b/dal/static/datacenterlight/img/banner-bg copy.jpg
similarity index 100%
rename from dal/dal/static/datacenterlight/img/banner-bg copy.jpg
rename to dal/static/datacenterlight/img/banner-bg copy.jpg
diff --git a/dal/dal/static/datacenterlight/img/banner-bg.jpg b/dal/static/datacenterlight/img/banner-bg.jpg
similarity index 100%
rename from dal/dal/static/datacenterlight/img/banner-bg.jpg
rename to dal/static/datacenterlight/img/banner-bg.jpg
diff --git a/dal/dal/static/datacenterlight/img/bg.png b/dal/static/datacenterlight/img/bg.png
similarity index 100%
rename from dal/dal/static/datacenterlight/img/bg.png
rename to dal/static/datacenterlight/img/bg.png
diff --git a/dal/dal/static/datacenterlight/img/cdistbyungleich.png b/dal/static/datacenterlight/img/cdistbyungleich.png
similarity index 100%
rename from dal/dal/static/datacenterlight/img/cdistbyungleich.png
rename to dal/static/datacenterlight/img/cdistbyungleich.png
diff --git a/dal/dal/static/datacenterlight/img/checkmark.png b/dal/static/datacenterlight/img/checkmark.png
similarity index 100%
rename from dal/dal/static/datacenterlight/img/checkmark.png
rename to dal/static/datacenterlight/img/checkmark.png
diff --git a/dal/dal/static/datacenterlight/img/configure.jpg b/dal/static/datacenterlight/img/configure.jpg
similarity index 100%
rename from dal/dal/static/datacenterlight/img/configure.jpg
rename to dal/static/datacenterlight/img/configure.jpg
diff --git a/dal/dal/static/datacenterlight/img/datacenterlight.png b/dal/static/datacenterlight/img/datacenterlight.png
similarity index 100%
rename from dal/dal/static/datacenterlight/img/datacenterlight.png
rename to dal/static/datacenterlight/img/datacenterlight.png
diff --git a/dal/dal/static/datacenterlight/img/dcl-email-bg.jpg b/dal/static/datacenterlight/img/dcl-email-bg.jpg
similarity index 100%
rename from dal/dal/static/datacenterlight/img/dcl-email-bg.jpg
rename to dal/static/datacenterlight/img/dcl-email-bg.jpg
diff --git a/dal/dal/static/datacenterlight/img/deluxeroom.jpg b/dal/static/datacenterlight/img/deluxeroom.jpg
similarity index 100%
rename from dal/dal/static/datacenterlight/img/deluxeroom.jpg
rename to dal/static/datacenterlight/img/deluxeroom.jpg
diff --git a/dal/dal/static/datacenterlight/img/devuan.png b/dal/static/datacenterlight/img/devuan.png
similarity index 100%
rename from dal/dal/static/datacenterlight/img/devuan.png
rename to dal/static/datacenterlight/img/devuan.png
diff --git a/dal/dal/static/datacenterlight/img/django.png b/dal/static/datacenterlight/img/django.png
similarity index 100%
rename from dal/dal/static/datacenterlight/img/django.png
rename to dal/static/datacenterlight/img/django.png
diff --git a/dal/dal/static/datacenterlight/img/dog.png b/dal/static/datacenterlight/img/dog.png
similarity index 100%
rename from dal/dal/static/datacenterlight/img/dog.png
rename to dal/static/datacenterlight/img/dog.png
diff --git a/dal/dal/static/datacenterlight/img/economy.jpg b/dal/static/datacenterlight/img/economy.jpg
similarity index 100%
rename from dal/dal/static/datacenterlight/img/economy.jpg
rename to dal/static/datacenterlight/img/economy.jpg
diff --git a/dal/dal/static/datacenterlight/img/facebook_logo.svg b/dal/static/datacenterlight/img/facebook_logo.svg
similarity index 100%
rename from dal/dal/static/datacenterlight/img/facebook_logo.svg
rename to dal/static/datacenterlight/img/facebook_logo.svg
diff --git a/dal/dal/static/datacenterlight/img/favicon.ico b/dal/static/datacenterlight/img/favicon.ico
similarity index 100%
rename from dal/dal/static/datacenterlight/img/favicon.ico
rename to dal/static/datacenterlight/img/favicon.ico
diff --git a/dal/dal/static/datacenterlight/img/header-bg.jpg b/dal/static/datacenterlight/img/header-bg.jpg
similarity index 100%
rename from dal/dal/static/datacenterlight/img/header-bg.jpg
rename to dal/static/datacenterlight/img/header-bg.jpg
diff --git a/dal/dal/static/datacenterlight/img/home.png b/dal/static/datacenterlight/img/home.png
similarity index 100%
rename from dal/dal/static/datacenterlight/img/home.png
rename to dal/static/datacenterlight/img/home.png
diff --git a/dal/dal/static/datacenterlight/img/how.png b/dal/static/datacenterlight/img/how.png
similarity index 100%
rename from dal/dal/static/datacenterlight/img/how.png
rename to dal/static/datacenterlight/img/how.png
diff --git a/dal/dal/static/datacenterlight/img/how1.png b/dal/static/datacenterlight/img/how1.png
similarity index 100%
rename from dal/dal/static/datacenterlight/img/how1.png
rename to dal/static/datacenterlight/img/how1.png
diff --git a/dal/dal/static/datacenterlight/img/how2.png b/dal/static/datacenterlight/img/how2.png
similarity index 100%
rename from dal/dal/static/datacenterlight/img/how2.png
rename to dal/static/datacenterlight/img/how2.png
diff --git a/dal/dal/static/datacenterlight/img/how3.png b/dal/static/datacenterlight/img/how3.png
similarity index 100%
rename from dal/dal/static/datacenterlight/img/how3.png
rename to dal/static/datacenterlight/img/how3.png
diff --git a/dal/dal/static/datacenterlight/img/how4.png b/dal/static/datacenterlight/img/how4.png
similarity index 100%
rename from dal/dal/static/datacenterlight/img/how4.png
rename to dal/static/datacenterlight/img/how4.png
diff --git a/dal/dal/static/datacenterlight/img/intro-bg.jpg b/dal/static/datacenterlight/img/intro-bg.jpg
similarity index 100%
rename from dal/dal/static/datacenterlight/img/intro-bg.jpg
rename to dal/static/datacenterlight/img/intro-bg.jpg
diff --git a/dal/dal/static/datacenterlight/img/ipad.png b/dal/static/datacenterlight/img/ipad.png
similarity index 100%
rename from dal/dal/static/datacenterlight/img/ipad.png
rename to dal/static/datacenterlight/img/ipad.png
diff --git a/dal/dal/static/datacenterlight/img/loading.gif b/dal/static/datacenterlight/img/loading.gif
similarity index 100%
rename from dal/dal/static/datacenterlight/img/loading.gif
rename to dal/static/datacenterlight/img/loading.gif
diff --git a/dal/dal/static/datacenterlight/img/logo_black.png b/dal/static/datacenterlight/img/logo_black.png
similarity index 100%
rename from dal/dal/static/datacenterlight/img/logo_black.png
rename to dal/static/datacenterlight/img/logo_black.png
diff --git a/dal/dal/static/datacenterlight/img/logo_black.svg b/dal/static/datacenterlight/img/logo_black.svg
similarity index 100%
rename from dal/dal/static/datacenterlight/img/logo_black.svg
rename to dal/static/datacenterlight/img/logo_black.svg
diff --git a/dal/dal/static/datacenterlight/img/logo_white.svg b/dal/static/datacenterlight/img/logo_white.svg
similarity index 100%
rename from dal/dal/static/datacenterlight/img/logo_white.svg
rename to dal/static/datacenterlight/img/logo_white.svg
diff --git a/dal/dal/static/datacenterlight/img/opennebula.png b/dal/static/datacenterlight/img/opennebula.png
similarity index 100%
rename from dal/dal/static/datacenterlight/img/opennebula.png
rename to dal/static/datacenterlight/img/opennebula.png
diff --git a/dal/dal/static/datacenterlight/img/pattern.jpg b/dal/static/datacenterlight/img/pattern.jpg
similarity index 100%
rename from dal/dal/static/datacenterlight/img/pattern.jpg
rename to dal/static/datacenterlight/img/pattern.jpg
diff --git a/dal/dal/static/datacenterlight/img/phones.png b/dal/static/datacenterlight/img/phones.png
similarity index 100%
rename from dal/dal/static/datacenterlight/img/phones.png
rename to dal/static/datacenterlight/img/phones.png
diff --git a/dal/dal/static/datacenterlight/img/presidentialroom.jpg b/dal/static/datacenterlight/img/presidentialroom.jpg
similarity index 100%
rename from dal/dal/static/datacenterlight/img/presidentialroom.jpg
rename to dal/static/datacenterlight/img/presidentialroom.jpg
diff --git a/dal/dal/static/datacenterlight/img/prometheus.png b/dal/static/datacenterlight/img/prometheus.png
similarity index 100%
rename from dal/dal/static/datacenterlight/img/prometheus.png
rename to dal/static/datacenterlight/img/prometheus.png
diff --git a/dal/dal/static/datacenterlight/img/python-logo.png b/dal/static/datacenterlight/img/python-logo.png
similarity index 100%
rename from dal/dal/static/datacenterlight/img/python-logo.png
rename to dal/static/datacenterlight/img/python-logo.png
diff --git a/dal/dal/static/datacenterlight/img/ssd.jpg b/dal/static/datacenterlight/img/ssd.jpg
similarity index 100%
rename from dal/dal/static/datacenterlight/img/ssd.jpg
rename to dal/static/datacenterlight/img/ssd.jpg
diff --git a/dal/dal/static/datacenterlight/img/standardroom.jpg b/dal/static/datacenterlight/img/standardroom.jpg
similarity index 100%
rename from dal/dal/static/datacenterlight/img/standardroom.jpg
rename to dal/static/datacenterlight/img/standardroom.jpg
diff --git a/dal/dal/static/datacenterlight/img/tayga.png b/dal/static/datacenterlight/img/tayga.png
similarity index 100%
rename from dal/dal/static/datacenterlight/img/tayga.png
rename to dal/static/datacenterlight/img/tayga.png
diff --git a/dal/dal/static/datacenterlight/img/ubuntu.png b/dal/static/datacenterlight/img/ubuntu.png
similarity index 100%
rename from dal/dal/static/datacenterlight/img/ubuntu.png
rename to dal/static/datacenterlight/img/ubuntu.png
diff --git a/dal/dal/static/datacenterlight/js/bootstrap-3.3.7.min.js b/dal/static/datacenterlight/js/bootstrap-3.3.7.min.js
similarity index 100%
rename from dal/dal/static/datacenterlight/js/bootstrap-3.3.7.min.js
rename to dal/static/datacenterlight/js/bootstrap-3.3.7.min.js
diff --git a/dal/dal/static/datacenterlight/js/form.js b/dal/static/datacenterlight/js/form.js
similarity index 100%
rename from dal/dal/static/datacenterlight/js/form.js
rename to dal/static/datacenterlight/js/form.js
diff --git a/dal/dal/static/datacenterlight/js/jquery-2.2.4.min.js b/dal/static/datacenterlight/js/jquery-2.2.4.min.js
similarity index 100%
rename from dal/dal/static/datacenterlight/js/jquery-2.2.4.min.js
rename to dal/static/datacenterlight/js/jquery-2.2.4.min.js
diff --git a/dal/dal/static/datacenterlight/js/main.js b/dal/static/datacenterlight/js/main.js
similarity index 100%
rename from dal/dal/static/datacenterlight/js/main.js
rename to dal/static/datacenterlight/js/main.js
diff --git a/dal/dal/static/hosting/card-django.png b/dal/static/hosting/card-django.png
similarity index 100%
rename from dal/dal/static/hosting/card-django.png
rename to dal/static/hosting/card-django.png
diff --git a/dal/dal/static/hosting/card-nodejs.png b/dal/static/hosting/card-nodejs.png
similarity index 100%
rename from dal/dal/static/hosting/card-nodejs.png
rename to dal/static/hosting/card-nodejs.png
diff --git a/dal/dal/static/hosting/card-rails.png b/dal/static/hosting/card-rails.png
similarity index 100%
rename from dal/dal/static/hosting/card-rails.png
rename to dal/static/hosting/card-rails.png
diff --git a/dal/dal/static/hosting/css/commons.css b/dal/static/hosting/css/commons.css
similarity index 100%
rename from dal/dal/static/hosting/css/commons.css
rename to dal/static/hosting/css/commons.css
diff --git a/dal/dal/static/hosting/css/dashboard.css b/dal/static/hosting/css/dashboard.css
similarity index 100%
rename from dal/dal/static/hosting/css/dashboard.css
rename to dal/static/hosting/css/dashboard.css
diff --git a/dal/dal/static/hosting/css/landing-page.css b/dal/static/hosting/css/landing-page.css
similarity index 100%
rename from dal/dal/static/hosting/css/landing-page.css
rename to dal/static/hosting/css/landing-page.css
diff --git a/dal/dal/static/hosting/css/nodejshosting.css b/dal/static/hosting/css/nodejshosting.css
similarity index 100%
rename from dal/dal/static/hosting/css/nodejshosting.css
rename to dal/static/hosting/css/nodejshosting.css
diff --git a/dal/dal/static/hosting/css/order.css b/dal/static/hosting/css/order.css
similarity index 100%
rename from dal/dal/static/hosting/css/order.css
rename to dal/static/hosting/css/order.css
diff --git a/dal/dal/static/hosting/css/orders.css b/dal/static/hosting/css/orders.css
similarity index 100%
rename from dal/dal/static/hosting/css/orders.css
rename to dal/static/hosting/css/orders.css
diff --git a/dal/dal/static/hosting/css/payment.css b/dal/static/hosting/css/payment.css
similarity index 100%
rename from dal/dal/static/hosting/css/payment.css
rename to dal/static/hosting/css/payment.css
diff --git a/dal/dal/static/hosting/css/price_calculator.css b/dal/static/hosting/css/price_calculator.css
similarity index 100%
rename from dal/dal/static/hosting/css/price_calculator.css
rename to dal/static/hosting/css/price_calculator.css
diff --git a/dal/dal/static/hosting/css/pricing.css b/dal/static/hosting/css/pricing.css
similarity index 100%
rename from dal/dal/static/hosting/css/pricing.css
rename to dal/static/hosting/css/pricing.css
diff --git a/dal/dal/static/hosting/css/user_keys.css b/dal/static/hosting/css/user_keys.css
similarity index 100%
rename from dal/dal/static/hosting/css/user_keys.css
rename to dal/static/hosting/css/user_keys.css
diff --git a/dal/dal/static/hosting/css/virtual-machine.css b/dal/static/hosting/css/virtual-machine.css
similarity index 100%
rename from dal/dal/static/hosting/css/virtual-machine.css
rename to dal/static/hosting/css/virtual-machine.css
diff --git a/dal/dal/static/hosting/django-intro-bg.png b/dal/static/hosting/django-intro-bg.png
similarity index 100%
rename from dal/dal/static/hosting/django-intro-bg.png
rename to dal/static/hosting/django-intro-bg.png
diff --git a/dal/dal/static/hosting/img/24-hours-support.svg b/dal/static/hosting/img/24-hours-support.svg
similarity index 100%
rename from dal/dal/static/hosting/img/24-hours-support.svg
rename to dal/static/hosting/img/24-hours-support.svg
diff --git a/dal/dal/static/hosting/img/CH_flag.png b/dal/static/hosting/img/CH_flag.png
similarity index 100%
rename from dal/dal/static/hosting/img/CH_flag.png
rename to dal/static/hosting/img/CH_flag.png
diff --git a/dal/dal/static/hosting/img/DE_flag.png b/dal/static/hosting/img/DE_flag.png
similarity index 100%
rename from dal/dal/static/hosting/img/DE_flag.png
rename to dal/static/hosting/img/DE_flag.png
diff --git a/dal/dal/static/hosting/img/ajax-loader.gif b/dal/static/hosting/img/ajax-loader.gif
similarity index 100%
rename from dal/dal/static/hosting/img/ajax-loader.gif
rename to dal/static/hosting/img/ajax-loader.gif
diff --git a/dal/dal/static/hosting/img/auth-bg-sm.jpg b/dal/static/hosting/img/auth-bg-sm.jpg
similarity index 100%
rename from dal/dal/static/hosting/img/auth-bg-sm.jpg
rename to dal/static/hosting/img/auth-bg-sm.jpg
diff --git a/dal/dal/static/hosting/img/auth-bg.jpg b/dal/static/hosting/img/auth-bg.jpg
similarity index 100%
rename from dal/dal/static/hosting/img/auth-bg.jpg
rename to dal/static/hosting/img/auth-bg.jpg
diff --git a/dal/dal/static/hosting/img/banner-bg copy.jpg b/dal/static/hosting/img/banner-bg copy.jpg
similarity index 100%
rename from dal/dal/static/hosting/img/banner-bg copy.jpg
rename to dal/static/hosting/img/banner-bg copy.jpg
diff --git a/dal/dal/static/hosting/img/banner-bg.jpg b/dal/static/hosting/img/banner-bg.jpg
similarity index 100%
rename from dal/dal/static/hosting/img/banner-bg.jpg
rename to dal/static/hosting/img/banner-bg.jpg
diff --git a/dal/dal/static/hosting/img/billing.svg b/dal/static/hosting/img/billing.svg
similarity index 100%
rename from dal/dal/static/hosting/img/billing.svg
rename to dal/static/hosting/img/billing.svg
diff --git a/dal/dal/static/hosting/img/card-django.png b/dal/static/hosting/img/card-django.png
similarity index 100%
rename from dal/dal/static/hosting/img/card-django.png
rename to dal/static/hosting/img/card-django.png
diff --git a/dal/dal/static/hosting/img/card-nodejs.png b/dal/static/hosting/img/card-nodejs.png
similarity index 100%
rename from dal/dal/static/hosting/img/card-nodejs.png
rename to dal/static/hosting/img/card-nodejs.png
diff --git a/dal/dal/static/hosting/img/card-rails.png b/dal/static/hosting/img/card-rails.png
similarity index 100%
rename from dal/dal/static/hosting/img/card-rails.png
rename to dal/static/hosting/img/card-rails.png
diff --git a/dal/dal/static/hosting/img/checkmark.png b/dal/static/hosting/img/checkmark.png
similarity index 100%
rename from dal/dal/static/hosting/img/checkmark.png
rename to dal/static/hosting/img/checkmark.png
diff --git a/dal/dal/static/hosting/img/configure.jpg b/dal/static/hosting/img/configure.jpg
similarity index 100%
rename from dal/dal/static/hosting/img/configure.jpg
rename to dal/static/hosting/img/configure.jpg
diff --git a/dal/dal/static/hosting/img/connected.svg b/dal/static/hosting/img/connected.svg
similarity index 100%
rename from dal/dal/static/hosting/img/connected.svg
rename to dal/static/hosting/img/connected.svg
diff --git a/dal/dal/static/hosting/img/copy.svg b/dal/static/hosting/img/copy.svg
similarity index 100%
rename from dal/dal/static/hosting/img/copy.svg
rename to dal/static/hosting/img/copy.svg
diff --git a/dal/dal/static/hosting/img/dashboard_settings.svg b/dal/static/hosting/img/dashboard_settings.svg
similarity index 100%
rename from dal/dal/static/hosting/img/dashboard_settings.svg
rename to dal/static/hosting/img/dashboard_settings.svg
diff --git a/dal/dal/static/hosting/img/delete.svg b/dal/static/hosting/img/delete.svg
similarity index 100%
rename from dal/dal/static/hosting/img/delete.svg
rename to dal/static/hosting/img/delete.svg
diff --git a/dal/dal/static/hosting/img/deluxeroom.jpg b/dal/static/hosting/img/deluxeroom.jpg
similarity index 100%
rename from dal/dal/static/hosting/img/deluxeroom.jpg
rename to dal/static/hosting/img/deluxeroom.jpg
diff --git a/dal/dal/static/hosting/img/django-intro-bg.png b/dal/static/hosting/img/django-intro-bg.png
similarity index 100%
rename from dal/dal/static/hosting/img/django-intro-bg.png
rename to dal/static/hosting/img/django-intro-bg.png
diff --git a/dal/dal/static/hosting/img/dog.png b/dal/static/hosting/img/dog.png
similarity index 100%
rename from dal/dal/static/hosting/img/dog.png
rename to dal/static/hosting/img/dog.png
diff --git a/dal/dal/static/hosting/img/economy.jpg b/dal/static/hosting/img/economy.jpg
similarity index 100%
rename from dal/dal/static/hosting/img/economy.jpg
rename to dal/static/hosting/img/economy.jpg
diff --git a/dal/dal/static/hosting/img/favicon.ico b/dal/static/hosting/img/favicon.ico
similarity index 100%
rename from dal/dal/static/hosting/img/favicon.ico
rename to dal/static/hosting/img/favicon.ico
diff --git a/dal/dal/static/hosting/img/g222.png b/dal/static/hosting/img/g222.png
similarity index 100%
rename from dal/dal/static/hosting/img/g222.png
rename to dal/static/hosting/img/g222.png
diff --git a/dal/dal/static/hosting/img/header-bg.jpg b/dal/static/hosting/img/header-bg.jpg
similarity index 100%
rename from dal/dal/static/hosting/img/header-bg.jpg
rename to dal/static/hosting/img/header-bg.jpg
diff --git a/dal/dal/static/hosting/img/home.png b/dal/static/hosting/img/home.png
similarity index 100%
rename from dal/dal/static/hosting/img/home.png
rename to dal/static/hosting/img/home.png
diff --git a/dal/dal/static/hosting/img/how.png b/dal/static/hosting/img/how.png
similarity index 100%
rename from dal/dal/static/hosting/img/how.png
rename to dal/static/hosting/img/how.png
diff --git a/dal/dal/static/hosting/img/how1.png b/dal/static/hosting/img/how1.png
similarity index 100%
rename from dal/dal/static/hosting/img/how1.png
rename to dal/static/hosting/img/how1.png
diff --git a/dal/dal/static/hosting/img/how2.png b/dal/static/hosting/img/how2.png
similarity index 100%
rename from dal/dal/static/hosting/img/how2.png
rename to dal/static/hosting/img/how2.png
diff --git a/dal/dal/static/hosting/img/how4.png b/dal/static/hosting/img/how4.png
similarity index 100%
rename from dal/dal/static/hosting/img/how4.png
rename to dal/static/hosting/img/how4.png
diff --git a/dal/dal/static/hosting/img/icon-pdf.svg b/dal/static/hosting/img/icon-pdf.svg
similarity index 100%
rename from dal/dal/static/hosting/img/icon-pdf.svg
rename to dal/static/hosting/img/icon-pdf.svg
diff --git a/dal/dal/static/hosting/img/icon-print.svg b/dal/static/hosting/img/icon-print.svg
similarity index 100%
rename from dal/dal/static/hosting/img/icon-print.svg
rename to dal/static/hosting/img/icon-print.svg
diff --git a/dal/dal/static/hosting/img/intro-bg.jpg b/dal/static/hosting/img/intro-bg.jpg
similarity index 100%
rename from dal/dal/static/hosting/img/intro-bg.jpg
rename to dal/static/hosting/img/intro-bg.jpg
diff --git a/dal/dal/static/hosting/img/ipad.png b/dal/static/hosting/img/ipad.png
similarity index 100%
rename from dal/dal/static/hosting/img/ipad.png
rename to dal/static/hosting/img/ipad.png
diff --git a/dal/dal/static/hosting/img/key.svg b/dal/static/hosting/img/key.svg
similarity index 100%
rename from dal/dal/static/hosting/img/key.svg
rename to dal/static/hosting/img/key.svg
diff --git a/dal/dal/static/hosting/img/login-bg.jpg b/dal/static/hosting/img/login-bg.jpg
similarity index 100%
rename from dal/dal/static/hosting/img/login-bg.jpg
rename to dal/static/hosting/img/login-bg.jpg
diff --git a/dal/dal/static/hosting/img/logo_black.png b/dal/static/hosting/img/logo_black.png
similarity index 100%
rename from dal/dal/static/hosting/img/logo_black.png
rename to dal/static/hosting/img/logo_black.png
diff --git a/dal/dal/static/hosting/img/logo_black.svg b/dal/static/hosting/img/logo_black.svg
similarity index 100%
rename from dal/dal/static/hosting/img/logo_black.svg
rename to dal/static/hosting/img/logo_black.svg
diff --git a/dal/dal/static/hosting/img/logo_white.svg b/dal/static/hosting/img/logo_white.svg
similarity index 100%
rename from dal/dal/static/hosting/img/logo_white.svg
rename to dal/static/hosting/img/logo_white.svg
diff --git a/dal/dal/static/hosting/img/nodejs-intro-bg.png b/dal/static/hosting/img/nodejs-intro-bg.png
similarity index 100%
rename from dal/dal/static/hosting/img/nodejs-intro-bg.png
rename to dal/static/hosting/img/nodejs-intro-bg.png
diff --git a/dal/dal/static/hosting/img/pattern.jpg b/dal/static/hosting/img/pattern.jpg
similarity index 100%
rename from dal/dal/static/hosting/img/pattern.jpg
rename to dal/static/hosting/img/pattern.jpg
diff --git a/dal/dal/static/hosting/img/pattern_original.jpg b/dal/static/hosting/img/pattern_original.jpg
similarity index 100%
rename from dal/dal/static/hosting/img/pattern_original.jpg
rename to dal/static/hosting/img/pattern_original.jpg
diff --git a/dal/dal/static/hosting/img/phones.png b/dal/static/hosting/img/phones.png
similarity index 100%
rename from dal/dal/static/hosting/img/phones.png
rename to dal/static/hosting/img/phones.png
diff --git a/dal/dal/static/hosting/img/plusVM.svg b/dal/static/hosting/img/plusVM.svg
similarity index 100%
rename from dal/dal/static/hosting/img/plusVM.svg
rename to dal/static/hosting/img/plusVM.svg
diff --git a/dal/dal/static/hosting/img/presidentialroom.jpg b/dal/static/hosting/img/presidentialroom.jpg
similarity index 100%
rename from dal/dal/static/hosting/img/presidentialroom.jpg
rename to dal/static/hosting/img/presidentialroom.jpg
diff --git a/dal/dal/static/hosting/img/rails-intro-bg.png b/dal/static/hosting/img/rails-intro-bg.png
similarity index 100%
rename from dal/dal/static/hosting/img/rails-intro-bg.png
rename to dal/static/hosting/img/rails-intro-bg.png
diff --git a/dal/dal/static/hosting/img/settings.svg b/dal/static/hosting/img/settings.svg
similarity index 100%
rename from dal/dal/static/hosting/img/settings.svg
rename to dal/static/hosting/img/settings.svg
diff --git a/dal/dal/static/hosting/img/shopping-cart.svg b/dal/static/hosting/img/shopping-cart.svg
similarity index 100%
rename from dal/dal/static/hosting/img/shopping-cart.svg
rename to dal/static/hosting/img/shopping-cart.svg
diff --git a/dal/dal/static/hosting/img/signup-bg.png b/dal/static/hosting/img/signup-bg.png
similarity index 100%
rename from dal/dal/static/hosting/img/signup-bg.png
rename to dal/static/hosting/img/signup-bg.png
diff --git a/dal/dal/static/hosting/img/standardroom.jpg b/dal/static/hosting/img/standardroom.jpg
similarity index 100%
rename from dal/dal/static/hosting/img/standardroom.jpg
rename to dal/static/hosting/img/standardroom.jpg
diff --git a/dal/dal/static/hosting/img/ubuntu.png b/dal/static/hosting/img/ubuntu.png
similarity index 100%
rename from dal/dal/static/hosting/img/ubuntu.png
rename to dal/static/hosting/img/ubuntu.png
diff --git a/dal/dal/static/hosting/img/vm.svg b/dal/static/hosting/img/vm.svg
similarity index 100%
rename from dal/dal/static/hosting/img/vm.svg
rename to dal/static/hosting/img/vm.svg
diff --git a/dal/dal/static/hosting/js/createvm.js b/dal/static/hosting/js/createvm.js
similarity index 100%
rename from dal/dal/static/hosting/js/createvm.js
rename to dal/static/hosting/js/createvm.js
diff --git a/dal/dal/static/hosting/js/gen-ssh-key.js b/dal/static/hosting/js/gen-ssh-key.js
similarity index 100%
rename from dal/dal/static/hosting/js/gen-ssh-key.js
rename to dal/static/hosting/js/gen-ssh-key.js
diff --git a/dal/dal/static/hosting/js/html2canvas.min.js b/dal/static/hosting/js/html2canvas.min.js
similarity index 100%
rename from dal/dal/static/hosting/js/html2canvas.min.js
rename to dal/static/hosting/js/html2canvas.min.js
diff --git a/dal/dal/static/hosting/js/html2pdf.min.js b/dal/static/hosting/js/html2pdf.min.js
similarity index 100%
rename from dal/dal/static/hosting/js/html2pdf.min.js
rename to dal/static/hosting/js/html2pdf.min.js
diff --git a/dal/dal/static/hosting/js/initial.js b/dal/static/hosting/js/initial.js
similarity index 100%
rename from dal/dal/static/hosting/js/initial.js
rename to dal/static/hosting/js/initial.js
diff --git a/dal/dal/static/hosting/js/order.js b/dal/static/hosting/js/order.js
similarity index 100%
rename from dal/dal/static/hosting/js/order.js
rename to dal/static/hosting/js/order.js
diff --git a/dal/dal/static/hosting/js/payment.js b/dal/static/hosting/js/payment.js
similarity index 100%
rename from dal/dal/static/hosting/js/payment.js
rename to dal/static/hosting/js/payment.js
diff --git a/dal/dal/static/hosting/js/pricing.js b/dal/static/hosting/js/pricing.js
similarity index 100%
rename from dal/dal/static/hosting/js/pricing.js
rename to dal/static/hosting/js/pricing.js
diff --git a/dal/dal/static/hosting/js/virtual_machine_detail.js b/dal/static/hosting/js/virtual_machine_detail.js
similarity index 100%
rename from dal/dal/static/hosting/js/virtual_machine_detail.js
rename to dal/static/hosting/js/virtual_machine_detail.js
diff --git a/dal/dal/static/hosting/nodejs-intro-bg.png b/dal/static/hosting/nodejs-intro-bg.png
similarity index 100%
rename from dal/dal/static/hosting/nodejs-intro-bg.png
rename to dal/static/hosting/nodejs-intro-bg.png
diff --git a/dal/dal/static/hosting/rails-intro-bg.png b/dal/static/hosting/rails-intro-bg.png
similarity index 100%
rename from dal/dal/static/hosting/rails-intro-bg.png
rename to dal/static/hosting/rails-intro-bg.png
diff --git a/dal/dal/templates/base.html b/dal/templates/base.html
similarity index 100%
rename from dal/dal/templates/base.html
rename to dal/templates/base.html
diff --git a/dal/dal/templates/base_short.html b/dal/templates/base_short.html
similarity index 100%
rename from dal/dal/templates/base_short.html
rename to dal/templates/base_short.html
diff --git a/dal/dal/templates/changeddata.html b/dal/templates/changeddata.html
similarity index 100%
rename from dal/dal/templates/changeddata.html
rename to dal/templates/changeddata.html
diff --git a/dal/dal/templates/changedpassword.html b/dal/templates/changedpassword.html
similarity index 100%
rename from dal/dal/templates/changedpassword.html
rename to dal/templates/changedpassword.html
diff --git a/dal/dal/templates/changepassword.html b/dal/templates/changepassword.html
similarity index 100%
rename from dal/dal/templates/changepassword.html
rename to dal/templates/changepassword.html
diff --git a/dal/dal/templates/changeuserdata.html b/dal/templates/changeuserdata.html
similarity index 100%
rename from dal/dal/templates/changeuserdata.html
rename to dal/templates/changeuserdata.html
diff --git a/dal/dal/templates/deleteaccount.html b/dal/templates/deleteaccount.html
similarity index 100%
rename from dal/dal/templates/deleteaccount.html
rename to dal/templates/deleteaccount.html
diff --git a/dal/dal/templates/deleteduser.html b/dal/templates/deleteduser.html
similarity index 100%
rename from dal/dal/templates/deleteduser.html
rename to dal/templates/deleteduser.html
diff --git a/dal/dal/templates/error.html b/dal/templates/error.html
similarity index 100%
rename from dal/dal/templates/error.html
rename to dal/templates/error.html
diff --git a/dal/dal/templates/hosting_login.html b/dal/templates/hosting_login.html
similarity index 100%
rename from dal/dal/templates/hosting_login.html
rename to dal/templates/hosting_login.html
diff --git a/dal/dal/templates/includes/_card_input.html b/dal/templates/includes/_card_input.html
similarity index 100%
rename from dal/dal/templates/includes/_card_input.html
rename to dal/templates/includes/_card_input.html
diff --git a/dal/dal/templates/includes/_contact.html b/dal/templates/includes/_contact.html
similarity index 100%
rename from dal/dal/templates/includes/_contact.html
rename to dal/templates/includes/_contact.html
diff --git a/dal/dal/templates/includes/_footer.html b/dal/templates/includes/_footer.html
similarity index 100%
rename from dal/dal/templates/includes/_footer.html
rename to dal/templates/includes/_footer.html
diff --git a/dal/dal/templates/includes/_header.html b/dal/templates/includes/_header.html
similarity index 100%
rename from dal/dal/templates/includes/_header.html
rename to dal/templates/includes/_header.html
diff --git a/dal/dal/templates/includes/_messages.html b/dal/templates/includes/_messages.html
similarity index 100%
rename from dal/dal/templates/includes/_messages.html
rename to dal/templates/includes/_messages.html
diff --git a/dal/dal/templates/includes/_navbar.html b/dal/templates/includes/_navbar.html
similarity index 100%
rename from dal/dal/templates/includes/_navbar.html
rename to dal/templates/includes/_navbar.html
diff --git a/dal/dal/templates/includes/_navbar_transparent.html b/dal/templates/includes/_navbar_transparent.html
similarity index 100%
rename from dal/dal/templates/includes/_navbar_transparent.html
rename to dal/templates/includes/_navbar_transparent.html
diff --git a/dal/dal/templates/includes/_navbar_user.html b/dal/templates/includes/_navbar_user.html
similarity index 100%
rename from dal/dal/templates/includes/_navbar_user.html
rename to dal/templates/includes/_navbar_user.html
diff --git a/dal/dal/templates/includes/_our_infrastructure.html b/dal/templates/includes/_our_infrastructure.html
similarity index 100%
rename from dal/dal/templates/includes/_our_infrastructure.html
rename to dal/templates/includes/_our_infrastructure.html
diff --git a/dal/dal/templates/includes/_pricing.html b/dal/templates/includes/_pricing.html
similarity index 100%
rename from dal/dal/templates/includes/_pricing.html
rename to dal/templates/includes/_pricing.html
diff --git a/dal/dal/templates/includes/_your_infrastructure.html b/dal/templates/includes/_your_infrastructure.html
similarity index 100%
rename from dal/dal/templates/includes/_your_infrastructure.html
rename to dal/templates/includes/_your_infrastructure.html
diff --git a/dal/dal/templates/landing.html b/dal/templates/landing.html
similarity index 100%
rename from dal/dal/templates/landing.html
rename to dal/templates/landing.html
diff --git a/dal/dal/templates/loginfailed.html b/dal/templates/loginfailed.html
similarity index 100%
rename from dal/dal/templates/loginfailed.html
rename to dal/templates/loginfailed.html
diff --git a/dal/dal/templates/mustbeloggedin.html b/dal/templates/mustbeloggedin.html
similarity index 100%
rename from dal/dal/templates/mustbeloggedin.html
rename to dal/templates/mustbeloggedin.html
diff --git a/dal/dal/templates/registeruser.html b/dal/templates/registeruser.html
similarity index 100%
rename from dal/dal/templates/registeruser.html
rename to dal/templates/registeruser.html
diff --git a/dal/dal/templates/resetpassword.html b/dal/templates/resetpassword.html
similarity index 100%
rename from dal/dal/templates/resetpassword.html
rename to dal/templates/resetpassword.html
diff --git a/dal/dal/templates/resetpasswordnew.html b/dal/templates/resetpasswordnew.html
similarity index 100%
rename from dal/dal/templates/resetpasswordnew.html
rename to dal/templates/resetpasswordnew.html
diff --git a/dal/dal/templates/send_resetrequest.html b/dal/templates/send_resetrequest.html
similarity index 100%
rename from dal/dal/templates/send_resetrequest.html
rename to dal/templates/send_resetrequest.html
diff --git a/dal/dal/templates/usercreated.html b/dal/templates/usercreated.html
similarity index 100%
rename from dal/dal/templates/usercreated.html
rename to dal/templates/usercreated.html
diff --git a/dal/dal/templates/useroptions.html b/dal/templates/useroptions.html
similarity index 100%
rename from dal/dal/templates/useroptions.html
rename to dal/templates/useroptions.html
diff --git a/dal/dal/urls.py b/dal/urls.py
similarity index 100%
rename from dal/dal/urls.py
rename to dal/urls.py
diff --git a/dal/dal/views.py b/dal/views.py
similarity index 100%
rename from dal/dal/views.py
rename to dal/views.py
diff --git a/dal/dal/wsgi.py b/dal/wsgi.py
similarity index 100%
rename from dal/dal/wsgi.py
rename to dal/wsgi.py
diff --git a/dal/manage.py b/manage.py
similarity index 100%
rename from dal/manage.py
rename to manage.py

From 1673d6e03ba37396e946f037acb23b65ee591c48 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 17 Feb 2019 17:44:17 +0100
Subject: [PATCH 02/54] Update .gitignore

---
 .gitignore | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/.gitignore b/.gitignore
index f7275bb..712a31c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,41 @@
+*.log
+db.sqlite3
+*.pyc
+*.DS_Store
+build/
+*.egg_info
+#editors && utilites.
+*.swp
+*~
+__pycache__/
+.ropeproject/
+#django
+local_settings.py
+
+!.keep
+media/
+!media/keep
+/CACHE/
+/static/
+
+\#*#
+.\#*
+*~
+
+secret-key
+
+node_modules/
+*.db
+ungleich.db
+*~*
+
+secret-key
+
+*.psd
+
+.idea/
+
+.env
+*.mo
+
 venv/

From 8b61db8dee1902ae116954bf505ae5da7156aef2 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 17 Feb 2019 17:57:48 +0100
Subject: [PATCH 03/54] Simplify getting LDAP_USE_TLS

---
 dal/settings.py | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/dal/settings.py b/dal/settings.py
index 7c30a2a..ee96962 100644
--- a/dal/settings.py
+++ b/dal/settings.py
@@ -28,8 +28,7 @@ search_base = os.environ['LDAPSEARCH'].split()
 search_base_ldap = [ LDAPSearch(x, ldap.SCOPE_SUBTREE, "(uid=%(user)s)") for x in search_base ]
 AUTH_LDAP_USER_SEARCH = LDAPSearchUnion(*search_base_ldap)
 
-if os.environ['LDAP_USE_TLS']:
-    AUTH_LDAP_START_TLS=True
+AUTH_LDAP_START_TLS = os.environ.get('LDAP_USE_TLS', False)
 
 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 

From 5ec63d8536d2c0786d9a4558b62f1aa7636fd4d2 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 17 Feb 2019 18:08:36 +0100
Subject: [PATCH 04/54] Get ALLOWED_HOSTS and DEBUG from .env

---
 dal/settings.py | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/dal/settings.py b/dal/settings.py
index ee96962..9fd3169 100644
--- a/dal/settings.py
+++ b/dal/settings.py
@@ -32,7 +32,9 @@ AUTH_LDAP_START_TLS = os.environ.get('LDAP_USE_TLS', False)
 
 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 
-ALLOWED_HOSTS = []
+ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost')
+
+DEBUG = os.environ.get('DEBUG', False)
 
 INSTALLED_APPS = [
     'django.contrib.admin',
@@ -131,6 +133,3 @@ DATABASES = {
     }
 }
 SECRET_KEY = os.environ.get('SECRET_KEY')
-
-# SECURITY WARNING: don't run with debug turned on in production!
-DEBUG = os.environ.get('DEBUG', False)

From 876567f9337fd476d3b9d8e0163b8b88eb1735d5 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 17 Feb 2019 18:20:56 +0100
Subject: [PATCH 05/54] Correct the way we get ALLOWED_HOSTS

---
 dal/settings.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/dal/settings.py b/dal/settings.py
index 9fd3169..8b467c2 100644
--- a/dal/settings.py
+++ b/dal/settings.py
@@ -32,10 +32,10 @@ AUTH_LDAP_START_TLS = os.environ.get('LDAP_USE_TLS', False)
 
 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 
-ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost')
-
 DEBUG = os.environ.get('DEBUG', False)
 
+ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost').split(",")
+
 INSTALLED_APPS = [
     'django.contrib.admin',
     'django.contrib.auth',

From c4c990a98d80ccdbf6b67bcedfdbae3770e4d0e5 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 17 Feb 2019 18:25:12 +0100
Subject: [PATCH 06/54] More correction

---
 dal/settings.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dal/settings.py b/dal/settings.py
index 8b467c2..2aa808d 100644
--- a/dal/settings.py
+++ b/dal/settings.py
@@ -34,7 +34,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 
 DEBUG = os.environ.get('DEBUG', False)
 
-ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost').split(",")
+ALLOWED_HOSTS = (os.environ.get('ALLOWED_HOSTS', 'localhost')).split(",")
 
 INSTALLED_APPS = [
     'django.contrib.admin',

From 467af3422c4a003018e98ece457c1bc5addda77a Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Mon, 18 Feb 2019 22:01:07 +0100
Subject: [PATCH 07/54] Update django bootstrap and filter requirements

---
 requirements.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/requirements.txt b/requirements.txt
index 0767c8c..f6d34b1 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,3 +2,5 @@ django
 django-auth-ldap
 python-ldap
 django-dotenv
+django-bootstrap3
+django-filter==2.1.0
\ No newline at end of file

From c571cf5c1d6cfb05e819afcf71a5f91a7492350b Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Mon, 18 Feb 2019 22:01:42 +0100
Subject: [PATCH 08/54] Add bootstrap3 to INSTALLED_APPS

---
 dal/settings.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/dal/settings.py b/dal/settings.py
index 2aa808d..1cc50c3 100644
--- a/dal/settings.py
+++ b/dal/settings.py
@@ -43,6 +43,7 @@ INSTALLED_APPS = [
     'django.contrib.sessions',
     'django.contrib.messages',
     'django.contrib.staticfiles',
+    'bootstrap3',
     'dal',
 ]
 

From dab31aa8537c476f908be92e2ddffedaf01ed8eb Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Mon, 18 Feb 2019 22:03:51 +0100
Subject: [PATCH 09/54] Remove unwanted code / refactor code

---
 dal/templates/includes/_footer.html           | 32 --------
 .../includes/_navbar_transparent.html         |  1 -
 dal/templates/landing.html                    | 73 +++++++++----------
 3 files changed, 35 insertions(+), 71 deletions(-)

diff --git a/dal/templates/includes/_footer.html b/dal/templates/includes/_footer.html
index e61ed59..800f7dc 100644
--- a/dal/templates/includes/_footer.html
+++ b/dal/templates/includes/_footer.html
@@ -1,41 +1,9 @@
 {% load i18n %}
-
-<style>
-.col-lg-12 {
-	background-color: grey;
-	color: white;
-}
-.list-inline {
-	background-color: grey;
-	color: white;
-}
-</style>
-
 <footer>
     <div class="container">
         <div class="row">
             <div class="col-lg-12">
                 <ul class="list-inline">
-                    <li class="col-lg-12">
-                        <a href="#">Home</a>
-                    </li>
-                    <li class="footer-menu-divider">&sdot;</li>
-                    <li>
-                        <a href="#about">How it works</a></li>
-                    <li class="footer-menu-divider">&sdot;</li>
-                    <li>
-                        <a href="#about">Your infrastructure</a></li>
-                    <li>&sdot;</li>
-                    <li>
-                        <a href="#about">Our infrastructure</a></li>
-                    <li class="footer-menu-divider">&sdot;</li>
-                    <li>
-                        <a href="#services">Pricing</a>
-                    </li>
-                    <li class="footer-menu-divider">&sdot;</li>
-                    <li>
-                        <a href="#contact">Contact</a>
-                    </li>
                 </ul>
                 <p class="copyright text-muted small">Copyright &copy; ungleich glarus ag {% now "Y" %}. {% trans "All Rights Reserved" %}</p>
             </div>
diff --git a/dal/templates/includes/_navbar_transparent.html b/dal/templates/includes/_navbar_transparent.html
index e413ace..1af4bcb 100644
--- a/dal/templates/includes/_navbar_transparent.html
+++ b/dal/templates/includes/_navbar_transparent.html
@@ -2,7 +2,6 @@
 
 <style>
 .container {
-	background-color: lightgrey;
 	color: black;
 }
 </style>
diff --git a/dal/templates/landing.html b/dal/templates/landing.html
index f56d2bb..6f31087 100644
--- a/dal/templates/landing.html
+++ b/dal/templates/landing.html
@@ -1,43 +1,40 @@
 {% extends "base_short.html" %}
-{% load staticfiles  %}
+{% load i18n staticfiles bootstrap3 %}
 
 
 {% block content %}
-
-<style>
-.auth-footer {
-	color: black;
-}
-a:link { color: #000000 }
-</style>
-<div class="auth_container">
-   <div class="auth_bg"></div>
-   <div class="auth_center">
-	<div class="auth_content">
-	    <div class="auth-box">
-		<h2 class="section-heading allcaps"> Login </h2>
-		{% include 'includes/_messages.html' %}
-		<form action={% url 'index' %} method="post" class="form" nonvalidated>
-			{% csrf_token %}
-			<div class="text-center">
-				<div class="form-group"><label class="sr-only control-label" for="username">Username</label><input class="form-control" type="text" name="username" id="username" placeholder="Username"></div>
-				<div class="form-group"><label class="sr-only control-label" for="password">Password</label><input class="form-control" type="password" name="password" id="password" placeholder="Password"></div>
-			   <br><br>
-			   <button type="submit" class="btn choice-btn"> Log in </button>
-			</div>
-		</form>
-		<div class="auth-footer">
-		   <div>
-		       Don't have an account yet?&nbsp;
-		       <a href={% url 'register' %}> Sign up </a>
-		   </div>
-		   <div>
-		       or <a href={% url 'reset_password' %}> Reset your password </a>
-		   </div>
-		</div>
-	     </div>
-	 </div>
-   </div>
-</div>
-
+    <div class="auth-container">
+        <div class="auth-bg"></div>
+        <div class="auth-center">
+            <div class="auth-content">
+                <div class="auth-box">
+                    <h1 class="section-heading allcaps">{% trans "Log in" %}</h1>
+                    {% include 'includes/_messages.html' %}
+                    <form action="{% url 'index' %}" method="post" class="form" novalidated>
+                        {% csrf_token %}
+                        {% for field in form %}
+                            {% bootstrap_field field show_label=False type='fields'%}
+                        {% endfor %}
+                        <p class="red">{{form.non_field_errors|striptags}}</p>
+                        <div class="text-center">
+                            <button type="submit" class="btn choice-btn">
+                                {% trans "Log in" %}
+                            </button>
+                        </div>
+                        <input type='hidden' name='next' value='{{request.GET.next}}'/>
+                    </form>
+                    <div class="auth-footer">
+                        <div>
+                            {% trans "Don't have an account yet ?" %}&nbsp;
+{#                            <a href="{% url 'signup' %}">{% trans "Sign up" %}</a>#}
+                        </div>
+                        <div>
+                            or <a href="{% url 'reset_password' %}">{% trans "Forgot your password ?" %}</a><br>
+{#                            or <a href="{% url 'resend_activation_link' %}">{% trans "Resend activation link" %}</a>#}
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
 {% endblock %}

From eb4dc68b3298b71899ff411aa3fdc7082afa982f Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Tue, 19 Feb 2019 21:21:30 +0100
Subject: [PATCH 10/54] Create logs dir

---
 logs/.keep | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 logs/.keep

diff --git a/logs/.keep b/logs/.keep
new file mode 100644
index 0000000..e69de29

From b60ffe6b5883bb326f6d00b680b94364ba86ba90 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Tue, 19 Feb 2019 23:15:07 +0100
Subject: [PATCH 11/54] Use python-decouple instead of django-dotenv + add
 logging

---
 dal/settings.py  | 58 +++++++++++++++++++++++++++++++++++++++---------
 requirements.txt |  4 ++--
 2 files changed, 49 insertions(+), 13 deletions(-)

diff --git a/dal/settings.py b/dal/settings.py
index 1cc50c3..db939af 100644
--- a/dal/settings.py
+++ b/dal/settings.py
@@ -11,28 +11,25 @@ https://docs.djangoproject.com/en/1.10/ref/settings/
 """
 
 import os
-import dotenv
+from decouple import config, Csv
 import ldap
 from django_auth_ldap.config import LDAPSearch, LDAPSearchUnion
 
-# get config
-dotenv.read_dotenv()
-
 # LDAP setup
-AUTH_LDAP_SERVER_URI = os.environ['LDAPSERVER']
-AUTH_LDAP_BIND_DN = os.environ['LDAPSEARCHUSER']
-AUTH_LDAP_BIND_PASSWORD = os.environ['LDAPSEARCHUSERPASSWORD']
+AUTH_LDAP_SERVER_URI = config('LDAPSERVER')
+AUTH_LDAP_BIND_DN = config('LDAPSEARCHUSER')
+AUTH_LDAP_BIND_PASSWORD = config('LDAPSEARCHUSERPASSWORD')
 
 # Search union over OUs
-search_base = os.environ['LDAPSEARCH'].split()
+search_base = config('LDAPSEARCH').split()
 search_base_ldap = [ LDAPSearch(x, ldap.SCOPE_SUBTREE, "(uid=%(user)s)") for x in search_base ]
 AUTH_LDAP_USER_SEARCH = LDAPSearchUnion(*search_base_ldap)
 
-AUTH_LDAP_START_TLS = os.environ.get('LDAP_USE_TLS', False)
+AUTH_LDAP_START_TLS = config('LDAP_USE_TLS', default=False, cast=bool)
 
 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 
-DEBUG = os.environ.get('DEBUG', False)
+DEBUG = config('DEBUG', default=False, cast=bool)
 
 ALLOWED_HOSTS = (os.environ.get('ALLOWED_HOSTS', 'localhost')).split(",")
 
@@ -133,4 +130,43 @@ DATABASES = {
         'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
     }
 }
-SECRET_KEY = os.environ.get('SECRET_KEY')
+SECRET_KEY = config('SECRET_KEY')
+
+
+LOGGING = {
+    'disable_existing_loggers': False,
+    'version': 1,
+    'formatters': {
+        'standard': {
+            'format': '%(asctime)s %(levelname)s %(name)s: %(message)s'
+        }
+    },
+    'handlers': {
+        'default': {
+            'level': 'DEBUG',
+            'class': 'logging.handlers.RotatingFileHandler',
+            'filename': 'logs/debug.log',
+            'maxBytes': 1024*1024*5,
+            'backupCount': 10,
+            'formatter': 'standard',
+        },
+        'console': {
+            'class': 'logging.StreamHandler',
+        },
+    },
+}
+
+if os.environ.get('ENABLE_DEBUG_LOG', '').strip().lower() == "true":
+    loggers_dict = {}
+    modules_to_log_list = os.environ.get('MODULES_TO_LOG', 'django').split(',')
+    for custom_module in modules_to_log_list:
+        logger_item = {
+            custom_module: {
+                'handlers': ['default'],
+                'level': 'INFO',
+                'propagate': True
+            }
+        }
+        loggers_dict.update(logger_item)
+
+    LOGGING['loggers'] = loggers_dict
diff --git a/requirements.txt b/requirements.txt
index f6d34b1..3f3ab68 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,6 +1,6 @@
 django
 django-auth-ldap
 python-ldap
-django-dotenv
 django-bootstrap3
-django-filter==2.1.0
\ No newline at end of file
+django-filter==2.1.0
+python-decouple

From a6a6f8213b7d872d333152d8494367709435cd92 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Tue, 19 Feb 2019 23:16:05 +0100
Subject: [PATCH 12/54] Add LoginForm

---
 dal/forms.py | 40 ++++++++++++++++++++++++++++++++++++++++
 dal/views.py | 21 +++++----------------
 2 files changed, 45 insertions(+), 16 deletions(-)
 create mode 100644 dal/forms.py

diff --git a/dal/forms.py b/dal/forms.py
new file mode 100644
index 0000000..ecbf9bc
--- /dev/null
+++ b/dal/forms.py
@@ -0,0 +1,40 @@
+from django import forms
+from django.contrib.auth import authenticate
+from django.shortcuts import render
+from django.utils.translation import ugettext_lazy as _
+
+
+class LoginForm(forms.Form):
+    email = forms.CharField(widget=forms.TextInput())
+    password = forms.CharField(widget=forms.PasswordInput())
+
+    class Meta:
+        fields = ['email', 'password']
+
+    def clean(self):
+        email = self.cleaned_data.get('email')
+        password = self.cleaned_data.get('password')
+        if self.errors:
+            return self.cleaned_data
+        is_auth = authenticate(username=email, password=password)
+        if not is_auth:
+            raise forms.ValidationError(
+                _("Your username and/or password were incorrect."))
+        elif is_auth.validated == 0:
+            raise forms.ValidationError(
+                _("Your account is not activated yet."))
+        return self.cleaned_data
+
+    def clean_email(self):
+        email = self.cleaned_data.get('email')
+        return email
+        # try:
+        #     CustomUser.objects.get(email=email)
+        #     return email
+        # except CustomUser.DoesNotExist:
+        #     raise forms.ValidationError(_("User does not exist"))
+
+    def form_valid(self, form):
+        form.save()
+        return render(self.request, 'useroptions.html', {'user': self.get_context_data()})
+
diff --git a/dal/views.py b/dal/views.py
index 0e8cd19..5ef21ad 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -1,6 +1,6 @@
 # Imports from django
 from django.shortcuts import render
-from django.views.generic import View
+from django.views.generic import View, FormView
 from django.contrib.auth import authenticate, login, logout
 from django.contrib.auth.models import User
 from django.http import HttpResponse, HttpResponseRedirect
@@ -9,6 +9,7 @@ from django.urls import reverse_lazy
 from django.contrib.auth.tokens import PasswordResetTokenGenerator
 from django.core.mail import EmailMessage
 from .models import ResetToken
+from .forms import LoginForm
 
 # Imports for the extra stuff not in django
 
@@ -96,21 +97,9 @@ class LDAP(object):
 
         return sorted(uidlist)[-1] + 1
 
-class Index(View):
-    def get(self, request):
-        if request.user.is_authenticated:
-            return render(request, 'useroptions.html', { 'user': request.user } )
-        return render(request, 'landing.html')
-
-    def post(self, request):
-        username = request.POST.get('username')
-        password = request.POST.get('password')
-        pwd = r'%s' % password
-        user = authenticate(request, username=username, password=pwd)
-        if user is not None:
-            login(request, user)
-            return render(request, 'useroptions.html', { 'user': user } )
-        return render(request, 'loginfailed.html')
+class Index(FormView):
+    template_name = "landing.html"
+    form_class = LoginForm
 
 class Register(View):
     def get(self, request):

From 47b714101b3570294c08c08ff7891e8643e235f0 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Tue, 19 Feb 2019 23:39:47 +0100
Subject: [PATCH 13/54] Reformat code

---
 dal/forms.py | 6 ++++--
 dal/urls.py  | 2 +-
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/dal/forms.py b/dal/forms.py
index ecbf9bc..3a0e7e9 100644
--- a/dal/forms.py
+++ b/dal/forms.py
@@ -19,10 +19,12 @@ class LoginForm(forms.Form):
         is_auth = authenticate(username=email, password=password)
         if not is_auth:
             raise forms.ValidationError(
-                _("Your username and/or password were incorrect."))
+                _("Your username and/or password were incorrect.")
+            )
         elif is_auth.validated == 0:
             raise forms.ValidationError(
-                _("Your account is not activated yet."))
+                _("Your account is not activated yet.")
+            )
         return self.cleaned_data
 
     def clean_email(self):
diff --git a/dal/urls.py b/dal/urls.py
index 10875b6..f977499 100644
--- a/dal/urls.py
+++ b/dal/urls.py
@@ -17,4 +17,4 @@ urlpatterns = [
     path('reset/<str:user>/<str:token>/', ResetRequest.as_view()),
     path('reset/', ResetRequest.as_view(), name="reset"),
     path('', Index.as_view(), name="index"),
-]
+]
\ No newline at end of file

From 00bc02541d04d7740ebf408b126b82ea8de7c6e4 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Tue, 19 Feb 2019 23:40:09 +0100
Subject: [PATCH 14/54] Add basic AUTH_LDAP_USER_ATTR_MAP

---
 dal/settings.py | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/dal/settings.py b/dal/settings.py
index db939af..81872b2 100644
--- a/dal/settings.py
+++ b/dal/settings.py
@@ -132,6 +132,11 @@ DATABASES = {
 }
 SECRET_KEY = config('SECRET_KEY')
 
+AUTH_LDAP_USER_ATTR_MAP = {
+    "first_name": "givenName",
+    "last_name": "sn",
+    "email": "mail"
+}
 
 LOGGING = {
     'disable_existing_loggers': False,

From 4d2ee8cf7710aefeb425c066a828124fbf1b76e4 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Wed, 20 Feb 2019 00:25:51 +0100
Subject: [PATCH 15/54] Add UserAccountValidationDetail model

---
 dal/models.py | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/dal/models.py b/dal/models.py
index 7dee319..676b103 100644
--- a/dal/models.py
+++ b/dal/models.py
@@ -1,4 +1,6 @@
 from django.db import models
+from django.contrib.auth.hashers import make_password
+from django.contrib.auth.models import User
 
 # Basic DB to correlate tokens, users and creation time
 
@@ -13,3 +15,18 @@ class ResetToken(models.Model):
     # creation time in epoch (UTC)
     # BigInt just so we are save for the next few decades ;)
     creation = models.BigIntegerField()
+
+
+def get_validation_slug():
+    return make_password(None)
+
+
+class UserAccountValidationDetail(models.Model):
+    user = models.OneToOneField(User, on_delete=models.CASCADE)
+    VALIDATED_CHOICES = ((0, 'Not validated'), (1, 'Validated'))
+    validated = models.IntegerField(choices=VALIDATED_CHOICES, default=0)
+    validation_slug = models.CharField(
+        db_index=True, unique=True, max_length=50,
+        default=get_validation_slug
+    )
+    date_validation_started = models.DateTimeField(auto_now_add=True)

From e8f12e18d2ad6229340c18c97890b14fe0001343 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Fri, 22 Feb 2019 06:06:36 +0100
Subject: [PATCH 16/54] Obtain ALLOWED_HOSTS from config

---
 dal/settings.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dal/settings.py b/dal/settings.py
index 81872b2..867c8db 100644
--- a/dal/settings.py
+++ b/dal/settings.py
@@ -31,7 +31,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 
 DEBUG = config('DEBUG', default=False, cast=bool)
 
-ALLOWED_HOSTS = (os.environ.get('ALLOWED_HOSTS', 'localhost')).split(",")
+ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=Csv())
 
 INSTALLED_APPS = [
     'django.contrib.admin',

From 76c585cdf47d269c41b9025e2e4b5f85a618f824 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sat, 23 Feb 2019 09:19:20 +0100
Subject: [PATCH 17/54] Comment/clean unused code

---
 dal/forms.py | 19 ++++---------------
 1 file changed, 4 insertions(+), 15 deletions(-)

diff --git a/dal/forms.py b/dal/forms.py
index 3a0e7e9..d4bc028 100644
--- a/dal/forms.py
+++ b/dal/forms.py
@@ -1,6 +1,5 @@
 from django import forms
 from django.contrib.auth import authenticate
-from django.shortcuts import render
 from django.utils.translation import ugettext_lazy as _
 
 
@@ -21,22 +20,12 @@ class LoginForm(forms.Form):
             raise forms.ValidationError(
                 _("Your username and/or password were incorrect.")
             )
-        elif is_auth.validated == 0:
-            raise forms.ValidationError(
-                _("Your account is not activated yet.")
-            )
+        # elif is_auth.validated == 0:
+        #     raise forms.ValidationError(
+        #         _("Your account is not activated yet.")
+        #     )
         return self.cleaned_data
 
     def clean_email(self):
         email = self.cleaned_data.get('email')
         return email
-        # try:
-        #     CustomUser.objects.get(email=email)
-        #     return email
-        # except CustomUser.DoesNotExist:
-        #     raise forms.ValidationError(_("User does not exist"))
-
-    def form_valid(self, form):
-        form.save()
-        return render(self.request, 'useroptions.html', {'user': self.get_context_data()})
-

From 5c96f5c186d3f2615cec44402b515410689422e3 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sat, 23 Feb 2019 09:20:58 +0100
Subject: [PATCH 18/54] Add form_valid to the index form

---
 dal/views.py | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/dal/views.py b/dal/views.py
index 5ef21ad..afd0241 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -100,6 +100,16 @@ class LDAP(object):
 class Index(FormView):
     template_name = "landing.html"
     form_class = LoginForm
+    success_url = 'useroptions.html'
+
+    def form_valid(self, form):
+        email = form.cleaned_data.get('email')
+        password = form.cleaned_data.get('password')
+        user = authenticate(username=email, password=password)
+        if user is not None:
+            login(self.request, user)
+            return render(self.request, 'useroptions.html', { 'user': user } )
+        return render(self.request, 'loginfailed.html')
 
 class Register(View):
     def get(self, request):

From a3dca06c35ec5364597e3995dbbc6d88b091e917 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sat, 23 Feb 2019 09:28:56 +0100
Subject: [PATCH 19/54] Use config instead of os.environ

---
 dal/settings.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/dal/settings.py b/dal/settings.py
index 867c8db..6523348 100644
--- a/dal/settings.py
+++ b/dal/settings.py
@@ -161,9 +161,11 @@ LOGGING = {
     },
 }
 
-if os.environ.get('ENABLE_DEBUG_LOG', '').strip().lower() == "true":
+if config('ENABLE_DEBUG_LOG', default=False, cast=bool):
     loggers_dict = {}
-    modules_to_log_list = os.environ.get('MODULES_TO_LOG', 'django').split(',')
+    modules_to_log_list = config(
+        'MODULES_TO_LOG', default='django', cast=Csv()
+    )
     for custom_module in modules_to_log_list:
         logger_item = {
             custom_module: {

From 113fa2c454a6b2458b0d062fd068ba67c3336c09 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sat, 23 Feb 2019 18:45:21 +0100
Subject: [PATCH 20/54] Pickup env variables and use them

---
 dal/settings.py | 17 +++++++++++++++--
 dal/views.py    |  6 +++---
 2 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/dal/settings.py b/dal/settings.py
index 6523348..a716182 100644
--- a/dal/settings.py
+++ b/dal/settings.py
@@ -16,9 +16,16 @@ import ldap
 from django_auth_ldap.config import LDAPSearch, LDAPSearchUnion
 
 # LDAP setup
+LDAP_SERVER = config('LDAP_SERVER')
 AUTH_LDAP_SERVER_URI = config('LDAPSERVER')
-AUTH_LDAP_BIND_DN = config('LDAPSEARCHUSER')
-AUTH_LDAP_BIND_PASSWORD = config('LDAPSEARCHUSERPASSWORD')
+
+LDAP_ADMIN_DN = config('LDAP_ADMIN_DN')
+LDAP_ADMIN_PASSWORD = config('LDAP_ADMIN_PASSWORD')
+AUTH_LDAP_BIND_DN = LDAP_ADMIN_DN
+AUTH_LDAP_BIND_PASSWORD = LDAP_ADMIN_PASSWORD
+
+LDAP_CUSTOMER_DN = config('LDAP_CUSTOMER_DN')
+LDAP_USERS_DN = config('LDAP_USERS_DN')
 
 # Search union over OUs
 search_base = config('LDAPSEARCH').split()
@@ -177,3 +184,9 @@ if config('ENABLE_DEBUG_LOG', default=False, cast=bool):
         loggers_dict.update(logger_item)
 
     LOGGING['loggers'] = loggers_dict
+
+    if 'ldap3' in modules_to_log_list:
+        from ldap3.utils.log import (
+            set_library_log_detail_level, OFF, BASIC, NETWORK, EXTENDED
+        )
+        set_library_log_detail_level(BASIC)
diff --git a/dal/views.py b/dal/views.py
index afd0241..d8443df 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -32,8 +32,8 @@ from django.conf import settings
 class LDAP(object):
     def __init__(self):
         self.uri = settings.AUTH_LDAP_SERVER_URI
-        self.user = settings.AUTH_LDAP_BIND_DN
-        self.password = settings.AUTH_LDAP_BIND_PASSWORD
+        self.user = settings.LDAP_ADMIN_DN
+        self.password = settings.LDAP_ADMIN_PASSWORD
 
         # FIXME: take from settings
         self.search_base = os.environ['LDAPSEARCH']
@@ -41,7 +41,7 @@ class LDAP(object):
         self.search_filter = "objectClass=inetOrgPerson"
 
         # FIXME: hard coded
-        self.dn = "uid={{}},{}".format(os.environ['LDAPCREATE'])
+        self.dn = "uid={{}},{}".format(settings.LDAP_CUSTOMER_DN)
         self.gid = "10004"
 
         self.conn = ldap.initialize(self.uri)

From 6a28b5135400ea3889e0348c22eba2b33712c88d Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sat, 23 Feb 2019 18:45:53 +0100
Subject: [PATCH 21/54] Fix bug: check the posted username also with logged in
 user's username

---
 dal/views.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dal/views.py b/dal/views.py
index d8443df..26f82f9 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -333,7 +333,7 @@ class ResetRequest(View):
         # get the hidden value of user
         user = request.POST.get("user")
         # some checks over the supplied data
-        if user == "" or not user:
+        if user == "" or not user or user != self.request.user.username:
             return render(request, 'error.html', { 'service': service, 'error': 'Something went wrong. Did you use the supplied form?' } )
         if password1 == "" or not password1 or password2 == "" or not password2:
             return render(request, 'error.html', { 'service': service, 'error': 'Please supply a password and confirm it.' } )

From f6f688dcb59c920d1bbaeb7a4152d8dcb3afdf82 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sat, 23 Feb 2019 18:47:01 +0100
Subject: [PATCH 22/54] WIP: Add ungleich_ldap and use it to reset password

---
 dal/ungleich_ldap.py | 144 +++++++++++++++++++++++++++++++++++++++++++
 dal/views.py         |  14 +++--
 2 files changed, 153 insertions(+), 5 deletions(-)
 create mode 100644 dal/ungleich_ldap.py

diff --git a/dal/ungleich_ldap.py b/dal/ungleich_ldap.py
new file mode 100644
index 0000000..7b8bb7a
--- /dev/null
+++ b/dal/ungleich_ldap.py
@@ -0,0 +1,144 @@
+import base64
+import hashlib
+import random
+
+import ldap3
+from django.conf import settings
+
+
+class LdapManager:
+    __instance = None
+    def __new__(cls):
+        if LdapManager.__instance is None:
+            LdapManager.__instance = object.__new__(cls)
+        return LdapManager.__instance
+
+    def __init__(self):
+        """
+        Initialize the LDAP subsystem.
+        """
+        self.rng = random.SystemRandom()
+        self.server = ldap3.Server(settings.AUTH_LDAP_SERVER)
+
+
+    def get_admin_conn(self):
+        """
+        Return a bound :class:`ldap3.Connection` instance which has write
+        permissions on the dn in which the user accounts reside.
+        """
+        conn = self.get_conn(user=settings.LDAP_ADMIN_DN,
+                        password=settings.LDAP_ADMIN_PASSWORD,
+                        raise_exceptions=True)
+        conn.bind()
+        return conn
+
+
+    def get_conn(self, **kwargs):
+        """
+        Return an unbound :class:`ldap3.Connection` which talks to the configured
+        LDAP server.
+
+        The *kwargs* are passed to the constructor of :class:`ldap3.Connection` and
+        can be used to set *user*, *password* and other useful arguments.
+        """
+        return ldap3.Connection(self.server, **kwargs)
+
+
+    def _ssha_password(self, password):
+        """
+        Apply the SSHA password hashing scheme to the given *password*.
+        *password* must be a :class:`bytes` object, containing the utf-8
+        encoded password.
+
+        Return a :class:`bytes` object containing ``ascii``-compatible data
+        which can be used as LDAP value, e.g. after armoring it once more using
+        base64 or decoding it to unicode from ``ascii``.
+        """
+        SALT_BYTES = 15
+
+        sha1 = hashlib.sha1()
+        salt = self.rng.getrandbits(SALT_BYTES * 8).to_bytes(SALT_BYTES,
+                                                               "little")
+        sha1.update(password)
+        sha1.update(salt)
+
+        digest = sha1.digest()
+        passwd = b"{SSHA}" + base64.b64encode(digest + salt)
+        return passwd
+
+
+    def create_user(self, loginname, displayname, mail, password):
+        """
+        Create a new user in the LDAP storage.
+
+        *loginname* must be a unique, valid user id. It is generally safe to
+        pass lower-case ascii letters here. The *loginname* of an account
+        cannot be changed.
+
+        *displayname* is the name which is shown to other users. This can be
+        changed in the future.
+
+        *mail* is a valid mail address of the user.
+
+        *password* is the initial plain text password for the user.
+        """
+
+        conn = self.get_admin_conn()
+        try:
+            conn.add(
+                ("uid={uid}," + settings.LDAP_CUSTOMER_DN).format(uid=loginname),
+                ["inetOrgPerson"],
+                {
+                    "uid": [loginname],
+                    "cn": [displayname],
+                    "sn": ["XXX"],
+                    "givenName": ["XXX"],
+                    "mail": [mail],
+                    "userpassword": [self._ssha_password(
+                        password.encode("utf-8")
+                    )]
+                }
+            )
+        finally:
+            conn.unbind()
+
+
+    def change_password(self, user_dn, new_password):
+        """
+        Changes the password of the user identified by user_dn
+
+        :param user_dn: str The distinguished name for identifying the user
+        :param new_password: str The new password string
+        :return: True if password was changed successfully False otherwise
+        """
+        conn = self.get_admin_conn()
+        return_val = conn.modify(
+            user_dn,
+            {
+                "userpassword": (
+                    ldap3.MODIFY_REPLACE,
+                    [self._ssha_password(new_password.encode("utf-8"))]
+                )
+            }
+        )
+        conn.unbind()
+        return return_val
+
+    def check_user_exists(self, uid, is_customer=True):
+        """
+        Check if the user with the given uid exists in the customer group.
+
+        :param uid: str representing the user
+        :param is_customer: bool representing whether the current user is a
+                            customer. By default, the user is a customer (assume)
+        :return: True if the user exists otherwise return False
+        """
+        conn = self.get_admin_conn()
+        try:
+            result = conn.search(
+                settings.LDAP_CUSTOMER_DN if is_customer else settings.LDAP_USERS_DN,
+                search_filter='(uid={uid})'.format(uid=uid)
+            )
+        finally:
+            conn.unbind()
+        return result
diff --git a/dal/views.py b/dal/views.py
index 26f82f9..8020e44 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -342,11 +342,15 @@ class ResetRequest(View):
         if len(password1) < 8:
             return render(request, 'error.html', { 'service': service, 'error': 'The password is too short, please use a longer one. At least 8 characters.' } )
         # everything checks out, now change the password
-        with get_pool().next() as rpc:
-            pwd = r'%s' % password1
-            result = rpc.changepassword.change_password(user, pwd)
-        # password change successfull
-        if result == True:
+
+        from .ungleich_ldap import LdapManager
+        ldap_manager = LdapManager()
+        result = ldap_manager.change_password(
+            ("uid={uid}," + settings.LDAP_CUSTOMER_DN).format(uid=user),
+            password1
+        )
+        # password change successful
+        if result:
             return render(request, 'changedpassword.html', { 'user': user } )
         # Something went wrong while changing the password
         else:

From 122ee37e48fc759cd425c510dcaf02da03321a28 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sat, 23 Feb 2019 19:50:42 +0100
Subject: [PATCH 23/54] Use LdapManager to change password

---
 dal/settings.py |  1 +
 dal/views.py    | 12 +++++++-----
 2 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/dal/settings.py b/dal/settings.py
index a716182..8ba5c15 100644
--- a/dal/settings.py
+++ b/dal/settings.py
@@ -23,6 +23,7 @@ LDAP_ADMIN_DN = config('LDAP_ADMIN_DN')
 LDAP_ADMIN_PASSWORD = config('LDAP_ADMIN_PASSWORD')
 AUTH_LDAP_BIND_DN = LDAP_ADMIN_DN
 AUTH_LDAP_BIND_PASSWORD = LDAP_ADMIN_PASSWORD
+AUTH_LDAP_SERVER = AUTH_LDAP_SERVER_URI
 
 LDAP_CUSTOMER_DN = config('LDAP_CUSTOMER_DN')
 LDAP_USERS_DN = config('LDAP_USERS_DN')
diff --git a/dal/views.py b/dal/views.py
index 8020e44..419e3b0 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -405,12 +405,14 @@ class ChangePassword(View):
         if len(password1) < 8:
             return render(request, 'error.html', { 'urlname': urlname, 'service': service,
                 'error': 'The password is too short, please use a longer one. At least 8 characters.' } )
-        with get_pool().next() as rpc:
-            # Trying to change the password
-            pwd = r'%s' % password1
-            result = rpc.changepassword.change_password(user, pwd)
+        from .ungleich_ldap import LdapManager
+        ldap_manager = LdapManager()
+        result = ldap_manager.change_password(
+            ("uid={uid}," + settings.LDAP_CUSTOMER_DN).format(uid=user),
+            password1
+        )
         # Password was changed
-        if result == True:
+        if result:
             return render(request, 'changedpassword.html', { 'user': user } )
         # Password not changed, instead got some kind of error
         else:

From fc139296fb3e557ef262afb8d262f86fae55b477 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sat, 23 Feb 2019 21:25:15 +0100
Subject: [PATCH 24/54] Add dal/ldap_max_uid_file to .gitignore

---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitignore b/.gitignore
index 712a31c..38b9c32 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,3 +39,4 @@ secret-key
 *.mo
 
 venv/
+dal/ldap_max_uid_file

From 0976d0dbcb478f4ab079d63846dd608d3423bb17 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sat, 23 Feb 2019 21:25:58 +0100
Subject: [PATCH 25/54] Obtain some LDAP configs from env

---
 dal/settings.py | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/dal/settings.py b/dal/settings.py
index 8ba5c15..95c1b56 100644
--- a/dal/settings.py
+++ b/dal/settings.py
@@ -27,6 +27,15 @@ AUTH_LDAP_SERVER = AUTH_LDAP_SERVER_URI
 
 LDAP_CUSTOMER_DN = config('LDAP_CUSTOMER_DN')
 LDAP_USERS_DN = config('LDAP_USERS_DN')
+LDAP_CUSTOMER_GROUP_ID = config('LDAP_CUSTOMER_GROUP_ID', cast=int)
+
+LDAP_MAX_UID_FILE_PATH = config(
+    'LDAP_MAX_UID_FILE_PATH',
+    default=os.path.join(os.path.abspath(
+        os.path.dirname(__file__)), 'ldap_max_uid_file'
+    )
+)
+LDAP_DEFAULT_START_UID = config('LDAP_DEFAULT_START_UID', cast=int)
 
 # Search union over OUs
 search_base = config('LDAPSEARCH').split()

From ac89df9254528fe235172a6dbcda7cbb10ac2b56 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sat, 23 Feb 2019 21:27:23 +0100
Subject: [PATCH 26/54] Add complete implementation of create_user

---
 dal/ungleich_ldap.py | 112 +++++++++++++++++++++++++++++++++----------
 1 file changed, 86 insertions(+), 26 deletions(-)

diff --git a/dal/ungleich_ldap.py b/dal/ungleich_ldap.py
index 7b8bb7a..54e8eee 100644
--- a/dal/ungleich_ldap.py
+++ b/dal/ungleich_ldap.py
@@ -4,6 +4,9 @@ import random
 
 import ldap3
 from django.conf import settings
+import logging
+
+logger = logging.getLogger(__name__)
 
 
 class LdapManager:
@@ -67,38 +70,53 @@ class LdapManager:
         return passwd
 
 
-    def create_user(self, loginname, displayname, mail, password):
-        """
-        Create a new user in the LDAP storage.
-
-        *loginname* must be a unique, valid user id. It is generally safe to
-        pass lower-case ascii letters here. The *loginname* of an account
-        cannot be changed.
-
-        *displayname* is the name which is shown to other users. This can be
-        changed in the future.
-
-        *mail* is a valid mail address of the user.
-
-        *password* is the initial plain text password for the user.
-        """
-
+    def create_user(self, user, password, firstname, lastname, email):
         conn = self.get_admin_conn()
+        uidNumber = self._get_max_uid() + 1
+        logger.debug("uidNumber={uidNumber}".format(uidNumber=uidNumber))
+        results = True
+        while results:
+            results = self.check_user_exists(
+                "",
+                True,
+                '(&(objectClass=inetOrgPerson)(objectClass=posixAccount)'
+                '(objectClass=top)(uidNumber={uidNumber}))'.format(
+                    uidNumber=uidNumber
+                )
+            )
+            if results:
+                logger.debug(
+                    "{uid} exists. Trying next.".format(uid=uidNumber)
+                )
+                uidNumber += 1
+        logger.debug("{uid} does not exist. Using it".format(uid=uidNumber))
+        self._set_max_uid(uidNumber)
         try:
             conn.add(
-                ("uid={uid}," + settings.LDAP_CUSTOMER_DN).format(uid=loginname),
-                ["inetOrgPerson"],
+                ("uid={uid}," + settings.LDAP_CUSTOMER_DN).format(uid=user),
+                ["inetOrgPerson", "posixAccount", "ldapPublickey"],
                 {
-                    "uid": [loginname],
-                    "cn": [displayname],
-                    "sn": ["XXX"],
-                    "givenName": ["XXX"],
-                    "mail": [mail],
-                    "userpassword": [self._ssha_password(
+                    "uid": [user.encode("utf-8")],
+                    "sn": [lastname.encode("utf-8")],
+                    "givenName": [firstname.encode("utf-8")],
+                    "cn": ["{} {}".format(firstname, lastname).encode("utf-8")],
+                    "displayName": ["{} {}".format(firstname, lastname).encode("utf-8")],
+                    "uidNumber": [str(uidNumber)],
+                    "gidNumber": [str(settings.LDAP_CUSTOMER_GROUP_ID)],
+                    "loginShell": ["/bin/bash"],
+                    "homeDirectory": ["/home/{}".format(user).encode("utf-8")],
+                    "mail": email.encode("utf-8"),
+                    "userPassword": [self._ssha_password(
                         password.encode("utf-8")
                     )]
                 }
             )
+            logger.debug('Created user %s %s' % (user.encode('utf-8'),
+                                                 uidNumber))
+        except Exception as ex:
+            logger.debug('Could not create user %s' % user.encode('utf-8'))
+            logger.error("Exception: " + str(ex))
+            raise Exception(ex)
         finally:
             conn.unbind()
 
@@ -124,21 +142,63 @@ class LdapManager:
         conn.unbind()
         return return_val
 
-    def check_user_exists(self, uid, is_customer=True):
+    def check_user_exists(self, uid, is_customer=True, search_filter=""):
         """
         Check if the user with the given uid exists in the customer group.
 
         :param uid: str representing the user
         :param is_customer: bool representing whether the current user is a
                             customer. By default, the user is a customer (assume)
+        :param search_filter: str representing the filter condition to find
+                            users. If its empty, the search finds the user with
+                            the given uid.
         :return: True if the user exists otherwise return False
         """
         conn = self.get_admin_conn()
         try:
             result = conn.search(
                 settings.LDAP_CUSTOMER_DN if is_customer else settings.LDAP_USERS_DN,
-                search_filter='(uid={uid})'.format(uid=uid)
+                search_filter=search_filter if len(search_filter)> 0 else
+                '(uid={uid})'.format(uid=uid)
             )
         finally:
             conn.unbind()
         return result
+
+    def _set_max_uid(self, max_uid):
+        """
+        a utility function to save max_uid value to a file
+
+        :param max_uid: an integer representing the max uid
+        :return:
+        """
+        with open(settings.LDAP_MAX_UID_FILE_PATH, 'w+') as handler:
+            handler.write(str(max_uid))
+
+    def _get_max_uid(self):
+        """
+        A utility function to read the max uid value that was previously set
+
+        :return: An integer representing the max uid value that was previously
+         set
+        """
+        try:
+            with open(settings.LDAP_MAX_UID_FILE_PATH, 'r+') as handler:
+                try:
+                    return_value = int(handler.read())
+                except ValueError as ve:
+                    logger.error(
+                        "Error reading int value from {}. {}"
+                        "Returning default value {} instead".format(
+                            settings.LDAP_MAX_UID_PATH,
+                            str(ve),
+                            settings.LDAP_DEFAULT_START_UID
+                        )
+                    )
+                    return_value = settings.LDAP_DEFAULT_START_UID
+                return return_value
+        except FileNotFoundError as fnfe:
+            logger.error("File not found : " + str(fnfe))
+            return_value = settings.LDAP_DEFAULT_START_UID
+            logger.error("So, returning UID={}".format(return_value))
+            return return_value

From 57fe6a01432d95c257671efe16f24a1f436dad63 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sat, 23 Feb 2019 21:29:33 +0100
Subject: [PATCH 27/54] Call create_user code

---
 dal/views.py | 81 ++++------------------------------------------------
 1 file changed, 5 insertions(+), 76 deletions(-)

diff --git a/dal/views.py b/dal/views.py
index 419e3b0..a1ff4a2 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -10,6 +10,7 @@ from django.contrib.auth.tokens import PasswordResetTokenGenerator
 from django.core.mail import EmailMessage
 from .models import ResetToken
 from .forms import LoginForm
+from .ungleich_ldap import LdapManager
 
 # Imports for the extra stuff not in django
 
@@ -28,75 +29,6 @@ import ldap.modlist as modlist
 from django.conf import settings
 
 
-
-class LDAP(object):
-    def __init__(self):
-        self.uri = settings.AUTH_LDAP_SERVER_URI
-        self.user = settings.LDAP_ADMIN_DN
-        self.password = settings.LDAP_ADMIN_PASSWORD
-
-        # FIXME: take from settings
-        self.search_base = os.environ['LDAPSEARCH']
-        self.search_scope = ldap.SCOPE_SUBTREE
-        self.search_filter = "objectClass=inetOrgPerson"
-
-        # FIXME: hard coded
-        self.dn = "uid={{}},{}".format(settings.LDAP_CUSTOMER_DN)
-        self.gid = "10004"
-
-        self.conn = ldap.initialize(self.uri)
-        if settings.AUTH_LDAP_START_TLS:
-            self.conn.start_tls_s()
-
-        self.conn.bind_s(self.user, self.password)
-
-
-    def check_user_exists(self, username):
-        exists = False
-
-        result = self.conn.search_s(self.search_base,
-                                    self.search_scope,
-                                    self.dn.format(username))
-        if len(result) > 0:
-            exists = True
-
-        return exists
-
-    def create_user(self, user, password, firstname, lastname, email):
-        dn = self.dn.format(user)
-        attr = {
-            "objectClass": ["inetOrgPerson".encode("utf-8"),
-                            "posixAccount".encode("utf-8"),
-                            "ldapPublickey".encode("utf-8")],
-            "uid": [user.encode("utf-8")],
-            "sn": [lastname.encode("utf-8")],
-            "givenName": [firstname.encode("utf-8")],
-            "cn": ["{} {}".format(firstname, lastname).encode("utf-8")],
-            "displayName": ["{} {}".format(firstname, lastname).encode("utf-8")],
-            "uidNumber": ["{}".format(self.get_new_uid_number()).encode("utf-8")],
-            "gidNumber": [self.gid.encode("utf-8")],
-            "loginShell": ["/bin/bash".encode("utf-8")],
-            "homeDirectory": ["/home/{}".format(user).encode("utf-8")],
-            "mail": email.encode("utf-8"),
-            "userPassword": password.encode("utf-8")
-        }
-
-        ldif = modlist.addModlist(attr)
-
-        print("just before: {} {}".format(dn, ldif))
-        return self.conn.add_s(dn, ldif)
-
-    def get_new_uid_number(self):
-        uidlist = [0]
-
-        for result in self.conn.search_s(self.search_base,
-                                         self.search_scope,
-                                         self.search_filter):
-            if 'uidNumber' in result[1]:
-                uidlist.append(int(result[1]['uidNumber'][0]))
-
-        return sorted(uidlist)[-1] + 1
-
 class Index(FormView):
     template_name = "landing.html"
     form_class = LoginForm
@@ -117,8 +49,6 @@ class Register(View):
 
     # Someone filled out the register page, do some basic checks and throw it at nameko
     def post(self, request):
-        l = LDAP()
-
         service = 'register an user'
         urlname = 'register'
         username = request.POST.get('username')
@@ -126,9 +56,6 @@ class Register(View):
         if username == "" or not username:
             return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Please supply a username.' } )
 
-        if l.check_user_exists(username):
-            return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'User already exists.' } )
-
         password1 = request.POST.get('password1')
         password2 = request.POST.get('password2')
         if password1 != password2:
@@ -155,7 +82,10 @@ class Register(View):
         pwd = r'%s' % password1
 
         try:
-            l.create_user(username, pwd, firstname, lastname, email)
+            ldap_manager = LdapManager()
+            ldap_manager.create_user(
+                username, pwd, firstname, lastname, email
+            )
         except Exception as e:
             return render(request, 'error.html', { 'urlname': urlname,
                                                    'service': service,
@@ -343,7 +273,6 @@ class ResetRequest(View):
             return render(request, 'error.html', { 'service': service, 'error': 'The password is too short, please use a longer one. At least 8 characters.' } )
         # everything checks out, now change the password
 
-        from .ungleich_ldap import LdapManager
         ldap_manager = LdapManager()
         result = ldap_manager.change_password(
             ("uid={uid}," + settings.LDAP_CUSTOMER_DN).format(uid=user),

From 89b535c3d60828330b6b1a6081012aaacebc9b27 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sat, 23 Feb 2019 21:37:27 +0100
Subject: [PATCH 28/54] Add ldap3 requirement

---
 requirements.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/requirements.txt b/requirements.txt
index 3f3ab68..c68b636 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,3 +4,4 @@ python-ldap
 django-bootstrap3
 django-filter==2.1.0
 python-decouple
+ldap3

From 017ca767bee2cf3aafca1398b0de1303b04c4ced Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 14:43:24 +0100
Subject: [PATCH 29/54] Also return entries in the ldap search result

---
 dal/ungleich_ldap.py | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/dal/ungleich_ldap.py b/dal/ungleich_ldap.py
index 54e8eee..24566fa 100644
--- a/dal/ungleich_ldap.py
+++ b/dal/ungleich_ldap.py
@@ -74,9 +74,9 @@ class LdapManager:
         conn = self.get_admin_conn()
         uidNumber = self._get_max_uid() + 1
         logger.debug("uidNumber={uidNumber}".format(uidNumber=uidNumber))
-        results = True
-        while results:
-            results = self.check_user_exists(
+        user_exists = True
+        while user_exists:
+            user_exists, _ = self.check_user_exists(
                 "",
                 True,
                 '(&(objectClass=inetOrgPerson)(objectClass=posixAccount)'
@@ -84,7 +84,7 @@ class LdapManager:
                     uidNumber=uidNumber
                 )
             )
-            if results:
+            if user_exists:
                 logger.debug(
                     "{uid} exists. Trying next.".format(uid=uidNumber)
                 )
@@ -155,15 +155,17 @@ class LdapManager:
         :return: True if the user exists otherwise return False
         """
         conn = self.get_admin_conn()
+        entries = []
         try:
             result = conn.search(
                 settings.LDAP_CUSTOMER_DN if is_customer else settings.LDAP_USERS_DN,
                 search_filter=search_filter if len(search_filter)> 0 else
                 '(uid={uid})'.format(uid=uid)
             )
+            entries = conn.entries
         finally:
             conn.unbind()
-        return result
+        return result, entries
 
     def _set_max_uid(self, max_uid):
         """

From 3a867a4cd1b603e0a562ad07676f7fa32bb67202 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 15:25:59 +0100
Subject: [PATCH 30/54] Update check_user_exists to accept attributes and add
 doc

---
 dal/ungleich_ldap.py | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/dal/ungleich_ldap.py b/dal/ungleich_ldap.py
index 24566fa..5e31b38 100644
--- a/dal/ungleich_ldap.py
+++ b/dal/ungleich_ldap.py
@@ -142,7 +142,8 @@ class LdapManager:
         conn.unbind()
         return return_val
 
-    def check_user_exists(self, uid, is_customer=True, search_filter=""):
+    def check_user_exists(self, uid, is_customer=True, search_filter="",
+                          attributes=None):
         """
         Check if the user with the given uid exists in the customer group.
 
@@ -152,7 +153,11 @@ class LdapManager:
         :param search_filter: str representing the filter condition to find
                             users. If its empty, the search finds the user with
                             the given uid.
-        :return: True if the user exists otherwise return False
+        :param attributes: list A list of str representing all the attributes
+                           to be obtained in the result entries
+        :return: tuple (bool, [ldap3.abstract.entry.Entry ..])
+                       A bool indicating if the user exists
+                       A list of all entries obtained in the search
         """
         conn = self.get_admin_conn()
         entries = []
@@ -160,7 +165,8 @@ class LdapManager:
             result = conn.search(
                 settings.LDAP_CUSTOMER_DN if is_customer else settings.LDAP_USERS_DN,
                 search_filter=search_filter if len(search_filter)> 0 else
-                '(uid={uid})'.format(uid=uid)
+                '(uid={uid})'.format(uid=uid),
+                attributes=attributes
             )
             entries = conn.entries
         finally:

From 3f7ab047a50e69aa3c520c74fc9eb628812a0e78 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 15:29:40 +0100
Subject: [PATCH 31/54] Use LdapManager call in change user details page

---
 dal/views.py | 32 +++++++++++++++++++++++---------
 1 file changed, 23 insertions(+), 9 deletions(-)

diff --git a/dal/views.py b/dal/views.py
index a1ff4a2..a4e02f0 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -101,16 +101,30 @@ class ChangeData(View):
         if not request.user.is_authenticated:
             return render(request, 'mustbeloggedin.html')
         user = request.user
-        login(request, user)
-        # get basic data (firstname, lastname, email)
-        with get_pool().next() as rpc:
-            (state, firstname, lastname, email) = rpc.getuserdata.get_data(str(request.user))
-        # If it throws an error, the errormessage gets put into firstname.. not great naming, but works best this way
-        if state == "error":
-            return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': firstname } )
-        # The template puts the old data as standard in the fields
+
+        ldap_manager = LdapManager()
+        user_exists, entries = ldap_manager.check_user_exists(
+            uid=user.username,
+            is_customer=True,
+            attributes=['uid', 'givenName', 'sn', 'email']
+        )
+
+        if user_exists:
+            return render(
+                request,
+                'changeuserdata.html',
+                { 'user': user.username,
+                  'firstname': entries[0].givenName
+                            if entries[0].givenName.value is not None else '',
+                  'lastname': entries[0].sn
+                            if entries[0].sn.value is not None else '',
+                  'email': entries[0].email
+                            if entries[0].email.value is not None else ''}
+            )
         else:
-            return render(request, 'changeuserdata.html', { 'user': str(request.user), 'firstname': firstname, 'lastname': lastname, 'email': email } )
+            return render(request, 'error.html',
+                          {'urlname': urlname, 'service': service,
+                           'error': request.user.username})
 
     # get the change request
     def post(self, request):

From 7d09819ccbe07f72acf868c951024e7e0d879721 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 17:23:41 +0100
Subject: [PATCH 32/54] Improve logging

---
 dal/settings.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dal/settings.py b/dal/settings.py
index 95c1b56..137c914 100644
--- a/dal/settings.py
+++ b/dal/settings.py
@@ -160,7 +160,7 @@ LOGGING = {
     'version': 1,
     'formatters': {
         'standard': {
-            'format': '%(asctime)s %(levelname)s %(name)s: %(message)s'
+            'format': '%(asctime)s %(levelname)s %(name)s %(funcName)s %(lineno)d: %(message)s'
         }
     },
     'handlers': {

From 3bc2e0a7e519b88813dbef2c173ca1e530cd2417 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 17:24:44 +0100
Subject: [PATCH 33/54] Take uid as parameter for change_password instead of
 user_dn

---
 dal/ungleich_ldap.py | 6 +++---
 dal/views.py         | 4 ++--
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/dal/ungleich_ldap.py b/dal/ungleich_ldap.py
index 5e31b38..c85ba48 100644
--- a/dal/ungleich_ldap.py
+++ b/dal/ungleich_ldap.py
@@ -121,17 +121,17 @@ class LdapManager:
             conn.unbind()
 
 
-    def change_password(self, user_dn, new_password):
+    def change_password(self, uid, new_password):
         """
         Changes the password of the user identified by user_dn
 
-        :param user_dn: str The distinguished name for identifying the user
+        :param uid: str The uid that identifies the user
         :param new_password: str The new password string
         :return: True if password was changed successfully False otherwise
         """
         conn = self.get_admin_conn()
         return_val = conn.modify(
-            user_dn,
+            ("uid={uid}," + settings.LDAP_CUSTOMER_DN).format(uid=uid),
             {
                 "userpassword": (
                     ldap3.MODIFY_REPLACE,
diff --git a/dal/views.py b/dal/views.py
index a4e02f0..e9793b8 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -289,7 +289,7 @@ class ResetRequest(View):
 
         ldap_manager = LdapManager()
         result = ldap_manager.change_password(
-            ("uid={uid}," + settings.LDAP_CUSTOMER_DN).format(uid=user),
+            user,
             password1
         )
         # password change successful
@@ -351,7 +351,7 @@ class ChangePassword(View):
         from .ungleich_ldap import LdapManager
         ldap_manager = LdapManager()
         result = ldap_manager.change_password(
-            ("uid={uid}," + settings.LDAP_CUSTOMER_DN).format(uid=user),
+            user,
             password1
         )
         # Password was changed

From a909a9b5c5f14761f57973a334fac28013369564 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 17:25:13 +0100
Subject: [PATCH 34/54] Add change_user_details

---
 dal/ungleich_ldap.py | 27 +++++++++++++++++++++++++++
 dal/views.py         | 23 +++++++++++++----------
 2 files changed, 40 insertions(+), 10 deletions(-)

diff --git a/dal/ungleich_ldap.py b/dal/ungleich_ldap.py
index c85ba48..2ee70c5 100644
--- a/dal/ungleich_ldap.py
+++ b/dal/ungleich_ldap.py
@@ -142,6 +142,33 @@ class LdapManager:
         conn.unbind()
         return return_val
 
+    def change_user_details(self, uid, details):
+        """
+        Updates the user details as per given values in kwargs of the user
+        identified by user_dn.
+
+        Assumes that all attributes passed in kwargs are valid.
+
+        :param uid: str The uid that identifies the user
+        :param details: dict A dictionary containing the new values
+        :return: True if user details were updated successfully False otherwise
+        """
+        conn = self.get_admin_conn()
+        details_dict = {k: (ldap3.MODIFY_REPLACE, [v.encode("utf-8")]) for k, v in details.items()}
+        try:
+            return_val = conn.modify(
+                ("uid={uid}," + settings.LDAP_CUSTOMER_DN).format(uid=uid),
+                details_dict
+            )
+            msg = "success"
+        except Exception as ex:
+            msg = str(ex)
+            logger.error("Exception: " + msg)
+            return_val = False
+        finally:
+            conn.unbind()
+        return return_val, msg
+
     def check_user_exists(self, uid, is_customer=True, search_filter="",
                           attributes=None):
         """
diff --git a/dal/views.py b/dal/views.py
index e9793b8..e03a634 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -106,7 +106,7 @@ class ChangeData(View):
         user_exists, entries = ldap_manager.check_user_exists(
             uid=user.username,
             is_customer=True,
-            attributes=['uid', 'givenName', 'sn', 'email']
+            attributes=['uid', 'givenName', 'sn', 'mail']
         )
 
         if user_exists:
@@ -118,8 +118,8 @@ class ChangeData(View):
                             if entries[0].givenName.value is not None else '',
                   'lastname': entries[0].sn
                             if entries[0].sn.value is not None else '',
-                  'email': entries[0].email
-                            if entries[0].email.value is not None else ''}
+                  'email': entries[0].mail
+                            if entries[0].mail.value is not None else ''}
             )
         else:
             return render(request, 'error.html',
@@ -136,7 +136,6 @@ class ChangeData(View):
         if not request.user.is_authenticated:
             return render(request, 'mustbeloggedin.html')
 
-        user = str(request.user)
         firstname = request.POST.get('firstname')
         lastname = request.POST.get('lastname')
         email = request.POST.get('email')
@@ -152,15 +151,19 @@ class ChangeData(View):
             validate_email(email)
         except ValidationError:
             return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'The supplied email address is invalid.' } )
-        # Trying to change the data
-        with get_pool().next() as rpc:
-            result = rpc.changeuserdata.change_data(user, firstname, lastname, email)
+
+        ldap_manager = LdapManager()
+        result, msg = ldap_manager.change_user_details(
+            uid=request.user.username,
+            details={"givenName": firstname, "sn": lastname, "mail": email}
+        )
+
         # Data change worked
-        if result == True:
-            return render(request, 'changeddata.html', { 'user': user, 'firstname': firstname, 'lastname': lastname, 'email': email } )
+        if result:
+            return render(request, 'changeddata.html', { 'user': request.user.username, 'firstname': firstname, 'lastname': lastname, 'email': email } )
         # Data change did not work, display error
         else:
-            return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': result } )
+            return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': msg } )
 
 
 class ResetPassword(View):

From 4e9493f1980336c9e87bcaf68757413d4270717a Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 17:44:48 +0100
Subject: [PATCH 35/54] Add delete_user

---
 dal/ungleich_ldap.py | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/dal/ungleich_ldap.py b/dal/ungleich_ldap.py
index 2ee70c5..5d56d2a 100644
--- a/dal/ungleich_ldap.py
+++ b/dal/ungleich_ldap.py
@@ -200,6 +200,27 @@ class LdapManager:
             conn.unbind()
         return result, entries
 
+    def delete_user(self, uid):
+        """
+        Deletes the user with the given uid from ldap
+
+        :param uid: str representing the user
+        :return: True if the delete was successful False otherwise
+        """
+        conn = self.get_admin_conn()
+        try:
+            return_val = conn.delete(
+                ("uid={uid}," + settings.LDAP_CUSTOMER_DN).format(uid=uid),
+            )
+            msg = "success"
+        except Exception as ex:
+            msg = str(ex)
+            logger.error("Exception: " + msg)
+            return_val = False
+        finally:
+            conn.unbind()
+        return return_val, msg
+
     def _set_max_uid(self, max_uid):
         """
         a utility function to save max_uid value to a file

From db4ffe79798ff292d35445466a8f04c0d6b5e7e0 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 17:45:39 +0100
Subject: [PATCH 36/54] Use LdapManager delete_user to delete the user's
 account

---
 dal/views.py | 39 +++++++++++++++++++++------------------
 1 file changed, 21 insertions(+), 18 deletions(-)

diff --git a/dal/views.py b/dal/views.py
index e03a634..4c76c13 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -379,24 +379,27 @@ class DeleteAccount(View):
 
         # Does the user exist?
         username = request.POST.get('username')
-        if not check_user_exists(username):
-            return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Unknown user.' } )
-
-        # Do user and password match?
-        password = request.POST.get('password')
-        pwd = r'%s' % password
-        check = authenticate(request, username=username, password=pwd)
-        if check is None:
-            return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Wrong password for user.' } )
-
-        # Try to delete the user
-        with get_pool().next() as rpc:
-            result = rpc.deleteuser.delete_user(username)
-        # User deleted
-        if result == True:
-            logout(request)
-            return render(request, 'deleteduser.html', { 'user': username } )
-        # User not deleted, got some kind of error
+        ldap_manager = LdapManager()
+        user_exists, user_details = ldap_manager.check_user_exists(username)
+        if user_exists and request.user.username == username:
+            # Do user and password match?
+            password = request.POST.get('password')
+            pwd = r'%s' % password
+            check = authenticate(request, username=username, password=pwd)
+            if check is None:
+                return render(request, 'error.html',
+                              {'urlname': urlname, 'service': service,
+                               'error': 'Wrong password for user.'})
+            result = ldap_manager.delete_user(username)
+            # User deleted
+            if result:
+                logout(request)
+                return render(request, 'deleteduser.html', {'user': username})
+            # User not deleted, got some kind of error
+            else:
+                return render(request, 'error.html',
+                              {'urlname': urlname, 'service': service,
+                               'error': result})
         else:
             return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': result } )
 

From 6e0788097f44a7e9e3f0ba739eeb1ed39e44f0a5 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 17:46:44 +0100
Subject: [PATCH 37/54] Update message

---
 dal/views.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dal/views.py b/dal/views.py
index 4c76c13..f697c90 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -401,7 +401,7 @@ class DeleteAccount(View):
                               {'urlname': urlname, 'service': service,
                                'error': result})
         else:
-            return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': result } )
+            return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Unknown user.' } )
 
 # Log out the session
 class LogOut(View):

From ccf600b6208ee1c1c18c2f2ab805dfdf5b3a090e Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 18:37:40 +0100
Subject: [PATCH 38/54] Add initial migration for dal

---
 dal/migrations/0001_initial.py | 37 ++++++++++++++++++++++++++++++++++
 dal/migrations/__init__.py     |  0
 2 files changed, 37 insertions(+)
 create mode 100644 dal/migrations/0001_initial.py
 create mode 100644 dal/migrations/__init__.py

diff --git a/dal/migrations/0001_initial.py b/dal/migrations/0001_initial.py
new file mode 100644
index 0000000..936a832
--- /dev/null
+++ b/dal/migrations/0001_initial.py
@@ -0,0 +1,37 @@
+# Generated by Django 2.1.7 on 2019-02-24 17:35
+
+import dal.models
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='ResetToken',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('user', models.CharField(max_length=100)),
+                ('token', models.CharField(max_length=255)),
+                ('creation', models.BigIntegerField()),
+            ],
+        ),
+        migrations.CreateModel(
+            name='UserAccountValidationDetail',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('validated', models.IntegerField(choices=[(0, 'Not validated'), (1, 'Validated')], default=0)),
+                ('validation_slug', models.CharField(db_index=True, default=dal.models.get_validation_slug, max_length=50, unique=True)),
+                ('date_validation_started', models.DateTimeField(auto_now_add=True)),
+                ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+            ],
+        ),
+    ]
diff --git a/dal/migrations/__init__.py b/dal/migrations/__init__.py
new file mode 100644
index 0000000..e69de29

From 9ce45e6f56b645fdb440ebb3c22c950a5ec65dd1 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 18:41:07 +0100
Subject: [PATCH 39/54] Set EMAIL_FROM_ADDRESS from env

---
 dal/settings.py | 2 ++
 dal/views.py    | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/dal/settings.py b/dal/settings.py
index 137c914..b1210b1 100644
--- a/dal/settings.py
+++ b/dal/settings.py
@@ -48,6 +48,8 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 
 DEBUG = config('DEBUG', default=False, cast=bool)
 
+EMAIL_FROM_ADDRESS = config('EMAIL_FROM_ADDRESS')
+
 ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=Csv())
 
 INSTALLED_APPS = [
diff --git a/dal/views.py b/dal/views.py
index f697c90..2ea6dfb 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -197,7 +197,7 @@ class ResetPassword(View):
         # getting epoch for the time now in UTC to spare us headache with timezones
         creationtime = int(datetime.utcnow().timestamp())
         # Construct the data for the email
-        email_from = 'Userservice at ungleich <%s>' % config['EMAIL']['EMAILFROM']
+        email_from = settings.EMAIL_FROM_ADDRESS
         to = ['%s <%s>' % (user, email)]
         subject = 'Password reset request for %s' % user
         link = self.build_reset_link(user, creationtime)

From 16b02cfe3f81f26714e41f63cb93213285ec9d73 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 18:42:02 +0100
Subject: [PATCH 40/54] Create base_url from request rather than hard code

---
 dal/views.py | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/dal/views.py b/dal/views.py
index 2ea6dfb..18ff70d 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -193,14 +193,14 @@ class ResetPassword(View):
             return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': emailsend } )
 
     # Sends an email to the user with the 24h active link for a password reset
-    def email(self, user, email):
+    def email(self, user, email, base_url):
         # getting epoch for the time now in UTC to spare us headache with timezones
         creationtime = int(datetime.utcnow().timestamp())
         # Construct the data for the email
         email_from = settings.EMAIL_FROM_ADDRESS
         to = ['%s <%s>' % (user, email)]
         subject = 'Password reset request for %s' % user
-        link = self.build_reset_link(user, creationtime)
+        link = self.build_reset_link(user, creationtime, base_url)
         body = 'This is an automated email which was triggered by a reset request for the user %s. Please do not reply to this email.\n' % user
         body += 'If you received this email in error, please disregard it. If you get multiple emails like this, please contact us to look into potential abuse.\n'
         body += 'To reset your password, please follow the link below:\n'
@@ -221,9 +221,8 @@ class ResetPassword(View):
         return result
 
     # Builds the reset link for the email and puts the token into the database
-    def build_reset_link(self, user, epochutc):
+    def build_reset_link(self, user, epochutc, base_url):
         # set up the data
-        host = 'account-staging.ungleich.ch'
         tokengen = PasswordResetTokenGenerator()
         # create some noise for use in the tokengenerator
         pseudouser = PseudoUser()
@@ -234,7 +233,7 @@ class ResetPassword(View):
         newdbentry = ResetToken(user=user, token=token, creation=epochutc)
         newdbentry.save()
         # set up the link
-        link = 'https://%s/reset/%s/%s/' % (host, userpart.decode('utf-8'), token)
+        link = (base_url + '/reset/%s/%s/') % (userpart.decode('utf-8'), token)
         return link
 
 

From acff3fc59213239cb4abf54db74d6810bbdf87bd Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 18:42:27 +0100
Subject: [PATCH 41/54] Use LdapManager in password reset too

---
 dal/views.py | 54 +++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 39 insertions(+), 15 deletions(-)

diff --git a/dal/views.py b/dal/views.py
index 18ff70d..334a197 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -175,22 +175,46 @@ class ResetPassword(View):
         service = 'send a password reset request'
         user = request.POST.get('user')
         # First, check if the user exists
-        if not check_user_exists(user):
-            return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'The user does not exist.' } )
-        # user exists, so try to get email
-        with get_pool().next() as rpc:
-            (state, tmp1, tmp2, email) = rpc.getuserdata.get_data(user)
-        # Either error with the datalookup or no email provided
-        if state == "error" or email == 'No email given' or not email:
-            return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Unable to retrieve email address for user.' } )
-        # Try to send the email out
-        emailsend = self.email(user, email)
-        # Email got sent out
-        if emailsend == True:
-            return render(request, 'send_resetrequest.html', { 'user': user } )
-        # Error while trying to send email
+        ldap_manager = LdapManager()
+        user_exists, entries = ldap_manager.check_user_exists(
+            uid=user,
+            attributes=['uid', 'givenName', 'sn', 'mail']
+        )
+        if user_exists and request.user.username == user:
+            # user exists, so try to get email
+            # with get_pool().next() as rpc:
+            #     (state, tmp1, tmp2, email) = rpc.getuserdata.get_data(user)
+            # Either error with the datalookup or no email provided
+            email = entries[0].mail.value
+            if email is None:
+                return render(
+                    request, 'error.html',
+                    {'urlname': urlname, 'service': service,
+                     'error': 'Unable to retrieve email address for user.'}
+                )
+
+            base_url = "{0}://{1}".format(self.request.scheme,
+                                          self.request.get_host())
+            # Try to send the email out
+            emailsend = self.email(user, email, base_url)
+            # Email got sent out
+            if emailsend == True:
+                return render(
+                    request, 'send_resetrequest.html', {'user': user}
+                )
+            # Error while trying to send email
+            else:
+                return render(
+                    request, 'error.html',
+                    {'urlname': urlname, 'service': service,
+                     'error': emailsend}
+                )
         else:
-            return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': emailsend } )
+            return render(
+                request, 'error.html',
+                { 'urlname': urlname, 'service': service,
+                  'error': 'The user does not exist.' }
+            )
 
     # Sends an email to the user with the 24h active link for a password reset
     def email(self, user, email, base_url):

From 0591a186d8e9a49183decf08496f0c9b6d7f5869 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 19:28:09 +0100
Subject: [PATCH 42/54] Add EMAIL settings

---
 dal/settings.py | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/dal/settings.py b/dal/settings.py
index b1210b1..9779679 100644
--- a/dal/settings.py
+++ b/dal/settings.py
@@ -50,6 +50,10 @@ DEBUG = config('DEBUG', default=False, cast=bool)
 
 EMAIL_FROM_ADDRESS = config('EMAIL_FROM_ADDRESS')
 
+EMAIL_HOST = config("EMAIL_HOST", default="localhost")
+EMAIL_PORT = config("EMAIL_PORT", default=25, cast=int)
+EMAIL_USE_TLS = config("EMAIL_USE_TLS", default=True, cast=bool)
+
 ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=Csv())
 
 INSTALLED_APPS = [

From c3b8f7b553314e28ee76efe580cacf74010eeb6c Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 20:13:09 +0100
Subject: [PATCH 43/54] Add LoginRequiredMixin mixin for various views

---
 dal/urls.py  |  2 +-
 dal/views.py | 10 ++++++----
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/dal/urls.py b/dal/urls.py
index f977499..b5f4a3a 100644
--- a/dal/urls.py
+++ b/dal/urls.py
@@ -16,5 +16,5 @@ urlpatterns = [
     path('logout/', LogOut.as_view(), name="logout"),
     path('reset/<str:user>/<str:token>/', ResetRequest.as_view()),
     path('reset/', ResetRequest.as_view(), name="reset"),
-    path('', Index.as_view(), name="index"),
+    path('', Index.as_view(), name="login_index"),
 ]
\ No newline at end of file
diff --git a/dal/views.py b/dal/views.py
index 334a197..1b055fa 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -27,6 +27,7 @@ import ldap
 import ldap.modlist as modlist
 
 from django.conf import settings
+from django.contrib.auth.mixins import LoginRequiredMixin
 
 
 class Index(FormView):
@@ -93,7 +94,7 @@ class Register(View):
 
         return render(request, 'usercreated.html', { 'user': username } )
 
-class ChangeData(View):
+class ChangeData(LoginRequiredMixin, View):
     # provide the form for the change request
     def get(self, request):
         urlname = 'change_data'
@@ -166,7 +167,8 @@ class ChangeData(View):
             return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': msg } )
 
 
-class ResetPassword(View):
+class ResetPassword(LoginRequiredMixin, View):
+    login_url = reverse_lazy('login_index')
     def get(self, request):
         return render(request, 'resetpassword.html')
 
@@ -339,7 +341,7 @@ class ResetRequest(View):
 
 # The logged in user can change the password here
 
-class ChangePassword(View):
+class ChangePassword(LoginRequiredMixin, View):
 
     # Presents the page for a logged in user
     def get(self, request):
@@ -389,7 +391,7 @@ class ChangePassword(View):
 
 
 # Deletes an account
-class DeleteAccount(View):
+class DeleteAccount(LoginRequiredMixin, View):
     # Show the basic form for deleting an account
     def get(self, request):
         return render(request, 'deleteaccount.html')

From f61023d01aa342253627c9d61f5bacb81c3b4fb9 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 20:14:49 +0100
Subject: [PATCH 44/54] Take user to logged in page when already authenticated

---
 dal/views.py | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/dal/views.py b/dal/views.py
index 1b055fa..0dcaeea 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -8,6 +8,7 @@ from django.core.validators import validate_email, ValidationError
 from django.urls import reverse_lazy
 from django.contrib.auth.tokens import PasswordResetTokenGenerator
 from django.core.mail import EmailMessage
+from django.views.decorators.cache import cache_control
 from .models import ResetToken
 from .forms import LoginForm
 from .ungleich_ldap import LdapManager
@@ -44,6 +45,14 @@ class Index(FormView):
             return render(self.request, 'useroptions.html', { 'user': user } )
         return render(self.request, 'loginfailed.html')
 
+    @cache_control(no_cache=True, must_revalidate=True, no_store=True)
+    def get(self, request, *args, **kwargs):
+        if self.request.user.is_authenticated:
+            return render(self.request, 'useroptions.html',
+                          { 'user': self.request.user.username } )
+        return super(Index, self).get(request, *args, **kwargs)
+
+
 class Register(View):
     def get(self, request):
         return render(request, 'registeruser.html')

From 5903e10d8743145af3035c707389664c93be746c Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 20:15:52 +0100
Subject: [PATCH 45/54] Redirect user to login page after logout

---
 dal/views.py | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/dal/views.py b/dal/views.py
index 0dcaeea..fb28dd3 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -441,7 +441,13 @@ class DeleteAccount(LoginRequiredMixin, View):
 class LogOut(View):
     def get(self, request):
         logout(request)
-        return HttpResponse("You have been logged out.", status=200)
+        return HttpResponse(
+            "You have been logged out. You will be redirected in 2 seconds."
+            "<script>"
+            "setTimeout(function (){document.location.href='/';}, 2000);"
+            "</script>",
+            status=200
+        )
 
 
 

From d4a02dc57109697ad101cbee0e5bd55d82f6ec74 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 20:16:10 +0100
Subject: [PATCH 46/54] Remove unused imports

---
 dal/views.py | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/dal/views.py b/dal/views.py
index fb28dd3..6f73602 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -2,8 +2,7 @@
 from django.shortcuts import render
 from django.views.generic import View, FormView
 from django.contrib.auth import authenticate, login, logout
-from django.contrib.auth.models import User
-from django.http import HttpResponse, HttpResponseRedirect
+from django.http import HttpResponse
 from django.core.validators import validate_email, ValidationError
 from django.urls import reverse_lazy
 from django.contrib.auth.tokens import PasswordResetTokenGenerator
@@ -21,12 +20,6 @@ from datetime import datetime
 from random import choice, randint
 import string
 
-import os
-
-# Use ldap, like django_auth_backend
-import ldap
-import ldap.modlist as modlist
-
 from django.conf import settings
 from django.contrib.auth.mixins import LoginRequiredMixin
 

From 14949cedb7ce42581f39e351aefaa37db88d2a79 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 20:34:08 +0100
Subject: [PATCH 47/54] Add register link to landing.html

---
 dal/templates/landing.html | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/dal/templates/landing.html b/dal/templates/landing.html
index 6f31087..741fd74 100644
--- a/dal/templates/landing.html
+++ b/dal/templates/landing.html
@@ -25,12 +25,10 @@
                     </form>
                     <div class="auth-footer">
                         <div>
-                            {% trans "Don't have an account yet ?" %}&nbsp;
-{#                            <a href="{% url 'signup' %}">{% trans "Sign up" %}</a>#}
+                            {% trans "Don't have an account yet ?" %}&nbsp;<a href="/register">{% trans "Sign up" %}</a>
                         </div>
                         <div>
                             or <a href="{% url 'reset_password' %}">{% trans "Forgot your password ?" %}</a><br>
-{#                            or <a href="{% url 'resend_activation_link' %}">{% trans "Resend activation link" %}</a>#}
                         </div>
                     </div>
                 </div>

From a20e9479c8b5c43597a17296423a20528921a5fb Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 20:34:53 +0100
Subject: [PATCH 48/54] Add login_url for all LoginRequiredMixin views

---
 dal/views.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/dal/views.py b/dal/views.py
index 6f73602..a3f33c5 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -97,6 +97,7 @@ class Register(View):
         return render(request, 'usercreated.html', { 'user': username } )
 
 class ChangeData(LoginRequiredMixin, View):
+    login_url = reverse_lazy('login_index')
     # provide the form for the change request
     def get(self, request):
         urlname = 'change_data'
@@ -344,7 +345,7 @@ class ResetRequest(View):
 # The logged in user can change the password here
 
 class ChangePassword(LoginRequiredMixin, View):
-
+    login_url = reverse_lazy('login_index')
     # Presents the page for a logged in user
     def get(self, request):
         if not request.user.is_authenticated:
@@ -394,6 +395,7 @@ class ChangePassword(LoginRequiredMixin, View):
 
 # Deletes an account
 class DeleteAccount(LoginRequiredMixin, View):
+    login_url = reverse_lazy('login_index')
     # Show the basic form for deleting an account
     def get(self, request):
         return render(request, 'deleteaccount.html')

From c0264e5dda090c724dad109e744fb2656eb48e18 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 20:35:25 +0100
Subject: [PATCH 49/54] Remove LoginRequiredMixin for ResetPassword view

As this can be done even when the user is logged out
---
 dal/views.py | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/dal/views.py b/dal/views.py
index a3f33c5..35fa4d1 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -170,8 +170,7 @@ class ChangeData(LoginRequiredMixin, View):
             return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': msg } )
 
 
-class ResetPassword(LoginRequiredMixin, View):
-    login_url = reverse_lazy('login_index')
+class ResetPassword(View):
     def get(self, request):
         return render(request, 'resetpassword.html')
 
@@ -185,7 +184,7 @@ class ResetPassword(LoginRequiredMixin, View):
             uid=user,
             attributes=['uid', 'givenName', 'sn', 'mail']
         )
-        if user_exists and request.user.username == user:
+        if user_exists:
             # user exists, so try to get email
             # with get_pool().next() as rpc:
             #     (state, tmp1, tmp2, email) = rpc.getuserdata.get_data(user)

From bf3b3b364faa0866a7ab8335a3ce303590835e9a Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 22:21:55 +0100
Subject: [PATCH 50/54] Get ENTIRE_SEARCH_BASE from env

---
 dal/settings.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/dal/settings.py b/dal/settings.py
index 9779679..a302eac 100644
--- a/dal/settings.py
+++ b/dal/settings.py
@@ -161,6 +161,8 @@ AUTH_LDAP_USER_ATTR_MAP = {
     "email": "mail"
 }
 
+ENTIRE_SEARCH_BASE = config("ENTIRE_SEARCH_BASE")
+
 LOGGING = {
     'disable_existing_loggers': False,
     'version': 1,

From a5e91ffda286eb79542cf4ef3b1015bbb064cc78 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 22:23:43 +0100
Subject: [PATCH 51/54] Simplify search_base logic

---
 dal/ungleich_ldap.py | 54 ++++++++++++++++++++++++++++----------------
 dal/views.py         | 12 +++-------
 2 files changed, 38 insertions(+), 28 deletions(-)

diff --git a/dal/ungleich_ldap.py b/dal/ungleich_ldap.py
index 5d56d2a..373e927 100644
--- a/dal/ungleich_ldap.py
+++ b/dal/ungleich_ldap.py
@@ -78,7 +78,6 @@ class LdapManager:
         while user_exists:
             user_exists, _ = self.check_user_exists(
                 "",
-                True,
                 '(&(objectClass=inetOrgPerson)(objectClass=posixAccount)'
                 '(objectClass=top)(uidNumber={uidNumber}))'.format(
                     uidNumber=uidNumber
@@ -154,34 +153,51 @@ class LdapManager:
         :return: True if user details were updated successfully False otherwise
         """
         conn = self.get_admin_conn()
-        details_dict = {k: (ldap3.MODIFY_REPLACE, [v.encode("utf-8")]) for k, v in details.items()}
-        try:
-            return_val = conn.modify(
-                ("uid={uid}," + settings.LDAP_CUSTOMER_DN).format(uid=uid),
-                details_dict
-            )
-            msg = "success"
-        except Exception as ex:
-            msg = str(ex)
-            logger.error("Exception: " + msg)
-            return_val = False
-        finally:
-            conn.unbind()
+
+        # Make sure the user exists first to change his/her details
+        user_exists, entries = self.check_user_exists(
+            uid=uid,
+            attributes=['uid', 'givenName', 'sn', 'mail', 'gidNumber'],
+            search_base=settings.ENTIRE_SEARCH_BASE
+        )
+
+
+        if user_exists:
+            details_dict = {k: (ldap3.MODIFY_REPLACE, [v.encode("utf-8")]) for
+                            k, v in details.items()}
+            try:
+                return_val = conn.modify(
+                    ("uid={uid}," + settings.LDAP_CUSTOMER_DN
+                     if entries[0].gidNumber.value == settings.LDAP_CUSTOMER_GROUP_ID
+                     else settings.LDAP_USERS_DN).format(uid=uid),
+                    details_dict
+                )
+                msg = "success"
+            except Exception as ex:
+                msg = str(ex)
+                logger.error("Exception: " + msg)
+                return_val = False
+            finally:
+                conn.unbind()
+        else:
+            msg = "User {} not found".format(uid)
+            logger.error(msg)
+            raise Exception(msg)
+
         return return_val, msg
 
-    def check_user_exists(self, uid, is_customer=True, search_filter="",
-                          attributes=None):
+    def check_user_exists(self, uid, search_filter="", attributes=None,
+                          search_base=settings.LDAP_CUSTOMER_DN):
         """
         Check if the user with the given uid exists in the customer group.
 
         :param uid: str representing the user
-        :param is_customer: bool representing whether the current user is a
-                            customer. By default, the user is a customer (assume)
         :param search_filter: str representing the filter condition to find
                             users. If its empty, the search finds the user with
                             the given uid.
         :param attributes: list A list of str representing all the attributes
                            to be obtained in the result entries
+        :param search_base: str
         :return: tuple (bool, [ldap3.abstract.entry.Entry ..])
                        A bool indicating if the user exists
                        A list of all entries obtained in the search
@@ -190,7 +206,7 @@ class LdapManager:
         entries = []
         try:
             result = conn.search(
-                settings.LDAP_CUSTOMER_DN if is_customer else settings.LDAP_USERS_DN,
+                search_base=search_base,
                 search_filter=search_filter if len(search_filter)> 0 else
                 '(uid={uid})'.format(uid=uid),
                 attributes=attributes
diff --git a/dal/views.py b/dal/views.py
index 35fa4d1..ea8917a 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -102,15 +102,13 @@ class ChangeData(LoginRequiredMixin, View):
     def get(self, request):
         urlname = 'change_data'
         service = 'get default data for logged in user'
-        if not request.user.is_authenticated:
-            return render(request, 'mustbeloggedin.html')
-        user = request.user
 
+        user = request.user
         ldap_manager = LdapManager()
         user_exists, entries = ldap_manager.check_user_exists(
             uid=user.username,
-            is_customer=True,
-            attributes=['uid', 'givenName', 'sn', 'mail']
+            attributes=['uid', 'givenName', 'sn', 'mail'],
+            search_base=settings.ENTIRE_SEARCH_BASE
         )
 
         if user_exists:
@@ -136,10 +134,6 @@ class ChangeData(LoginRequiredMixin, View):
         service = 'change user data'
         urlname = 'change_data'
 
-        # Only logged in users may change data
-        if not request.user.is_authenticated:
-            return render(request, 'mustbeloggedin.html')
-
         firstname = request.POST.get('firstname')
         lastname = request.POST.get('lastname')
         email = request.POST.get('email')

From bdb57221e5844006e4ecbfd828ea684acea859da Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 23:25:12 +0100
Subject: [PATCH 52/54] Also check user before password reset

---
 dal/ungleich_ldap.py | 44 +++++++++++++++++++++++++-------------------
 dal/views.py         |  1 +
 2 files changed, 26 insertions(+), 19 deletions(-)

diff --git a/dal/ungleich_ldap.py b/dal/ungleich_ldap.py
index 373e927..74f102f 100644
--- a/dal/ungleich_ldap.py
+++ b/dal/ungleich_ldap.py
@@ -129,15 +129,29 @@ class LdapManager:
         :return: True if password was changed successfully False otherwise
         """
         conn = self.get_admin_conn()
-        return_val = conn.modify(
-            ("uid={uid}," + settings.LDAP_CUSTOMER_DN).format(uid=uid),
-            {
-                "userpassword": (
-                    ldap3.MODIFY_REPLACE,
-                    [self._ssha_password(new_password.encode("utf-8"))]
-                )
-            }
+
+        # Make sure the user exists first to change his/her details
+        user_exists, entries = self.check_user_exists(
+            uid=uid,
+            search_base=settings.ENTIRE_SEARCH_BASE
         )
+        return_val = False
+        if user_exists:
+            try:
+                return_val = conn.modify(
+                    entries[0].entry_dn,
+                    {
+                        "userpassword": (
+                            ldap3.MODIFY_REPLACE,
+                            [self._ssha_password(new_password.encode("utf-8"))]
+                        )
+                    }
+                )
+            except Exception as ex:
+                logger.error("Exception: " + str(ex))
+        else:
+            logger.error("User {} not found".format(uid))
+
         conn.unbind()
         return return_val
 
@@ -157,33 +171,25 @@ class LdapManager:
         # Make sure the user exists first to change his/her details
         user_exists, entries = self.check_user_exists(
             uid=uid,
-            attributes=['uid', 'givenName', 'sn', 'mail', 'gidNumber'],
             search_base=settings.ENTIRE_SEARCH_BASE
         )
 
-
+        return_val = False
         if user_exists:
             details_dict = {k: (ldap3.MODIFY_REPLACE, [v.encode("utf-8")]) for
                             k, v in details.items()}
             try:
-                return_val = conn.modify(
-                    ("uid={uid}," + settings.LDAP_CUSTOMER_DN
-                     if entries[0].gidNumber.value == settings.LDAP_CUSTOMER_GROUP_ID
-                     else settings.LDAP_USERS_DN).format(uid=uid),
-                    details_dict
-                )
+                return_val = conn.modify(entries[0].entry_dn, details_dict)
                 msg = "success"
             except Exception as ex:
                 msg = str(ex)
                 logger.error("Exception: " + msg)
-                return_val = False
             finally:
                 conn.unbind()
         else:
             msg = "User {} not found".format(uid)
             logger.error(msg)
-            raise Exception(msg)
-
+            conn.unbind()
         return return_val, msg
 
     def check_user_exists(self, uid, search_filter="", attributes=None,
diff --git a/dal/views.py b/dal/views.py
index ea8917a..0bcd174 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -176,6 +176,7 @@ class ResetPassword(View):
         ldap_manager = LdapManager()
         user_exists, entries = ldap_manager.check_user_exists(
             uid=user,
+            search_base=settings.ENTIRE_SEARCH_BASE,
             attributes=['uid', 'givenName', 'sn', 'mail']
         )
         if user_exists:

From bcb3d6165db9269784327f6494b171ba9207edc6 Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 23:32:50 +0100
Subject: [PATCH 53/54] Logout user after password reset

---
 dal/views.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/dal/views.py b/dal/views.py
index 0bcd174..5002eaa 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -381,6 +381,7 @@ class ChangePassword(LoginRequiredMixin, View):
         )
         # Password was changed
         if result:
+            logout(request)
             return render(request, 'changedpassword.html', { 'user': user } )
         # Password not changed, instead got some kind of error
         else:

From 7191eb0997af50d0a6537d4e393f164d25dfb9bf Mon Sep 17 00:00:00 2001
From: PCoder <purple.coder@yahoo.co.uk>
Date: Sun, 24 Feb 2019 23:51:32 +0100
Subject: [PATCH 54/54] Initialize checks_out variable to False (missing
 before)

---
 dal/views.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/dal/views.py b/dal/views.py
index 5002eaa..5d643d2 100644
--- a/dal/views.py
+++ b/dal/views.py
@@ -279,6 +279,7 @@ class ResetRequest(View):
         user = b64decode(tmp_user)
         user_clean = user.decode('utf-8')
         # set checks_out = True if token is found in database
+        checks_out = False
         dbentries = ResetToken.objects.all().filter(user=user_clean)
         for entry in dbentries:
             if entry.token == token: