incremental
diff --git a/.clang-format b/.clang-format
index 17d370f..113030c 100644
--- a/.clang-format
+++ b/.clang-format
@@ -47,12 +47,21 @@
 ExperimentalAutoDetectBinPacking: false
 ForEachMacros:   [ foreach, Q_FOREACH, BOOST_FOREACH ]
 IncludeCategories: 
+
+  - Regex:           '^[<"](crow)'
+    Priority:        5
+  - Regex:           '^[<"](boost)'
+    Priority:        6
+  - Regex:           '^[<"](gtest|gmock)'
+    Priority:        7
   - Regex:           '^<.*\.h>'
     Priority:        1
-  - Regex:           '^<.*'
+  - Regex:           '^<.*\.hpp>'
     Priority:        2
-  - Regex:           '.*'
+  - Regex:           '^<.*'
     Priority:        3
+  - Regex:           '.*'
+    Priority:        4
 IndentCaseLabels: true
 IndentWidth:     2
 IndentWrappedFunctionNames: false
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e80c6c1..1be970a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,21 +8,16 @@
 
 SET(BUILD_SHARED_LIBRARIES OFF)
 
-#set(HUNTER_ROOT /home/ed/hunter)
 #SET(HUNTER_STATUS_DEBUG ON)
 
-
-#SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls")
-#-fsanitize-memory-track-origins=2 -fno-omit-frame-pointer
-SET(MSAN_CXX_FLAGS "-fsanitize=memory -stdlib=libc++ -I/home/ed/libcxx_msan/include -I/home/ed/libcxx_msan/include/c++/v1")
-SET(MSAN_LINKER_EXE_FLAGS "${MSAN_CXX_FLAGS} -lc++abi -L/home/ed/libcxx_msan/lib -Wl,-rpath,I/home/ed/libcxx_msan/lib")
+#SET(MSAN_CXX_FLAGS "-fsanitize=memory -stdlib=libc++ -I/home/ed/libcxx_msan/include -I/home/ed/libcxx_msan/include/c++/v1")
+#SET(MSAN_LINKER_EXE_FLAGS "${MSAN_CXX_FLAGS} -lc++abi -L/home/ed/libcxx_msan/lib -Wl,-rpath,I/home/ed/libcxx_msan/lib")
 
 #SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MSAN_CXX_FLAGS}")
 #SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MSAN_LINKER_EXE_FLAGS}")
 
-
-message("CMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}")
-message("MSAN_CXX_FLAGS=${MSAN_CXX_FLAGS}")
+# Debug information
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fno-omit-frame-pointer")
 
 include("cmake/HunterGate.cmake")
 #HunterGate(
@@ -39,8 +34,6 @@
 
 project(bmc-webserver CXX C)
 
-
-
 set(CMAKE_CXX_STANDARD 14)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
@@ -67,15 +60,13 @@
 add_definitions(-DBOOST_SYSTEM_NO_DEPRECATED)
 add_definitions(-DBOOST_ALL_NO_LIB)
 set(Boost_USE_STATIC_LIBS ON)
-hunter_add_package(Boost)
-find_package(Boost)
+hunter_add_package(Boost COMPONENTS system)
+find_package(Boost COMPONENTS system)
 
 #Openssl
 hunter_add_package(OpenSSL)
 find_package(OpenSSL REQUIRED)
 
-
-
 #g3 logging
 # G3logger does some unfortunate compile options, so cheat a little bit and copy/paste
 set(LOG_SRC ${CMAKE_CURRENT_SOURCE_DIR}/g3log/src)
@@ -93,6 +84,7 @@
 include_directories(${LOG_SRC})
 
 add_library(g3logger ${SRC_FILES})
+# clean up some warnings in files we don't own
 if(("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang"))
     set_source_files_properties(g3log/src/logcapture.cpp PROPERTIES COMPILE_FLAGS -Wno-braced-scalar-init)
     set_source_files_properties(g3log/src/filesink.cpp PROPERTIES COMPILE_FLAGS -Wno-braced-scalar-init)
@@ -113,6 +105,7 @@
 
 
 # Crow
+add_definitions(-DCROW_DISABLE_LOGGING)
 add_definitions(-DCROW_ENABLE_SSL)
 include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/crow/include)
 
@@ -169,7 +162,7 @@
     g3log/test_unit/testing_helpers.cpp  
     g3log/test_unit/test_io.cpp        
     g3log/test_unit/test_message.cpp
-    src/crowtest/crow_unittest.cpp
+    src/crow_test.cpp
     src/gtest_main.cpp
     src/base64_test.cpp
     src/token_authorization_middleware_test.cpp
@@ -177,8 +170,10 @@
     src/webassets_test.cpp
     src/crow_getroutes_test.cpp
     src/ast_jpeg_decoder_test.cpp
-
+    src/kvm_websocket_test.cpp
+    src/test_utils.cpp
     src/msan_test.cpp
+    src/ci_map_tests.cpp
 
     ${CMAKE_BINARY_DIR}/generated/blns.hpp
 )
@@ -216,13 +211,14 @@
 add_executable(bmcweb ${WEBSERVER_MAIN} ${HDR_FILES} ${SRC_FILES})
 target_link_libraries(bmcweb pthread)
 target_link_libraries(bmcweb OpenSSL::SSL OpenSSL::Crypto)
+target_link_libraries(bmcweb Boost::system)
 target_link_libraries(bmcweb g3logger)
 target_link_libraries(bmcweb ${ZLIB_LIBRARIES})
 add_dependencies(bmcweb packagestaticcpp)
 
 # udpclient
-add_executable(udpclient src/udpclient.cpp)
-target_link_libraries(udpclient pthread)
+#add_executable(udpclient src/udpclient.cpp)
+#target_link_libraries(udpclient pthread)
 
 add_executable(getvideo src/getvideo_main.cpp)
 target_link_libraries(getvideo pthread)
diff --git a/crow/include/crow/app.h b/crow/include/crow/app.h
index e0e5d84..4bce60a 100644
--- a/crow/include/crow/app.h
+++ b/crow/include/crow/app.h
@@ -1,5 +1,12 @@
 #pragma once
 
+#include "crow/http_request.h"
+#include "crow/http_server.h"
+#include "crow/logging.h"
+#include "crow/middleware_context.h"
+#include "crow/routing.h"
+#include "crow/settings.h"
+#include "crow/utility.h"
 #include <chrono>
 #include <cstdint>
 #include <functional>
@@ -9,14 +16,6 @@
 #include <thread>
 #include <type_traits>
 
-#include "crow/http_request.h"
-#include "crow/http_server.h"
-#include "crow/logging.h"
-#include "crow/middleware_context.h"
-#include "crow/routing.h"
-#include "crow/settings.h"
-#include "crow/utility.h"
-
 #ifdef CROW_MSVC_WORKAROUND
 #define CROW_ROUTE(app, url) app.route_dynamic(url)
 #else
@@ -116,9 +115,7 @@
     router_.debug_print();
   }
 
-  std::vector<std::string> get_routes() {
-    return router_.get_routes();
-  }
+  std::vector<std::string> get_routes() { return router_.get_routes(); }
 
 #ifdef CROW_ENABLE_SSL
   self_t& ssl_file(const std::string& crt_filename,
diff --git a/crow/include/crow/ci_map.h b/crow/include/crow/ci_map.h
index b2021d3..bf50fd0 100644
--- a/crow/include/crow/ci_map.h
+++ b/crow/include/crow/ci_map.h
@@ -1,29 +1,31 @@
 #pragma once
 
+#include <algorithm>
+#include <iostream>
 #include <boost/algorithm/string/predicate.hpp>
+#include <boost/container/flat_map.hpp>
 #include <boost/functional/hash.hpp>
-#include <unordered_map>
 
 namespace crow {
-struct ci_hash {
-  size_t operator()(const std::string& key) const {
-    std::size_t seed = 0;
-    std::locale locale;
-
-    for (auto c : key) {
-      boost::hash_combine(seed, std::toupper(c, locale));
-    }
-
-    return seed;
-  }
-};
 
 struct ci_key_eq {
-  bool operator()(const std::string& l, const std::string& r) const {
-    return boost::iequals(l, r);
+  bool operator()(const std::string& left, const std::string& right) const {
+    unsigned int lsz = left.size();
+    unsigned int rsz = right.size();
+    for (unsigned int i = 0; i < std::min(lsz, rsz); ++i) {
+      auto lchar = tolower(left[i]);
+      auto rchar = tolower(right[i]);
+      if (lchar != rchar) {
+        return lchar < rchar;
+      }
+    }
+
+    if (rsz != lsz) {
+      return lsz < rsz;
+    }
+    return 0;
   }
 };
 
-using ci_map =
-    std::unordered_multimap<std::string, std::string, ci_hash, ci_key_eq>;
+using ci_map = boost::container::flat_map<std::string, std::string, ci_key_eq>;
 }
diff --git a/crow/include/crow/http_connection.h b/crow/include/crow/http_connection.h
index ed669c3..4b10c11 100644
--- a/crow/include/crow/http_connection.h
+++ b/crow/include/crow/http_connection.h
@@ -7,6 +7,8 @@
 #include <chrono>
 #include <vector>
 
+#include <boost/container/flat_map.hpp>
+
 #include "crow/http_parser_merged.h"
 
 #include "crow/dumb_timer_queue.h"
@@ -263,7 +265,7 @@
                                 "Keep-Alive"))
           add_keep_alive_ = true;
       }
-      if (!req.headers.count("host")) {
+      if (!req.headers.count("Host")) {
         is_invalid_request = true;
         res = response(400);
       }
@@ -334,7 +336,7 @@
       return;
     }
 
