var ZBase = (function() {
  var modules_status = {};
  var modules_waitlist = [];
  var config;

  var findRoute = function(path) {
    for (var i = 0; i < config.routes.length; i++) {
      if (path.indexOf(config.routes[i].path_prefix) == 0) {
        return config.routes[i];
      }
    }

    return null;
  };

  var redirectToDefaultRoute = function() {
    alert("Not Found, redirect to default");
  };

  var showFatalError = function() {
    alert("Fatal Error, please reload the page");
  };

  var onNavigationChange = function(path) {
    var route = findRoute(path);
    if (route == null) {
      redirectToDefaultRoute();
      return;
    }

    loadModules(route.modules, function() {
      console.log("loaded modules for view");
    });
  };

  var init = function(_config) {
    config = _config;
    onNavigationChange(window.location.pathname + window.location.search);
  };

  var finishModuleDownload = function(module) {
    modules_status[module] = "loaded";
    // fire all finished callbacks
    for (var j = modules_waitlist.length - 1; j >= 0; j--) {
      var entry = modules_waitlist[j];
      for (var i = 0; i < entry.modules.length; i++) {
        if (modules_status[entry.modules[i]] != "loaded") {
          return;
        }
      }

      modules_waitlist.splice(j, 1);
      entry.on_loaded();
    }
  };

  var startModulesDownload = function(unloaded_modules) {
    unloaded_modules.forEach(function(module) {
      if (modules_status[module] != "loading") {
        modules_status[module] = "loading";
        console.log("Loading Module: ", module);

        window.setTimeout(function() {
          finishModuleDownload(module);
        }, 0);
      }
    });
  };

  var loadModules = function(modules, on_loaded) {
    var unloaded_modules = [];

    // search for missing modules
    modules.forEach(function(module) {
      if (modules_status[module] != "loaded") {
        unloaded_modules.push(module);
      }
    });

    // early exit if all modules are already loded
    if (unloaded_modules.length == 0) {
      on_loaded();
      return;
    }

    // add ourselves to the waitlist
    modules_waitlist.push({
      modules: modules,
      on_loaded: on_loaded
    });

    // start loading missing modules
    startModulesDownload(unloaded_modules);
  };


  return {
    init: init,
    loadModules: loadModules
  };
})();


@@ -1378,25 +1378,16 @@
 unction(
-unloaded_
 modules)
@@ -1389,33 +1389,24 @@
 ules) %7B%0A    
-unloaded_
 modules.forE
@@ -1438,147 +1438,92 @@
     
-if (modules_status%5Bmodule%5D != %22loading%22) %7B%0A        modules_status%5Bmodule%5D = %22loading%22;%0A        console.log(%22Loading Module: %22, module);%0A%0A  
+console.log(%22Loading Module: %22, module);%0A      modules_status%5Bmodule%5D = %22loading%22;%0A%0A
     
@@ -1563,18 +1563,16 @@
         
-  
 finishMo
@@ -1603,25 +1603,15 @@
     
-  
 %7D, 0);%0A
-      %7D%0A
     
@@ -1679,69 +1679,91 @@
     
-var unloaded_modules = %5B%5D;%0A%0A    // search for missing 
+// search for modules that have not finished loading%0A    var unloaded_
 modules
+ = %5B%5D;
 %0A   
@@ -2170,13 +2170,264 @@
 // s
-tart 
+earch for modules that haven't started downloading yet%0A    var download_modules = %5B%5D;%0A    unloaded_modules.forEach(function(module) %7B%0A      if (modules_status%5Bmodule%5D != %22loading%22) %7B%0A        download_modules.push(module);%0A      %7D%0A    %7D);%0A%0A    // start down
 load
@@ -2471,24 +2471,24 @@
 ownload(
-u
+dow
 nload
-ed
 _modules

call startDownloadModules only with modules that haven't been started downloading yet