-    static std::unordered_map<int, std::string> statusCodes = {
+    static boost::container::flat_map<int, std::string> statusCodes = {
         {200, "HTTP/1.1 200 OK\r\n"},
         {201, "HTTP/1.1 201 Created\r\n"},
         {202, "HTTP/1.1 202 Accepted\r\n"},
diff --git a/crow/include/crow/http_response.h b/crow/include/crow/http_response.h
index 66d2ee3..322147b 100644
--- a/crow/include/crow/http_response.h
+++ b/crow/include/crow/http_response.h
@@ -1,6 +1,5 @@
 #pragma once
 #include <string>
-#include <unordered_map>
 
 #include "crow/ci_map.h"
 #include "crow/http_request.h"
diff --git a/crow/include/crow/json.h b/crow/include/crow/json.h
index f368eb1..4672a8d 100644
--- a/crow/include/crow/json.h
+++ b/crow/include/crow/json.h
@@ -3,14 +3,14 @@
 //#define CROW_JSON_NO_ERROR_CHECK
 
 #include <algorithm>
-#include <boost/algorithm/string/predicate.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/operators.hpp>
 #include <iostream>
 #include <memory>
 #include <string>
-#include <unordered_map>
 #include <vector>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/container/flat_map.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/operators.hpp>
 
 #include "crow/settings.h"
 
@@ -920,7 +920,7 @@
   double d{};
   std::string s;
   std::unique_ptr<std::vector<wvalue>> l;
-  std::unique_ptr<std::unordered_map<std::string, wvalue>> o;
+  std::unique_ptr<boost::container::flat_map<std::string, wvalue>> o;
 
  public:
   wvalue() {}
@@ -944,8 +944,8 @@
         for (auto it = r.begin(); it != r.end(); ++it) l->emplace_back(*it);
         return;
       case type::Object:
-        o = std::unique_ptr<std::unordered_map<std::string, wvalue>>(
-            new std::unordered_map<std::string, wvalue>{});
+        o = std::unique_ptr<boost::container::flat_map<std::string, wvalue>>(
+            new boost::container::flat_map<std::string, wvalue>{});
         for (auto it = r.begin(); it != r.end(); ++it)
           o->emplace(it->key(), *it);
         return;
@@ -1097,8 +1097,8 @@
     if (t_ != type::Object) reset();
     t_ = type::Object;
     if (!o)
-      o = std::unique_ptr<std::unordered_map<std::string, wvalue>>(
-          new std::unordered_map<std::string, wvalue>{});
+      o = std::unique_ptr<boost::container::flat_map<std::string, wvalue>>(
+          new boost::container::flat_map<std::string, wvalue>{});
     return (*o)[str];
   }
 
diff --git a/crow/include/crow/middleware.h b/crow/include/crow/middleware.h
index 342f128..64b9f98 100644
--- a/crow/include/crow/middleware.h
+++ b/crow/include/crow/middleware.h
@@ -1,7 +1,9 @@
 #pragma once
-#include <boost/algorithm/string/trim.hpp>
+
 #include "crow/http_request.h"
 #include "crow/http_response.h"
+#include <boost/algorithm/string/trim.hpp>
+#include <boost/container/flat_map.hpp>
 
 namespace crow {
 // Any middleware requires following 3 members:
@@ -33,8 +35,8 @@
 
 struct CookieParser {
   struct context {
-    std::unordered_map<std::string, std::string> jar;
-    std::unordered_map<std::string, std::string> cookies_to_add;
+    boost::container::flat_map<std::string, std::string> jar;
+    boost::container::flat_map<std::string, std::string> cookies_to_add;
 
     std::string get_cookie(const std::string& key) {
       if (jar.count(key)) return jar[key];
diff --git a/crow/include/crow/parser.h b/crow/include/crow/parser.h
index 8fffcfc..8140d62 100644
--- a/crow/include/crow/parser.h
+++ b/crow/include/crow/parser.h
@@ -4,7 +4,6 @@
 #include <boost/algorithm/string.hpp>
 #include <boost/tokenizer.hpp>
 #include <string>
-#include <unordered_map>
 
 #include "crow/http_parser_merged.h"
 #include "crow/http_request.h"
diff --git a/crow/include/crow/routing.h b/crow/include/crow/routing.h
index d07f09f..f1f3b32 100644
--- a/crow/include/crow/routing.h
+++ b/crow/include/crow/routing.h
@@ -4,10 +4,11 @@
 #include <cstdint>
 #include <memory>
 #include <tuple>
-#include <unordered_map>
 #include <utility>
 #include <vector>
 
+#include "boost/container/flat_map.hpp"
+
 #include "crow/common.h"
 #include "crow/http_request.h"
 #include "crow/http_response.h"
@@ -502,7 +503,7 @@
   struct Node {
     unsigned rule_index{};
     std::array<unsigned, (int)ParamType::MAX> param_childrens{};
-    std::unordered_map<std::string, unsigned> children;
+    boost::container::flat_map<std::string, unsigned> children;
 
     bool IsSimpleNode() const {
       return !rule_index &&
diff --git a/crow/include/crow/socket_adaptors.h b/crow/include/crow/socket_adaptors.h
index a0d8dfa..34bf801 100644
--- a/crow/include/crow/socket_adaptors.h
+++ b/crow/include/crow/socket_adaptors.h
@@ -33,7 +33,6 @@
   tcp::socket socket_;
 };
 
-
 struct TestSocketAdaptor {
   using context = void;
   TestSocketAdaptor(boost::asio::io_service& io_service, context*)
@@ -74,9 +73,31 @@
 
   tcp::endpoint remote_endpoint() { return raw_socket().remote_endpoint(); }
 
-  bool is_open() { return raw_socket().is_open(); }
+  bool is_open() {
+    /*TODO(ed) this is a bit of a cheat.
+     There are cases  when running a websocket where ssl_socket_ might have
+    std::move() called on it (to transfer ownership to websocket::Connection)
+    and be empty.  This (and the check on close()) is a cheat to do something
+    sane in this scenario. the correct fix would likely involve changing the
+    http parser to return a specific code meaning "has been upgraded" so that
+    the do_read function knows not to try to close the connection which would
+    fail, because the adapter is gone.  As is, do_read beleives the parse
+    failed, because is_open now returns False (which could also mean the client
+    disconnected during parse)
+    */
+    if (ssl_socket_ != nullptr) {
+      return ssl_socket_->lowest_layer().is_open();
+    } else {
+      return false;
+    }
+  }
 
-  void close() { raw_socket().close(); }
+  void close() {
+    if (ssl_socket_ == nullptr) {
+      return;
+    }
+    ssl_socket_->lowest_layer().close();
+  }
 
   boost::asio::io_service& get_io_service() {
     return raw_socket().get_io_service();
diff --git a/crow/include/crow/websocket.h b/crow/include/crow/websocket.h
index c148c37..f29f13b 100644
--- a/crow/include/crow/websocket.h
+++ b/crow/include/crow/websocket.h
@@ -138,7 +138,7 @@
         "HTTP/1.1 101 Switching Protocols\r\n"
         "Upgrade: websocket\r\n"
         "Connection: Upgrade\r\n"
-        "Sec-WebSocket-Protocol: binary\n"  // TODO(ed): this hardcodes binary mode
+        "Sec-WebSocket-Protocol: binary\r\n"  // TODO(ed): this hardcodes binary mode
                                             // find a better way
         "Sec-WebSocket-Accept: ";
     static std::string crlf = "\r\n";
diff --git a/include/aspeed/JTABLES.H b/include/aspeed/JTABLES.H
index 93fec8c..bff39e3 100644
--- a/include/aspeed/JTABLES.H
+++ b/include/aspeed/JTABLES.H
@@ -1,11 +1,11 @@
-

-static unsigned char zigzag[64] = {

+#pragma once

+static const unsigned char zigzag[64] = {

     0,  1,  5,  6,  14, 15, 27, 28, 2,  4,  7,  13, 16, 26, 29, 42,

     3,  8,  12, 17, 25, 30, 41, 43, 9,  11, 18, 24, 31, 40, 44, 53,

     10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60,

     21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63};

 

-static unsigned char dezigzag[64 + 15] = {

+static const unsigned char dezigzag[64 + 15] = {

     0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40,

     48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36,

     29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61,

@@ -13,24 +13,24 @@
     // let corrupt input sample past end

     63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63};

 

-static unsigned char *std_luminance_qt;

-static unsigned char *std_chrominance_qt;

+static const unsigned char *std_luminance_qt;

+static const unsigned char *std_chrominance_qt;

 

 // Standard Huffman tables (cf. JPEG standard section K.3) */

 

-static unsigned char std_dc_luminance_nrcodes[17] = {0, 0, 1, 5, 1, 1, 1, 1, 1,

+static const unsigned char std_dc_luminance_nrcodes[17] = {0, 0, 1, 5, 1, 1, 1, 1, 1,

                                                      1, 0, 0, 0, 0, 0, 0, 0};

-static unsigned char std_dc_luminance_values[12] = {0, 1, 2, 3, 4,  5,

+static const unsigned char std_dc_luminance_values[12] = {0, 1, 2, 3, 4,  5,

                                                     6, 7, 8, 9, 10, 11};

 

-static unsigned char std_dc_chrominance_nrcodes[17] = {

+static const unsigned char std_dc_chrominance_nrcodes[17] = {

     0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0};

-static unsigned char std_dc_chrominance_values[12] = {0, 1, 2, 3, 4,  5,

+static const unsigned char std_dc_chrominance_values[12] = {0, 1, 2, 3, 4,  5,

                                                       6, 7, 8, 9, 10, 11};

 

-static unsigned char std_ac_luminance_nrcodes[17] = {

+static const unsigned char std_ac_luminance_nrcodes[17] = {

     0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d};

-static unsigned char std_ac_luminance_values[162] = {

+static const unsigned char std_ac_luminance_values[162] = {

     0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06,

     0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,

     0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72,

@@ -46,9 +46,9 @@
     0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4,

     0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa};

 

-static unsigned char std_ac_chrominance_nrcodes[17] = {

+static const unsigned char std_ac_chrominance_nrcodes[17] = {

     0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77};

-static unsigned char std_ac_chrominance_values[162] = {

+static const unsigned char std_ac_chrominance_values[162] = {

     0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,

     0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,

     0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1,

@@ -64,7 +64,7 @@
     0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,

     0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa};

 

-unsigned short int DC_LUMINANCE_HUFFMANCODE[13 * 2] = {

+static const unsigned short int DC_LUMINANCE_HUFFMANCODE[13 * 2] = {

     /* 0 */ 0x0000,  0,

     /* 1 */ 0x4000,  2,

     /* 2 */ 0x6000,  3,

@@ -80,7 +80,7 @@
     /* 12 */ 0xFFFF, 9,

 };

 

-unsigned short int DC_CHROMINANCE_HUFFMANCODE[13 * 2] = {

+static const unsigned short int DC_CHROMINANCE_HUFFMANCODE[13 * 2] = {

     /* 0 */ 0x0000,  0,

     /* 1 */ 0x4000,  2,

     /* 2 */ 0x8000,  2,

@@ -96,7 +96,7 @@
     /* 12 */ 0xFFFF, 11,

 };

 

-unsigned short int AC_LUMINANCE_HUFFMANCODE[39 * 2] = {

+static const unsigned short int AC_LUMINANCE_HUFFMANCODE[39 * 2] = {

     /* 0 */ 0x0000,  0,

     /* 1 */ 0x4000,  2,

     /* 2 */ 0x8000,  2,

@@ -138,7 +138,7 @@
     /* 38 */ 0xFFFF, 16,

 };

 

-unsigned short int AC_CHROMINANCE_HUFFMANCODE[45 * 2] = {

+static const unsigned short int AC_CHROMINANCE_HUFFMANCODE[45 * 2] = {

     /* 0 */ 0x0000,  0,

     /* 1 */ 0x4000,  2,

     /* 2 */ 0x8000,  2,

@@ -187,59 +187,59 @@
 };

 

 //[100]=========================

-static unsigned char Tbl_100Y[64] = {

+static const unsigned char Tbl_100Y[64] = {

     2, 1, 1, 2,  3,  5,  6,  7,  1, 1,  1,  2,  3,  7,  7,  6,

     1, 1, 2, 3,  5,  7,  8,  7,  1, 2,  2,  3,  6,  10, 10, 7,

     2, 2, 4, 7,  8,  13, 12, 9,  3, 4,  6,  8,  10, 13, 14, 11,

     6, 8, 9, 10, 12, 15, 15, 12, 9, 11, 11, 12, 14, 12, 12, 12};

-static unsigned char Tbl_100UV[64] = {

+static const unsigned char Tbl_100UV[64] = {

     3,  3,  4,  8,  18, 18, 18, 18, 3,  3,  4,  12, 18, 18, 18, 18,

     4,  4,  10, 18, 18, 18, 18, 18, 8,  12, 18, 18, 18, 18, 18, 18,

     18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,

     18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18};

 

 //[086]=========================

-static unsigned char Tbl_086Y[64] = {

+static const unsigned char Tbl_086Y[64] = {

     3, 2,  1,  3,  4,  7,  9,  11, 2,  2,  2,  3,  4,  10, 11, 10,

     2, 2,  3,  4,  7,  10, 12, 10, 2,  3,  4,  5,  9,  16, 15, 11,

     3, 4,  6,  10, 12, 20, 19, 14, 4,  6,  10, 12, 15, 19, 21, 17,

     9, 12, 14, 16, 19, 22, 22, 18, 13, 17, 17, 18, 21, 18, 19, 18};

-static unsigned char Tbl_086UV[64] = {

+static const unsigned char Tbl_086UV[64] = {

     4,  5,  6,  13, 27, 27, 27, 27, 5,  5,  7,  18, 27, 27, 27, 27,

     6,  7,  15, 27, 27, 27, 27, 27, 13, 18, 27, 27, 27, 27, 27, 27,

     27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,

     27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27};

 

 //[071]=========================

-static unsigned char Tbl_071Y[64] = {

+static const unsigned char Tbl_071Y[64] = {

     6,  4,  3,  6,  9,  15, 19, 22, 4,  4,  5,  7,  9,  21, 22, 20,

     5,  4,  6,  9,  15, 21, 25, 21, 5,  6,  8,  10, 19, 32, 30, 23,

     6,  8,  13, 21, 25, 40, 38, 28, 9,  13, 20, 24, 30, 39, 42, 34,

     18, 24, 29, 32, 38, 45, 45, 37, 27, 34, 35, 36, 42, 37, 38, 37};

-static unsigned char Tbl_071UV[64] = {

+static const unsigned char Tbl_071UV[64] = {

     9,  10, 13, 26, 55, 55, 55, 55, 10, 11, 14, 37, 55, 55, 55, 55,

     13, 14, 31, 55, 55, 55, 55, 55, 26, 37, 55, 55, 55, 55, 55, 55,

     55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,

     55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55};

 //[057]=========================

-static unsigned char Tbl_057Y[64] = {

+static const unsigned char Tbl_057Y[64] = {

     9,  6,  5,  9,  13, 22, 28, 34, 6,  6,  7,  10, 14, 32, 33, 30,

     7,  7,  9,  13, 22, 32, 38, 31, 7,  9,  12, 16, 28, 48, 45, 34,

     10, 12, 20, 31, 38, 61, 57, 43, 13, 19, 30, 36, 45, 58, 63, 51,

     27, 36, 43, 48, 57, 68, 67, 56, 40, 51, 53, 55, 63, 56, 57, 55};

-static unsigned char Tbl_057UV[64] = {

+static const unsigned char Tbl_057UV[64] = {

     13, 14, 19, 38, 80, 80, 80, 80, 14, 17, 21, 53, 80, 80, 80, 80,

     19, 21, 45, 80, 80, 80, 80, 80, 38, 53, 80, 80, 80, 80, 80, 80,

     80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,

     80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80};

 

 //[043]=========================

-static unsigned char Tbl_043Y[64] = {

+static const unsigned char Tbl_043Y[64] = {

     11, 7,  7,  11, 17, 28, 36, 43, 8,  8,  10, 13, 18, 41, 43, 39,

     10, 9,  11, 17, 28, 40, 49, 40, 10, 12, 15, 20, 36, 62, 57, 44,

     12, 15, 26, 40, 48, 78, 74, 55, 17, 25, 39, 46, 58, 74, 81, 66,

     35, 46, 56, 62, 74, 86, 86, 72, 51, 66, 68, 70, 80, 71, 74, 71};

-static unsigned char Tbl_043UV[64] = {

+static const unsigned char Tbl_043UV[64] = {

     18,  19,  26,  51,  108, 108, 108, 108, 19,  22,  28,  72,  108,

     108, 108, 108, 26,  28,  61,  108, 108, 108, 108, 108, 51,  72,

     108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108,

@@ -247,12 +247,12 @@
     108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108};

 

 //[029]=========================

-static unsigned char Tbl_029Y[64] = {

+static const unsigned char Tbl_029Y[64] = {

     14, 9,  9,  14, 21, 36,  46,  55, 10, 10, 12, 17, 23,  52, 54,  49,

     12, 11, 14, 21, 36, 51,  62,  50, 12, 15, 19, 26, 46,  78, 72,  56,

     16, 19, 33, 50, 61, 98,  93,  69, 21, 31, 49, 58, 73,  94, 102, 83,

     44, 58, 70, 78, 93, 109, 108, 91, 65, 83, 86, 88, 101, 90, 93,  89};

-static unsigned char Tbl_029UV[64] = {

+static const unsigned char Tbl_029UV[64] = {

     22,  24,  32,  63,  133, 133, 133, 133, 24,  28,  34,  88,  133,

     133, 133, 133, 32,  34,  75,  133, 133, 133, 133, 133, 63,  88,

     133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133,

@@ -260,24 +260,24 @@
     133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133};

 

 //[014]=========================

-static unsigned char Tbl_014Y[64] = {

+static const unsigned char Tbl_014Y[64] = {

     17, 12, 10, 17, 26,  43,  55,  66,  13, 13,  15,  20,  28,  63,  65,  60,

     15, 14, 17, 26, 43,  62,  75,  61,  15, 18,  24,  31,  55,  95,  87,  67,

     19, 24, 40, 61, 74,  119, 112, 84,  26, 38,  60,  70,  88,  113, 123, 100,

     53, 70, 85, 95, 112, 132, 131, 110, 78, 100, 103, 107, 122, 109, 112, 108};

-static unsigned char Tbl_014UV[64] = {

+static const unsigned char Tbl_014UV[64] = {

     27,  29,  39,  76,  160, 160, 160, 160, 29,  34,  42,  107, 160,

     160, 160, 160, 39,  42,  91,  160, 160, 160, 160, 160, 76,  107,

     160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,

     160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,

     160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160};

 //[000]=========================

-static unsigned char Tbl_000Y[64] = {

+static const unsigned char Tbl_000Y[64] = {

     20, 13, 12, 20,  30,  50,  63,  76,  15, 15,  17,  23,  32,  72,  75,  68,

     17, 16, 20, 30,  50,  71,  86,  70,  17, 21,  27,  36,  63,  108, 100, 77,

     22, 27, 46, 70,  85,  136, 128, 96,  30, 43,  68,  80,  101, 130, 141, 115,

     61, 80, 97, 108, 128, 151, 150, 126, 90, 115, 118, 122, 140, 125, 128, 123};

-static unsigned char Tbl_000UV[64] = {

+static const unsigned char Tbl_000UV[64] = {

     31,  33,  45,  88,  185, 185, 185, 185, 33,  39,  48,  123, 185,

     185, 185, 185, 45,  48,  105, 185, 185, 185, 185, 185, 88,  123,

     185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185,

diff --git a/include/ast_jpeg_decoder.hpp b/include/ast_jpeg_decoder.hpp
index 4036423..6e5a3d4 100644
--- a/include/ast_jpeg_decoder.hpp
+++ b/include/ast_jpeg_decoder.hpp
@@ -73,8 +73,8 @@
  public:
   AstJpegDecoder() {
     // TODO(ed) figure out how to init this in the constructor
-    YUVBuffer.resize(800 * 600);
-    OutBuffer.resize(800 * 600);
+    YUVBuffer.resize(1920 * 1200);
+    OutBuffer.resize(1920 * 1200);
     for (auto &r : OutBuffer) {
       r.R = 0x00;
       r.G = 0x00;
@@ -815,8 +815,9 @@
             }
     */
   }
-  void load_Huffman_table(Huffman_table *HT, unsigned char *nrcode,
-                          unsigned char *value, unsigned short int *Huff_code) {
+  void load_Huffman_table(Huffman_table *HT, const unsigned char *nrcode,
+                          const unsigned char *value,
+                          const unsigned short int *Huff_code) {
     unsigned char k, j, i;
     unsigned int code, code_index;
 
@@ -1001,7 +1002,7 @@
     return 1;
   }
 
-  void set_quant_table(uint8_t *basic_table, uint8_t scale_factor,
+  void set_quant_table(const uint8_t *basic_table, uint8_t scale_factor,
                        uint8_t *newtable)
   // Set quantization table and zigzag reorder it
   {
@@ -1307,8 +1308,8 @@
   std::array<int, 256> m_Y;
   unsigned long buffer_index;
   uint32_t codebuf, newbuf, readbuf;
-  uint8_t *std_luminance_qt;
-  uint8_t *std_chrominance_qt;
+  const unsigned char *std_luminance_qt;
+  const uint8_t *std_chrominance_qt;
 
   signed short int DCY, DCCb, DCCr;  // Coeficientii DC pentru Y,Cb,Cr
   signed short int DCT_coeff[384];
diff --git a/include/crow/g3_logger.hpp b/include/crow/g3_logger.hpp
index 8980207..748328e 100644
--- a/include/crow/g3_logger.hpp
+++ b/include/crow/g3_logger.hpp
@@ -1,8 +1,10 @@
 #pragma once
 
 // This file overrides the default crow logging framework to use g3 instead.
-// It implements enough of the interfaces of the crow logging framework to work correctly
-// but deletes the ILogHandler interface, as usage of that would be counter to the g3
+// It implements enough of the interfaces of the crow logging framework to work
+// correctly
+// but deletes the ILogHandler interface, as usage of that would be counter to
+// the g3
 // handler management, and would cause performance issues.
 
 #include <cstdio>
@@ -45,7 +47,7 @@
   }
 
   //
-  static void setLogLevel(LogLevel level) { }
+  static void setLogLevel(LogLevel level) {}
 
   static LogLevel get_current_log_level() { return get_log_level_ref(); }
 
@@ -61,29 +63,17 @@
   LogLevel level_;
 };
 }
+#ifndef CROW_DISABLE_LOGGING
+#define CROW_DISABLE_LOGGING false
+#endif
 
-#define CROW_LOG_CRITICAL LOG(FATAL)
-#define CROW_LOG_ERROR LOG(WARNING)
-#define CROW_LOG_WARNING LOG(WARNING)
-#define CROW_LOG_INFO LOG(INFO)
-#define CROW_LOG_DEBUG LOG(DEBUG)
-
-
-
-/*
-#define CROW_LOG_CRITICAL   \
-        if (false) \
-            crow::logger("CRITICAL", crow::LogLevel::Critical)
-#define CROW_LOG_ERROR      \
-        if (false) \
-            crow::logger("ERROR   ", crow::LogLevel::Error)
-#define CROW_LOG_WARNING    \
-        if (false) \
-            crow::logger("WARNING ", crow::LogLevel::Warning)
-#define CROW_LOG_INFO       \
-        if (false) \
-            crow::logger("INFO    ", crow::LogLevel::Info)
-#define CROW_LOG_DEBUG      \
-        if (false) \
-            crow::logger("DEBUG   ", crow::LogLevel::Debug)
-*/
\ No newline at end of file
+#define CROW_LOG_CRITICAL \
+  if (!CROW_DISABLE_LOGGING) LOG(FATAL)
+#define CROW_LOG_ERROR \
+  if (!CROW_DISABLE_LOGGING) LOG(WARNING)
+#define CROW_LOG_WARNING \
+  if (!CROW_DISABLE_LOGGING) LOG(WARNING)
+#define CROW_LOG_INFO \
+  if (!CROW_DISABLE_LOGGING) LOG(INFO)
+#define CROW_LOG_DEBUG \
+  if (!CROW_DISABLE_LOGGING) LOG(DEBUG)
diff --git a/include/test_utils.hpp b/include/test_utils.hpp
new file mode 100644
index 0000000..eb990d5
--- /dev/null
+++ b/include/test_utils.hpp
@@ -0,0 +1,6 @@
+#pragma once
+
+#include <string>
+
+bool gzipInflate(const std::string& compressedBytes,
+                 std::string& uncompressedBytes);
\ No newline at end of file
diff --git a/include/web_kvm.hpp b/include/web_kvm.hpp
index 62be097..df0bef5 100644
--- a/include/web_kvm.hpp
+++ b/include/web_kvm.hpp
@@ -51,6 +51,14 @@
   client_cut_text = 6
 };
 
+enum class server_to_client_message_type : uint8_t
+{
+    framebuffer_update = 0,
+    set_color_map_entries = 1,
+    bell_message = 2,
+    server_cut_text = 3
+};
+
 struct set_pixel_format_msg {
   boost::endian::big_uint8_t pad1;
   boost::endian::big_uint8_t pad2;
@@ -135,7 +143,7 @@
   std::string serialized(vector_size, 0);
 
   size_t i = 0;
-  serialized[i++] = 0;  // Type
+  serialized[i++] = static_cast<char>(server_to_client_message_type::framebuffer_update);  // Type
   serialized[i++] = 0;  // Pad byte
   boost::endian::big_uint16_t number_of_rectangles = msg.rectangles.size();
   std::memcpy(&serialized[i], &number_of_rectangles,
@@ -271,47 +279,47 @@
                     auto msg = reinterpret_cast<const frame_buffer_update_req*>(
                         data.data() + sizeof(client_to_server_msg_type));
 
-                      // Todo(ed) lifecycle of the video puller and decoder
-                      // should be
-                      // with the websocket, not recreated every time
-                      AstVideo::VideoPuller p;
-                      p.initialize();
-                      auto out = p.read_video();
-                      AstVideo::AstJpegDecoder d;
-                      d.decode(out.buffer, out.width, out.height, out.mode,
-                               out.y_selector, out.uv_selector);
+                    // Todo(ed) lifecycle of the video puller and decoder
+                    // should be
+                    // with the websocket, not recreated every time
+                    AstVideo::VideoPuller p;
+                    p.initialize();
+                    auto out = p.read_video();
+                    AstVideo::AstJpegDecoder d;
+                    d.decode(out.buffer, out.width, out.height, out.mode,
+                             out.y_selector, out.uv_selector);
 
-                      framebuffer_update_msg buffer_update_msg;
+                    framebuffer_update_msg buffer_update_msg;
 
-                      // If the viewer is requesting a full update, force write
-                      // of all pixels
+                    // If the viewer is requesting a full update, force write
+                    // of all pixels
 
-                      framebuffer_rectangle this_rect;
-                      this_rect.x = msg->x_position;
-                      this_rect.y = msg->y_position;
-                      this_rect.width = out.width;
-                      this_rect.height = out.height;
-                      this_rect.encoding =
-                          static_cast<uint8_t>(encoding_type::raw);
-                      LOG(DEBUG) << "Encoding is " << this_rect.encoding;
-                      this_rect.data.reserve(this_rect.width *
-                                             this_rect.height * 4);
-                      LOG(DEBUG) << "Width " << out.width << " Height "
-                                 << out.height;
+                    framebuffer_rectangle this_rect;
+                    this_rect.x = msg->x_position;
+                    this_rect.y = msg->y_position;
+                    this_rect.width = out.width;
+                    this_rect.height = out.height;
+                    this_rect.encoding =
+                        static_cast<uint8_t>(encoding_type::raw);
+                    LOG(DEBUG) << "Encoding is " << this_rect.encoding;
+                    this_rect.data.reserve(this_rect.width * this_rect.height *
+                                           4);
+                    LOG(DEBUG) << "Width " << out.width << " Height "
+                               << out.height;
 
-                      for (int i = 0; i < out.width * out.height; i++) {
-                        auto& pixel = d.OutBuffer[i];
-                        this_rect.data.push_back(pixel.B);
-                        this_rect.data.push_back(pixel.G);
-                        this_rect.data.push_back(pixel.R);
-                        this_rect.data.push_back(0);
-                      }
+                    for (int i = 0; i < out.width * out.height; i++) {
+                      auto& pixel = d.OutBuffer[i];
+                      this_rect.data.push_back(pixel.B);
+                      this_rect.data.push_back(pixel.G);
+                      this_rect.data.push_back(pixel.R);
+                      this_rect.data.push_back(0);
+                    }
 
-                      buffer_update_msg.rectangles.push_back(
-                          std::move(this_rect));
-                      auto serialized = serialize(buffer_update_msg);
+                    buffer_update_msg.rectangles.push_back(
+                        std::move(this_rect));
+                    auto serialized = serialize(buffer_update_msg);
 
-                      conn.send_binary(serialized);
+                    conn.send_binary(serialized);
 
                   }  // TODO(Ed) handle error
 
diff --git a/scripts/build_web_assets.py b/scripts/build_web_assets.py
index 857880e..264448e 100755
--- a/scripts/build_web_assets.py
+++ b/scripts/build_web_assets.py
@@ -87,12 +87,33 @@
     return string_content.encode()
 
 
-def filter_js(sha1_list, file_content):
+def embed_angular_templates(sha1_list, dependency_ordered_file_list, content_dict, file_content):
+    string_content = file_content.decode()
+    index = string_content.find("<script")
+    if index == -1:
+        raise Exception("Couldn't find first script tag in html?")
+    preload_string = ""
+    for full_filepath in dependency_ordered_file_list:
+        relative_path, _ = get_relative_path(full_filepath)
+        if re.search("partial-.*\\.html", relative_path):
+            sha1_path = get_sha1_path_from_relative(relative_path, sha1_list[relative_path])
 
+            print("full_filepath" + full_filepath)
+            preload_string += (
+                "<script type=\"text/ng-template\" id=\"" + sha1_path + "\">\n" +
+                open(full_filepath, 'r').read() +
+                "</script>\n"
+            )
+
+    for key in content_dict:
+        print(key)
+    string_content = string_content[:index] + preload_string + string_content[index:]
+    return string_content.encode()
+
+def filter_js(sha1_list, file_content):
     string_content = file_content.decode()
     for key, value in sha1_list.items():
         replace_name = get_sha1_path_from_relative(key, value)
-
         string_content_new = re.sub(key, replace_name, string_content)
         if string_content_new != string_content:
             print("    Replaced {}".format(key))
@@ -163,7 +184,7 @@
 
                 elif ext == ".js" or ext == ".css":
                     match = re.search(
-                        "([\"'](\.\./)*)(" + relative_replacename + ")([\"'\?])", file_content)
+                        "(\.\./)*" + relative_replacename, file_content)
                     if match:
                         depends_on[full_filepath].append(full_replacename)
 
@@ -191,6 +212,8 @@
 
         if extension == ".html" or relative_path == "/":
             new_file_content = filter_html(sha1_list, file_content)
+            if relative_path.endswith("index.html"):
+                new_file_content = embed_angular_templates(sha1_list, dependency_ordered_file_list, content_dict, new_file_content)
         elif extension == ".js" or extension == ".css":
             new_file_content = filter_js(sha1_list, file_content)
         else:
diff --git a/src/JTABLES.cpp b/src/JTABLES.cpp
new file mode 100644
index 0000000..0033c2b
--- /dev/null
+++ b/src/JTABLES.cpp
@@ -0,0 +1,286 @@
+#include <aspeed/JTABLES.H>
+
+static unsigned char zigzag[64] = {
+    0,  1,  5,  6,  14, 15, 27, 28, 2,  4,  7,  13, 16, 26, 29, 42,
+    3,  8,  12, 17, 25, 30, 41, 43, 9,  11, 18, 24, 31, 40, 44, 53,
+    10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60,
+    21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63};
+
+static unsigned char dezigzag[64 + 15] = {
+    0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40,
+    48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36,
+    29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61,
+    54, 47, 55, 62, 63,
+    // let corrupt input sample past end
+    63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63};
+
+static unsigned char *std_luminance_qt;
+static unsigned char *std_chrominance_qt;
+
+// Standard Huffman tables (cf. JPEG standard section K.3) */
+
+static unsigned char std_dc_luminance_nrcodes[17] = {0, 0, 1, 5, 1, 1, 1, 1, 1,
+                                                     1, 0, 0, 0, 0, 0, 0, 0};
+static unsigned char std_dc_luminance_values[12] = {0, 1, 2, 3, 4,  5,
+                                                    6, 7, 8, 9, 10, 11};
+
+static unsigned char std_dc_chrominance_nrcodes[17] = {
+    0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
+static unsigned char std_dc_chrominance_values[12] = {0, 1, 2, 3, 4,  5,
+                                                      6, 7, 8, 9, 10, 11};
+
+static unsigned char std_ac_luminance_nrcodes[17] = {
+    0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d};
+static unsigned char std_ac_luminance_values[162] = {
+    0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06,
+    0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+    0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72,
+    0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+    0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
+    0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+    0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75,
+    0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+    0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
+    0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+    0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
+    0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+    0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4,
+    0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa};
+
+static unsigned char std_ac_chrominance_nrcodes[17] = {
+    0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77};
+static unsigned char std_ac_chrominance_values[162] = {
+    0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
+    0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+    0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1,
+    0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+    0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44,
+    0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+    0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74,
+    0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+    0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a,
+    0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+    0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+    0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+    0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
+    0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa};
+
+unsigned short int DC_LUMINANCE_HUFFMANCODE[13 * 2] = {
+    /* 0 */ 0x0000,  0,
+    /* 1 */ 0x4000,  2,
+    /* 2 */ 0x6000,  3,
+    /* 3 */ 0x8000,  3,
+    /* 4 */ 0xA000,  3,
+    /* 5 */ 0xC000,  3,
+    /* 6 */ 0xE000,  3,
+    /* 7 */ 0xF000,  4,
+    /* 8 */ 0xF800,  5,
+    /* 9 */ 0xFC00,  6,
+    /* 10 */ 0xFE00, 7,
+    /* 11 */ 0xFF00, 8,
+    /* 12 */ 0xFFFF, 9,
+};
+
+unsigned short int DC_CHROMINANCE_HUFFMANCODE[13 * 2] = {
+    /* 0 */ 0x0000,  0,
+    /* 1 */ 0x4000,  2,
+    /* 2 */ 0x8000,  2,
+    /* 3 */ 0xC000,  2,
+    /* 4 */ 0xE000,  3,
+    /* 5 */ 0xF000,  4,
+    /* 6 */ 0xF800,  5,
+    /* 7 */ 0xFC00,  6,
+    /* 8 */ 0xFE00,  7,
+    /* 9 */ 0xFF00,  8,
+    /* 10 */ 0xFF80, 9,
+    /* 11 */ 0xFFC0, 10,
+    /* 12 */ 0xFFFF, 11,
+};
+
+unsigned short int AC_LUMINANCE_HUFFMANCODE[39 * 2] = {
+    /* 0 */ 0x0000,  0,
+    /* 1 */ 0x4000,  2,
+    /* 2 */ 0x8000,  2,
+    /* 3 */ 0xA000,  3,
+    /* 4 */ 0xB000,  4,
+    /* 5 */ 0xC000,  4,
+    /* 6 */ 0xD000,  4,
+    /* 7 */ 0xD800,  5,
+    /* 8 */ 0xE000,  5,
+    /* 9 */ 0xE800,  5,
+    /* 10 */ 0xEC00, 6,
+    /* 11 */ 0xF000, 6,
+    /* 12 */ 0xF200, 7,
+    /* 13 */ 0xF400, 7,
+    /* 14 */ 0xF600, 7,
+    /* 15 */ 0xF800, 7,
+    /* 16 */ 0xF900, 8,
+    /* 17 */ 0xFA00, 8,
+    /* 18 */ 0xFB00, 8,
+    /* 19 */ 0xFB80, 9,
+    /* 20 */ 0xFC00, 9,
+    /* 21 */ 0xFC80, 9,
+    /* 22 */ 0xFD00, 9,
+    /* 23 */ 0xFD80, 9,
+    /* 24 */ 0xFDC0, 10,
+    /* 25 */ 0xFE00, 10,
+    /* 26 */ 0xFE40, 10,
+    /* 27 */ 0xFE80, 10,
+    /* 28 */ 0xFEC0, 10,
+    /* 29 */ 0xFEE0, 11,
+    /* 30 */ 0xFF00, 11,
+    /* 31 */ 0xFF20, 11,
+    /* 32 */ 0xFF40, 11,
+    /* 33 */ 0xFF50, 12,
+    /* 34 */ 0xFF60, 12,
+    /* 35 */ 0xFF70, 12,
+    /* 36 */ 0xFF80, 12,
+    /* 37 */ 0xFF82, 15,
+    /* 38 */ 0xFFFF, 16,
+};
+
+unsigned short int AC_CHROMINANCE_HUFFMANCODE[45 * 2] = {
+    /* 0 */ 0x0000,  0,
+    /* 1 */ 0x4000,  2,
+    /* 2 */ 0x8000,  2,
+    /* 3 */ 0xA000,  3,
+    /* 4 */ 0xB000,  4,
+    /* 5 */ 0xC000,  4,
+    /* 6 */ 0xC800,  5,
+    /* 7 */ 0xD000,  5,
+    /* 8 */ 0xD800,  5,
+    /* 9 */ 0xE000,  5,
+    /* 10 */ 0xE400, 6,
+    /* 11 */ 0xE800, 6,
+    /* 12 */ 0xEC00, 6,
+    /* 13 */ 0xF000, 6,
+    /* 14 */ 0xF200, 7,
+    /* 15 */ 0xF400, 7,
+    /* 16 */ 0xF600, 7,
+    /* 17 */ 0xF700, 8,
+    /* 18 */ 0xF800, 8,
+    /* 19 */ 0xF900, 8,
+    /* 20 */ 0xFA00, 8,
+    /* 21 */ 0xFA80, 9,
+    /* 22 */ 0xFB00, 9,
+    /* 23 */ 0xFB80, 9,
+    /* 24 */ 0xFC00, 9,
+    /* 25 */ 0xFC80, 9,
+    /* 26 */ 0xFD00, 9,
+    /* 27 */ 0xFD80, 9,
+    /* 28 */ 0xFDC0, 10,
+    /* 29 */ 0xFE00, 10,
+    /* 30 */ 0xFE40, 10,
+    /* 31 */ 0xFE80, 10,
+    /* 32 */ 0xFEC0, 10,
+    /* 33 */ 0xFEE0, 11,
+    /* 34 */ 0xFF00, 11,
+    /* 35 */ 0xFF20, 11,
+    /* 36 */ 0xFF40, 11,
+    /* 37 */ 0xFF50, 12,
+    /* 38 */ 0xFF60, 12,
+    /* 39 */ 0xFF70, 12,
+    /* 40 */ 0xFF80, 12,
+    /* 41 */ 0xFF84, 14,
+    /* 42 */ 0xFF86, 15,
+    /* 43 */ 0xFF88, 15,
+    /* 44 */ 0xFFFF, 16,
+};
+
+//[100]=========================
+static unsigned char Tbl_100Y[64] = {
+    2, 1, 1, 2,  3,  5,  6,  7,  1, 1,  1,  2,  3,  7,  7,  6,
+    1, 1, 2, 3,  5,  7,  8,  7,  1, 2,  2,  3,  6,  10, 10, 7,
+    2, 2, 4, 7,  8,  13, 12, 9,  3, 4,  6,  8,  10, 13, 14, 11,
+    6, 8, 9, 10, 12, 15, 15, 12, 9, 11, 11, 12, 14, 12, 12, 12};
+static unsigned char Tbl_100UV[64] = {
+    3,  3,  4,  8,  18, 18, 18, 18, 3,  3,  4,  12, 18, 18, 18, 18,
+    4,  4,  10, 18, 18, 18, 18, 18, 8,  12, 18, 18, 18, 18, 18, 18,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18};
+
+//[086]=========================
+static unsigned char Tbl_086Y[64] = {
+    3, 2,  1,  3,  4,  7,  9,  11, 2,  2,  2,  3,  4,  10, 11, 10,
+    2, 2,  3,  4,  7,  10, 12, 10, 2,  3,  4,  5,  9,  16, 15, 11,
+    3, 4,  6,  10, 12, 20, 19, 14, 4,  6,  10, 12, 15, 19, 21, 17,
+    9, 12, 14, 16, 19, 22, 22, 18, 13, 17, 17, 18, 21, 18, 19, 18};
+static unsigned char Tbl_086UV[64] = {
+    4,  5,  6,  13, 27, 27, 27, 27, 5,  5,  7,  18, 27, 27, 27, 27,
+    6,  7,  15, 27, 27, 27, 27, 27, 13, 18, 27, 27, 27, 27, 27, 27,
+    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27};
+
+//[071]=========================
+static unsigned char Tbl_071Y[64] = {
+    6,  4,  3,  6,  9,  15, 19, 22, 4,  4,  5,  7,  9,  21, 22, 20,
+    5,  4,  6,  9,  15, 21, 25, 21, 5,  6,  8,  10, 19, 32, 30, 23,
+    6,  8,  13, 21, 25, 40, 38, 28, 9,  13, 20, 24, 30, 39, 42, 34,
+    18, 24, 29, 32, 38, 45, 45, 37, 27, 34, 35, 36, 42, 37, 38, 37};
+static unsigned char Tbl_071UV[64] = {
+    9,  10, 13, 26, 55, 55, 55, 55, 10, 11, 14, 37, 55, 55, 55, 55,
+    13, 14, 31, 55, 55, 55, 55, 55, 26, 37, 55, 55, 55, 55, 55, 55,
+    55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
+    55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55};
+//[057]=========================
+static unsigned char Tbl_057Y[64] = {
+    9,  6,  5,  9,  13, 22, 28, 34, 6,  6,  7,  10, 14, 32, 33, 30,
+    7,  7,  9,  13, 22, 32, 38, 31, 7,  9,  12, 16, 28, 48, 45, 34,
+    10, 12, 20, 31, 38, 61, 57, 43, 13, 19, 30, 36, 45, 58, 63, 51,
+    27, 36, 43, 48, 57, 68, 67, 56, 40, 51, 53, 55, 63, 56, 57, 55};
+static unsigned char Tbl_057UV[64] = {
+    13, 14, 19, 38, 80, 80, 80, 80, 14, 17, 21, 53, 80, 80, 80, 80,
+    19, 21, 45, 80, 80, 80, 80, 80, 38, 53, 80, 80, 80, 80, 80, 80,
+    80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
+    80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80};
+
+//[043]=========================
+static unsigned char Tbl_043Y[64] = {
+    11, 7,  7,  11, 17, 28, 36, 43, 8,  8,  10, 13, 18, 41, 43, 39,
+    10, 9,  11, 17, 28, 40, 49, 40, 10, 12, 15, 20, 36, 62, 57, 44,
+    12, 15, 26, 40, 48, 78, 74, 55, 17, 25, 39, 46, 58, 74, 81, 66,
+    35, 46, 56, 62, 74, 86, 86, 72, 51, 66, 68, 70, 80, 71, 74, 71};
+static unsigned char Tbl_043UV[64] = {
+    18,  19,  26,  51,  108, 108, 108, 108, 19,  22,  28,  72,  108,
+    108, 108, 108, 26,  28,  61,  108, 108, 108, 108, 108, 51,  72,
+    108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108,
+    108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108,
+    108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108};
+
+//[029]=========================
+static unsigned char Tbl_029Y[64] = {
+    14, 9,  9,  14, 21, 36,  46,  55, 10, 10, 12, 17, 23,  52, 54,  49,
+    12, 11, 14, 21, 36, 51,  62,  50, 12, 15, 19, 26, 46,  78, 72,  56,
+    16, 19, 33, 50, 61, 98,  93,  69, 21, 31, 49, 58, 73,  94, 102, 83,
+    44, 58, 70, 78, 93, 109, 108, 91, 65, 83, 86, 88, 101, 90, 93,  89};
+static unsigned char Tbl_029UV[64] = {
+    22,  24,  32,  63,  133, 133, 133, 133, 24,  28,  34,  88,  133,
+    133, 133, 133, 32,  34,  75,  133, 133, 133, 133, 133, 63,  88,
+    133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133,
+    133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133,
+    133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133};
+
+//[014]=========================
+static unsigned char Tbl_014Y[64] = {
+    17, 12, 10, 17, 26,  43,  55,  66,  13, 13,  15,  20,  28,  63,  65,  60,
+    15, 14, 17, 26, 43,  62,  75,  61,  15, 18,  24,  31,  55,  95,  87,  67,
+    19, 24, 40, 61, 74,  119, 112, 84,  26, 38,  60,  70,  88,  113, 123, 100,
+    53, 70, 85, 95, 112, 132, 131, 110, 78, 100, 103, 107, 122, 109, 112, 108};
+static unsigned char Tbl_014UV[64] = {
+    27,  29,  39,  76,  160, 160, 160, 160, 29,  34,  42,  107, 160,
+    160, 160, 160, 39,  42,  91,  160, 160, 160, 160, 160, 76,  107,
+    160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+    160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+    160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160};
+//[000]=========================
+static unsigned char Tbl_000Y[64] = {
+    20, 13, 12, 20,  30,  50,  63,  76,  15, 15,  17,  23,  32,  72,  75,  68,
+    17, 16, 20, 30,  50,  71,  86,  70,  17, 21,  27,  36,  63,  108, 100, 77,
+    22, 27, 46, 70,  85,  136, 128, 96,  30, 43,  68,  80,  101, 130, 141, 115,
+    61, 80, 97, 108, 128, 151, 150, 126, 90, 115, 118, 122, 140, 125, 128, 123};
+static unsigned char Tbl_000UV[64] = {
+    31,  33,  45,  88,  185, 185, 185, 185, 33,  39,  48,  123, 185,
+    185, 185, 185, 45,  48,  105, 185, 185, 185, 185, 185, 88,  123,
+    185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185,
+    185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185,
+    185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185};
\ No newline at end of file
diff --git a/src/ast_jpeg_decoder_test.cpp b/src/ast_jpeg_decoder_test.cpp
index 5b9e769..22c9ecf 100644
--- a/src/ast_jpeg_decoder_test.cpp
+++ b/src/ast_jpeg_decoder_test.cpp
@@ -1,6 +1,6 @@
 #include "ast_jpeg_decoder.hpp"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
 
 #ifdef BUILD_CIMG
 #define cimg_display 0
@@ -85,7 +85,7 @@
     }
   }
 }
-/*
+
 TEST(AstJpegDecoder, TestColors) {
   AstVideo::RawVideoBuffer out;
 
@@ -110,7 +110,7 @@
            out.uv_selector);
 
   int tolerance = 16;
-
+  /*
   for (int i = 0; i < out.width * out.height; i++) {
     AstVideo::RGB &pixel = d.OutBuffer[i];
     EXPECT_GT(pixel.R, 0x8E - tolerance);
@@ -120,8 +120,9 @@
     EXPECT_GT(pixel.B, 0xF1 - tolerance);
     EXPECT_LT(pixel.B, 0xF1 + tolerance);
   }
+  */
 }
-*/
+
 // Tests the buffers around the screen aren't written to
 TEST(AstJpegDecoder, BufferLimits) {
   AstVideo::RawVideoBuffer out;
diff --git a/src/ci_map_tests.cpp b/src/ci_map_tests.cpp
new file mode 100644
index 0000000..acaaa6e
--- /dev/null
+++ b/src/ci_map_tests.cpp
@@ -0,0 +1,78 @@
+#include "crow/ci_map.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace testing;
+
+TEST(CiMap, MapEmpty) {
+  crow::ci_map map;
+  EXPECT_TRUE(map.empty());
+  EXPECT_EQ(map.size(), 0);
+
+  map.emplace("foo", "bar");
+
+  map.clear();
+  EXPECT_TRUE(map.empty());
+}
+
+TEST(CiMap, MapBasicInsert) {
+  crow::ci_map map;
+  map.emplace("foo", "bar");
+  auto x = map.find("foo");
+  ASSERT_NE(x, map.end());
+
+  EXPECT_EQ(map.find("foo")->first, "foo");
+  EXPECT_EQ(map.find("foo")->second, "bar");
+  EXPECT_EQ(map.find("FOO")->first, "foo");
+  EXPECT_EQ(map.find("FOO")->second, "bar");
+}
+
+TEST(CiMap, MapManyInsert) {
+  crow::ci_map map;
+  map.emplace("foo", "car");
+  map.emplace("foo", "boo");
+  map.emplace("bar", "cat");
+  map.emplace("baz", "bat");
+
+  EXPECT_EQ(map.size(), 3);
+  ASSERT_NE(map.find("foo"), map.end());
+  EXPECT_EQ(map.find("foo")->first, "foo");
+  EXPECT_EQ(map.find("foo")->second, "car");
+
+  ASSERT_NE(map.find("FOO"), map.end());
+  EXPECT_EQ(map.find("FOO")->first, "foo");
+  EXPECT_EQ(map.find("FOO")->second, "car");
+  
+  ASSERT_NE(map.find("bar"), map.end());
+  EXPECT_EQ(map.find("bar")->first, "bar");
+  EXPECT_EQ(map.find("bar")->second, "cat");
+
+  ASSERT_NE(map.find("BAR"), map.end());
+  EXPECT_EQ(map.find("BAR")->first, "bar");
+  EXPECT_EQ(map.find("BAR")->second, "cat");
+
+  ASSERT_NE(map.find("baz"), map.end());
+  EXPECT_EQ(map.find("baz")->first, "baz");
+  EXPECT_EQ(map.find("baz")->second, "bat");
+
+  ASSERT_NE(map.find("BAZ"), map.end());
+  EXPECT_EQ(map.find("BAZ")->first, "baz");
+  EXPECT_EQ(map.find("BAZ")->second, "bat");
+
+  EXPECT_EQ(map.count("foo"), 1);
+  EXPECT_EQ(map.count("bar"), 1);
+  EXPECT_EQ(map.count("baz"), 1);
+  EXPECT_EQ(map.count("FOO"), 1);
+  EXPECT_EQ(map.count("BAR"), 1);
+  EXPECT_EQ(map.count("BAZ"), 1);
+}
+
+TEST(CiMap, MapMultiInsert) {
+  crow::ci_map map;
+  map.emplace("foo", "bar1");
+  map.emplace("foo", "bar2");
+  EXPECT_EQ(map.count("foo"), 1);
+  EXPECT_EQ(map.count("FOO"), 1);
+  EXPECT_EQ(map.count("fOo"), 1);
+  EXPECT_EQ(map.count("FOo"), 1);
+}
\ No newline at end of file
diff --git a/src/crowtest/crow_unittest.cpp b/src/crow_test.cpp
similarity index 100%
rename from src/crowtest/crow_unittest.cpp
rename to src/crow_test.cpp
diff --git a/src/crowtest/about.txt b/src/crowtest/about.txt
deleted file mode 100644
index bd55fd1..0000000
--- a/src/crowtest/about.txt
+++ /dev/null
@@ -1 +0,0 @@
-This folder contains a port of the CROW unit tests, ported to google test to maek them easier to run
\ No newline at end of file
diff --git a/src/getvideo_main.cpp b/src/getvideo_main.cpp
index cd7f09c..8c92bd3 100644
--- a/src/getvideo_main.cpp
+++ b/src/getvideo_main.cpp
@@ -1,4 +1,3 @@
-
 #include <fcntl.h>
 #include <unistd.h>
 #include <chrono>
diff --git a/src/kvm_websocket_test.cpp b/src/kvm_websocket_test.cpp
new file mode 100644
index 0000000..d690305
--- /dev/null
+++ b/src/kvm_websocket_test.cpp
@@ -0,0 +1,102 @@
+#include <iostream>
+#include <sstream>
+#include <vector>
+#include "test_utils.hpp"
+#include "web_kvm.hpp"
+#include "crow.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace crow;
+using namespace testing;
+
+// Tests static files are loaded correctly
+TEST(Kvm, BasicRfb) {
+  SimpleApp app;
+
+  crow::kvm::request_routes(app);
+  app.bindaddr("127.0.0.1").port(45451);
+  CROW_ROUTE(app, "/")([]() { return 200; });
+  auto _ = async(std::launch::async, [&] { app.run(); });
+  auto routes = app.get_routes();
+  asio::io_service is;
+
+  {
+    // Retry a couple of times waiting for the server to come up
+    // TODO(ed)  This is really unfortunate, and should use some form of mock
+    asio::ip::tcp::socket c(is);
+    for (int i = 0; i < 200; i++) {
+      try {
+        c.connect(asio::ip::tcp::endpoint(
+            asio::ip::address::from_string("127.0.0.1"), 45451));
+        c.close();
+        break;
+      } catch (std::exception e) {
+        // do nothing.  We expect this to fail while the server is starting up
+      }
+    }
+  }
+
+  // Get the websocket
+  std::string sendmsg =
+      ("GET /kvmws HTTP/1.1\r\n"
+       "Host: localhost:45451\r\n"
+       "Connection: Upgrade\r\n"
+       "Upgrade: websocket\r\n"
+       "Sec-WebSocket-Version: 13\r\n"
+       "Sec-WebSocket-Key: aLeGkmLPZmdv5tTyEpJ3jQ==\r\n"
+       "Sec-WebSocket-Extensions: permessage-deflate; "
+       "client_max_window_bits\r\n"
+       "Sec-WebSocket-Protocol: binary\r\n"
+       "\r\n");
+
+  asio::ip::tcp::socket socket(is);
+  socket.connect(asio::ip::tcp::endpoint(
+      asio::ip::address::from_string("127.0.0.1"), 45451));
+  socket.send(asio::buffer(sendmsg));
+
+  // Read the response status line. The response streambuf will automatically
+  // grow to accommodate the entire line. The growth may be limited by passing
+  // a maximum size to the streambuf constructor.
+  boost::asio::streambuf response;
+  boost::asio::read_until(socket, response, "\r\n");
+
+  // Check that response is OK.
+  std::istream response_stream(&response);
+  std::string http_response;
+  std::getline(response_stream, http_response);
+
+  EXPECT_EQ(http_response, "HTTP/1.1 101 Switching Protocols\r");
+
+  // Read the response headers, which are terminated by a blank line.
+  boost::asio::read_until(socket, response, "\r\n\r\n");
+
+  // Process the response headers.
+  std::string header;
+  std::vector<std::string> headers;
+  while (std::getline(response_stream, header) && header != "\r") {
+    headers.push_back(header);
+  }
+
+  EXPECT_THAT(headers, Contains("Upgrade: websocket\r"));
+  EXPECT_THAT(headers, Contains("Connection: Upgrade\r"));
+  EXPECT_THAT(headers, Contains("Sec-WebSocket-Protocol: binary\r"));
+  // TODO(ed) This is the result that it gives today.  Need to check websocket
+  // docs and make
+  // sure that this calclution is actually being done to spec
+  EXPECT_THAT(headers,
+              Contains("Sec-WebSocket-Accept: /CnDM3l79rIxniLNyxMryXbtLEU=\r"));
+  std::array<char, 13> rfb_open_string;
+
+  //
+  // socket.receive(rfb_open_string.data(), rfb_open_string.size());
+  boost::asio::read(socket, boost::asio::buffer(rfb_open_string));
+  auto open_string =
+      std::string(std::begin(rfb_open_string), std::end(rfb_open_string));
+  // Todo(ed) find out what the two characters at the end of the websocket
+  // stream are
+  open_string = open_string.substr(2);
+  EXPECT_EQ(open_string, "RFB 003.008");
+
+  app.stop();
+}
\ No newline at end of file
diff --git a/src/msan_test.cpp b/src/msan_test.cpp
index 047d3cf..9fcb9d5 100644
--- a/src/msan_test.cpp
+++ b/src/msan_test.cpp
@@ -1,5 +1,5 @@
-#include "gtest/gtest.h"
 #include <string>
+#include "gtest/gtest.h"
 
 TEST(MemorySanitizer, TestIsWorking) {
   std::string foo("foo");
diff --git a/src/security_headers_middleware.cpp b/src/security_headers_middleware.cpp
index bcaa87d..265cda7 100644
--- a/src/security_headers_middleware.cpp
+++ b/src/security_headers_middleware.cpp
@@ -2,19 +2,38 @@
 
 namespace crow {
 
+static const std::string strict_transport_security_key =
+    "Strict-Transport-Security";
+static const std::string strict_transport_security_value =
+    "max-age=31536000; includeSubdomains; preload";
+
+static const std::string ua_compatability_key = "X-UA-Compatible";
+static const std::string ua_compatability_value = "IE=11";
+
+static const std::string xframe_key = "X-Frame-Options";
+static const std::string xframe_value = "DENY";
+
+static const std::string xss_key = "X-XSS-Protection";
+static const std::string xss_value = "1; mode=block";
+
+static const std::string content_security_key = "X-Content-Security-Policy";
+static const std::string content_security_value = "default-src 'self'";
+
 void SecurityHeadersMiddleware::before_handle(crow::request& req, response& res,
                                               context& ctx) {}
 
 void SecurityHeadersMiddleware::after_handle(request& /*req*/, response& res,
                                              context& ctx) {
-  // TODO(ed) these should really check content types.  for example, X-UA-Compatible
-  // header doesn't make sense when retrieving a JSON or javascript file.  It doesn't
-  // hurt anything, it's just ugly.
-  res.set_header("Strict-Transport-Security",
-                 "max-age=31536000; includeSubdomains; preload");
-  res.set_header("X-UA-Compatible", "IE=11");
-  res.set_header("X-Frame-Options", "DENY");
-  res.set_header("X-XSS-Protection", "1; mode=block");
-  res.set_header("X-Content-Security-Policy", "default-src 'self'");
+  /*
+   TODO(ed) these should really check content types.  for example,
+   X-UA-Compatible header doesn't make sense when retrieving a JSON or
+   javascript file.  It doesn't hurt anything, it's just ugly.
+   */
+  res.add_header(strict_transport_security_key,
+                 strict_transport_security_value);
+  res.add_header(ua_compatability_key, ua_compatability_value);
+  res.add_header(xframe_key, xframe_value);
+  res.add_header(xss_key, xss_value);
+  res.add_header(content_security_key, content_security_value);
 }
 }
diff --git a/src/security_headers_middleware_test.cpp b/src/security_headers_middleware_test.cpp
index fc183e9..5045215 100644
--- a/src/security_headers_middleware_test.cpp
+++ b/src/security_headers_middleware_test.cpp
@@ -1,7 +1,7 @@
-#include <crow/app.h>
-#include <gmock/gmock.h>
 #include <security_headers_middleware.hpp>
-#include "gtest/gtest.h"
+#include <crow/app.h>
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
 
 using namespace crow;
 using namespace std;
diff --git a/src/test_utils.cpp b/src/test_utils.cpp
new file mode 100644
index 0000000..65ef721
--- /dev/null
+++ b/src/test_utils.cpp
@@ -0,0 +1,67 @@
+#include <zlib.h>
+#include <test_utils.hpp>
+#include <cstring>
+
+bool gzipInflate(const std::string& compressedBytes,
+                 std::string& uncompressedBytes) {
+  if (compressedBytes.size() == 0) {
+    uncompressedBytes = compressedBytes;
+    return true;
+  }
+
+  uncompressedBytes.clear();
+
+  unsigned full_length = compressedBytes.size();
+  unsigned half_length = compressedBytes.size() / 2;
+
+  unsigned uncompLength = full_length;
+  char* uncomp = (char*)calloc(sizeof(char), uncompLength);
+
+  z_stream strm;
+  strm.next_in = (Bytef*)compressedBytes.c_str();
+  strm.avail_in = compressedBytes.size();
+  strm.total_out = 0;
+  strm.zalloc = Z_NULL;
+  strm.zfree = Z_NULL;
+
+  bool done = false;
+
+  if (inflateInit2(&strm, (16 + MAX_WBITS)) != Z_OK) {
+    free(uncomp);
+    return false;
+  }
+
+  while (!done) {
+    // If our output buffer is too small
+    if (strm.total_out >= uncompLength) {
+      // Increase size of output buffer
+      char* uncomp2 = (char*)calloc(sizeof(char), uncompLength + half_length);
+      std::memcpy(uncomp2, uncomp, uncompLength);
+      uncompLength += half_length;
+      free(uncomp);
+      uncomp = uncomp2;
+    }
+
+    strm.next_out = (Bytef*)(uncomp + strm.total_out);
+    strm.avail_out = uncompLength - strm.total_out;
+
+    // Inflate another chunk.
+    int err = inflate(&strm, Z_SYNC_FLUSH);
+    if (err == Z_STREAM_END)
+      done = true;
+    else if (err != Z_OK) {
+      break;
+    }
+  }
+
+  if (inflateEnd(&strm) != Z_OK) {
+    free(uncomp);
+    return false;
+  }
+
+  for (size_t i = 0; i < strm.total_out; ++i) {
+    uncompressedBytes += uncomp[i];
+  }
+  free(uncomp);
+  return true;
+}
\ No newline at end of file
diff --git a/src/token_authorization_middleware.cpp b/src/token_authorization_middleware.cpp
index 4c7a2d4..8b109e0 100644
--- a/src/token_authorization_middleware.cpp
+++ b/src/token_authorization_middleware.cpp
@@ -1,10 +1,10 @@
-#include <boost/algorithm/string/predicate.hpp>
 #include <random>
 #include <unordered_map>
+#include <boost/algorithm/string/predicate.hpp>
 
-#include <crow/logging.h>
 #include <base64.hpp>
 #include <token_authorization_middleware.hpp>
+#include <crow/logging.h>
 
 namespace crow {
 
@@ -29,7 +29,7 @@
     res.end();
   };
 
-  LOG(DEBUG) << "Token Auth Got route " << req.url;
+  CROW_LOG_DEBUG << "Token Auth Got route " << req.url;
 
   if (req.url == "/" || boost::starts_with(req.url, "/static/")) {
     // TODO this is total hackery to allow the login page to work before the
diff --git a/src/token_authorization_middleware_test.cpp b/src/token_authorization_middleware_test.cpp
index c01e7f9..e8277653 100644
--- a/src/token_authorization_middleware_test.cpp
+++ b/src/token_authorization_middleware_test.cpp
@@ -1,7 +1,7 @@
+#include "token_authorization_middleware.hpp"
 #include <crow/app.h>
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
-#include "token_authorization_middleware.hpp"
 
 using namespace crow;
 using namespace std;
diff --git a/src/udpclient.cpp b/src/udpclient.cpp
index cf9f3d1..9bebd6e 100644
--- a/src/udpclient.cpp
+++ b/src/udpclient.cpp
@@ -8,9 +8,8 @@
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 //
 #include <array>
-#include <boost/array.hpp>
-#include <boost/asio.hpp>
 #include <iostream>
+#include <boost/asio.hpp>
 
 using boost::asio::ip::udp;
 
@@ -44,7 +43,7 @@
         0x0E + 0x80;  // E is defined in spec as this channel
                       // 0x80 is requesting IPMI 2.0
     uint8_t byte1 = static_cast<uint8_t>(channel_number | 0x80);
-    boost::array<uint8_t, 2> payload{byte1, privilege_level};
+    std::array<uint8_t, 2> payload{byte1, privilege_level};
 
     int payload_sum = 0;
     for (auto element : payload) {
diff --git a/src/webassets_test.cpp b/src/webassets_test.cpp
index 8d0cfef..1d02171 100644
--- a/src/webassets_test.cpp
+++ b/src/webassets_test.cpp
@@ -1,85 +1,20 @@
 #include <crow/app.h>
 #include <gmock/gmock.h>
-#include <zlib.h>
+
+#include <test_utils.hpp>
+#include <webassets.hpp>
+#include <sstream>
 #include <boost/algorithm/string/predicate.hpp>
 #include <boost/iostreams/copy.hpp>
 #include <boost/iostreams/filter/gzip.hpp>
 #include <boost/iostreams/filtering_streambuf.hpp>
 #include <boost/lexical_cast.hpp>
-#include <sstream>
-#include <webassets.hpp>
 #include "gtest/gtest.h"
+
 using namespace crow;
 using namespace std;
 using namespace testing;
 
-bool gzipInflate(const std::string& compressedBytes,
-                 std::string& uncompressedBytes) {
-  if (compressedBytes.size() == 0) {
-    uncompressedBytes = compressedBytes;
-    return true;
-  }
-
-  uncompressedBytes.clear();
-
-  unsigned full_length = compressedBytes.size();
-  unsigned half_length = compressedBytes.size() / 2;
-
-  unsigned uncompLength = full_length;
-  char* uncomp = (char*)calloc(sizeof(char), uncompLength);
-
-  z_stream strm;
-  strm.next_in = (Bytef*)compressedBytes.c_str();
-  strm.avail_in = compressedBytes.size();
-  strm.total_out = 0;
-  strm.zalloc = Z_NULL;
-  strm.zfree = Z_NULL;
-
-  bool done = false;
-
-  if (inflateInit2(&strm, (16 + MAX_WBITS)) != Z_OK) {
-    free(uncomp);
-    return false;
-  }
-
-  while (!done) {
-    // If our output buffer is too small
-    if (strm.total_out >= uncompLength) {
-      // Increase size of output buffer
-      char* uncomp2 = (char*)calloc(sizeof(char), uncompLength + half_length);
-      memcpy(uncomp2, uncomp, uncompLength);
-      uncompLength += half_length;
-      free(uncomp);
-      uncomp = uncomp2;
-    }
-
-    strm.next_out = (Bytef*)(uncomp + strm.total_out);
-    strm.avail_out = uncompLength - strm.total_out;
-
-    // Inflate another chunk.
-    int err = inflate(&strm, Z_SYNC_FLUSH);
-    if (err == Z_STREAM_END)
-      done = true;
-    else if (err != Z_OK) {
-      break;
-    }
-  }
-
-  if (inflateEnd(&strm) != Z_OK) {
-    free(uncomp);
-    return false;
-  }
-
-  for (size_t i = 0; i < strm.total_out; ++i) {
-    uncompressedBytes += uncomp[i];
-  }
-  free(uncomp);
-  return true;
-}
-
-
-
-
 // Tests static files are loaded correctly
 TEST(Webassets, StaticFilesFixedRoutes) {
   std::array<char, 2048> buf;
@@ -151,8 +86,6 @@
   server.stop();
 }
 
-
-
 // Tests static files are loaded correctly
 TEST(Webassets, EtagIsSane) {
   std::array<char, 2048> buf;
diff --git a/src/webserver_main.cpp b/src/webserver_main.cpp
index d77d822..2ec7e37 100644
--- a/src/webserver_main.cpp
+++ b/src/webserver_main.cpp
@@ -21,10 +21,12 @@
 #include "crow/websocket.h"
 
 #include "color_cout_g3_sink.hpp"
-#include "webassets.hpp"
-
 #include "security_headers_middleware.hpp"
+#include "ssl_key_handler.hpp"
 #include "token_authorization_middleware.hpp"
+#include "web_kvm.hpp"
+#include "webassets.hpp"
+#include "webassets.hpp"
 
 #include <boost/asio.hpp>
 #include <boost/endian/arithmetic.hpp>
@@ -34,10 +36,6 @@
 #include <string>
 #include <unordered_set>
 
-#include <web_kvm.hpp>
-#include <webassets.hpp>
-#include "ssl_key_handler.hpp"
-
 int main(int argc, char** argv) {
   auto worker(g3::LogWorker::createLogWorker());
   std::string logger_name("bmcweb");
@@ -117,6 +115,8 @@
 
       });
   auto ssl_context = ensuressl::get_ssl_context(ssl_pem_file);
-  app.port(18080).ssl(std::move(ssl_context)).run();
+  app.port(18080)
+      //.ssl(std::move(ssl_context))
+      //.concurrency(4)
+      .run();
 }
-
diff --git a/static/css/font-awesome.css b/static/css/font-awesome.css
index a67a323..d7de407 100644
--- a/static/css/font-awesome.css
+++ b/static/css/font-awesome.css
@@ -6,7 +6,7 @@
  * -------------------------- */
 @font-face {
   font-family: 'FontAwesome';
-  /* WARNING: This line is modified from stock FA, to make cachign work*/
+  /* WARNING: This line is modified from stock FA, to make caching work*/
   src: url('../../static/fonts/fontawesome-webfont.woff') format('woff');
   font-weight: normal;
   font-style: normal;
diff --git a/static/css/intel.css b/static/css/intel.css
index 5080c77..5ce5e38 100644
--- a/static/css/intel.css
+++ b/static/css/intel.css
@@ -561,3 +561,10 @@
 .table-striped-invert > tbody > tr:nth-child(2n+1) > td, .table-striped > tbody > tr:nth-child(2n+1) > th {
        background-color: #ffffff;
 }
+
+
+.div-fake-hidden {
+    width:0px;
+    height:0px;
+    overflow:hidden;
+}
\ No newline at end of file
diff --git a/static/index.html b/static/index.html
index f0f4148..687aa64 100644
--- a/static/index.html
+++ b/static/index.html
@@ -3,74 +3,75 @@
 
 <head>
     <meta charset="utf-8" />
-    <meta http-equiv="X-UA-Compatible" content="IE=edge">
-    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+    <meta name="viewport" content="width=device-width, initial-scale=1" />
     <title>Integrated BMC Console</title>
 
-    <link href="static/css/bootstrap.css" rel="stylesheet">
-    <link href="static/css/font-awesome.css" rel="stylesheet" >  
-    <link href="static/css/intel.css" rel="stylesheet">
+    <link href="static/css/bootstrap.css" rel="stylesheet" />
+    <link href="static/css/font-awesome.css" rel="stylesheet" />
+    <link href="static/css/intel.css" rel="stylesheet" />
 
     <link rel="icon" href="static/favicon.ico" type="image/x-icon" />
 
-    <script type="text/javascript" src="static/js/angular.js"></script>
-    <script type="text/javascript" src="static/js/angular-animate.js"></script>
-    <script type="text/javascript" src="static/js/angular-sanitize.js"></script>
-    <script type="text/javascript" src="static/js/angular-cookies.js"></script>
-    <script type="text/javascript" src="static/js/angular-resource.js"></script>
-    <script type="text/javascript" src="static/js/angular-ui-router.js"></script>
-    <script type="text/javascript" src="static/js/angular-websocket.js"></script>
-    <script type="text/javascript" src="static/js/lodash.core.js"></script>
+    <script type="text/javascript" src="static/js/angular.js" defer></script>
+    <script type="text/javascript" src="static/js/angular-animate.js" defer></script>
+    <script type="text/javascript" src="static/js/angular-sanitize.js" defer></script>
+    <script type="text/javascript" src="static/js/angular-cookies.js" defer></script>
+    <script type="text/javascript" src="static/js/angular-resource.js" defer></script>
+    <script type="text/javascript" src="static/js/angular-ui-router.js" defer></script>
+    <script type="text/javascript" src="static/js/angular-websocket.js" defer></script>
+    <script type="text/javascript" src="static/js/lodash.core.js" defer></script>
 
-    <script type="text/javascript" src="static/js/ui-bootstrap-tpls-2.1.3.js"></script>
+    <script type="text/javascript" src="static/js/ui-bootstrap-tpls-2.1.3.js" defer></script>
 
-    <script type="text/javascript" src="static/js/bmcApp.js"></script>
-    <script type="text/javascript" src="static/js/base64.js"></script>
-    <script type="text/javascript" src="static/js/versionController.js"></script>
-    <script type="text/javascript" src="static/js/selController.js"></script>
-    <script type="text/javascript" src="static/js/loginController.js"></script>
-    <script type="text/javascript" src="static/js/kvmController.js"></script>
-    <script type="text/javascript" src="static/js/ipmiController.js"></script>
- 
-    <script type="text/javascript" src="static/noVNC/core/util.js"></script>
-    <script type="text/javascript" src="static/noVNC/app/webutil.js"></script>  
+    <script type="text/javascript" src="static/js/bmcApp.js" defer></script>
+    <script type="text/javascript" src="static/js/base64.js" defer></script>
+    <script type="text/javascript" src="static/js/versionController.js" defer></script>
+    <script type="text/javascript" src="static/js/selController.js" defer></script>
+    <script type="text/javascript" src="static/js/loginController.js" defer></script>
+    <script type="text/javascript" src="static/js/kvmController.js" defer></script>
+    <script type="text/javascript" src="static/js/ipmiController.js" defer></script>
 
-    <script type="text/javascript" src="static/noVNC/core/base64.js"></script>
-    <script type="text/javascript" src="static/noVNC/core/websock.js"></script>
-    <script type="text/javascript" src="static/noVNC/core/des.js"></script>
-    <script type="text/javascript" src="static/noVNC/core/input/keysymdef.js"></script>
-    <script type="text/javascript" src="static/noVNC/core/input/xtscancodes.js"></script>
-    <script type="text/javascript" src="static/noVNC/core/input/util.js"></script>
-    <script type="text/javascript" src="static/noVNC/core/input/devices.js"></script>
-    <script type="text/javascript" src="static/noVNC/core/display.js"></script>
-    <script type="text/javascript" src="static/noVNC/core/inflator.js"></script>
-    <script type="text/javascript" src="static/noVNC/core/rfb.js"></script>
-    <script type="text/javascript" src="static/noVNC/core/input/keysym.js"></script> 
+    <script type="text/javascript" src="static/noVNC/core/util.js" defer></script>
+    <script type="text/javascript" src="static/noVNC/app/webutil.js" defer></script>
+
+    <script type="text/javascript" src="static/noVNC/core/base64.js" defer></script>
+    <script type="text/javascript" src="static/noVNC/core/websock.js" defer></script>
+    <script type="text/javascript" src="static/noVNC/core/des.js" defer></script>
+    <script type="text/javascript" src="static/noVNC/core/input/keysymdef.js" defer></script>
+    <script type="text/javascript" src="static/noVNC/core/input/xtscancodes.js" defer></script>
+    <script type="text/javascript" src="static/noVNC/core/input/util.js" defer></script>
+    <script type="text/javascript" src="static/noVNC/core/input/devices.js" defer></script>
+    <script type="text/javascript" src="static/noVNC/core/display.js" defer></script>
+    <script type="text/javascript" src="static/noVNC/core/inflator.js" defer></script>
+    <script type="text/javascript" src="static/noVNC/core/rfb.js" defer></script>
+    <script type="text/javascript" src="static/noVNC/core/input/keysym.js" defer></script>
 
 </head>
 
 <body>
+    <div class="div-fake-hidden"><i class="fa fa-square-o fa-3x"></i></div>
     <div ng-controller="MainCtrl">
-        
         <nav class="navbar navbar-inverse">
 
+
             <div class="container-fluid">
 
                 <!-- Brand and toggle get grouped for better mobile display -->
                 <div class="navbar-header navbar-left">
+                    <a class="navbar-brand" href="#"><img style="max-width:100%; max-height:100%;" src="static/img/logo.png" /></a>
                     <button type="button" class="navbar-toggle" ng-init="navCollapsed = true" ng-click="navCollapsed = !navCollapsed" />
                     <span class="sr-only">Toggle navigation</span>
                     <span class="icon-bar"></span>
                     <span class="icon-bar"></span>
                     <span class="icon-bar"></span>
-                    </button>
-                    <a class="navbar-brand" href="#"><img style="max-width:100%; max-height:100%; height:50; width:73" src="static/img/logo.png" /></a>
                 </div>
 
                 <!-- Collect the nav links, forms, and other content for toggling -->
                 <div class="collapse navbar-collapse" uib-collapse="navCollapsed">
 
                     <ul class="nav navbar-nav navbar-left">
+
                         <li class="dropdown" uib-dropdown dropdown-append-to-body>
                             <a href="#" class="dropdown-toggle" uib-dropdown-toggle role="button" aria-haspopup="true" aria-expanded="false">System <span class="caret"></span></a>
                             <ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="systemlink">
@@ -104,7 +105,7 @@
                                 <li><a href="#">Firmware Update</a></li>
                             </ul>
                         </li>
-                        <li class="dropdown"uib-dropdown dropdown-append-to-body>
+                        <li class="dropdown" uib-dropdown dropdown-append-to-body>
                             <a href="#" class="dropdown-toggle" uib-dropdown-toggle role="button" aria-haspopup="true" aria-expanded="false">Remote Control <span class="caret"></span></a>
                             <ul class="dropdown-menu" uib-dropdown-menu role="menu">
                                 <li><a ui-sref="kvm">KVM Redirection</a></li>
diff --git a/static/js/bmcApp.js b/static/js/bmcApp.js
index 7d31cc2..2678ac0 100644
--- a/static/js/bmcApp.js
+++ b/static/js/bmcApp.js
@@ -10,6 +10,8 @@
   'ngResource'
 ]);
 
+
+
 app.controller('MainCtrl', ['$scope', function($scope) {
 
 }]);
@@ -72,9 +74,14 @@
 
 app.run(['$rootScope', '$cookieStore', '$state', '$resource', 'AuthenticationService', '$http', '$templateCache',
   function($rootScope, $cookieStore, $state, $resource, AuthenticationService, $http, $templateCache) {
+
+    $http.get('static/partial-login.html', {cache:$templateCache});
+    $http.get('static/partial-kvm.html', {cache: $templateCache});
+
     if ($rootScope.globals == undefined){
         $rootScope.globals = {};
     }
+
     
     // keep user logged in after page refresh
     AuthenticationService.RestoreCredientials();
@@ -90,8 +97,7 @@
             $state.go('login');
           }
         });
-  
-    $http.get('static/partial-kvm.html', { cache: $templateCache });
+
   }
 ]);
 
diff --git a/static/partial-login.html b/static/partial-login.html
index 247ad1e..bee698e 100644
--- a/static/partial-login.html
+++ b/static/partial-login.html
@@ -14,6 +14,5 @@
     </div>
     <div class="form-actions">
         <button type="submit" ng-disabled="form.$invalid || dataLoading" class="btn btn-danger">Login</button>
-        <img ng-if="dataLoading" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA=="/>
     </div>
 </form>
\ No newline at end of file