exports.applyChanges = (callback) => {
    var errors = new ErrorCatcher();
    var racer = new Racer();

    racer.add((done) => {
      // Rename the rules.conf.new file
      fs.rename(paths.rulesNewFilePath(), paths.rulesFilePath(), (err) => {
        if (err && err.code != 'ENOENT') {
          console.error(err);
          errors.addError({ message: 'Could not rename rules file' });
        }

        done();
      });
    }).add((done) => {
      // Rename the config files of the modules
      fs.readdir(conf.configPath, (err, files) => {
        if (err) {
          errors.addError('Could not open module config directory');
        } else {
          files.forEach((dir) => {
            if (dir.startsWith('module_')) {
              var moduleDir = paths.moduleConfDir(dir);

              racer.add((done) => {
                fs.stat(moduleDir, (err, stats) => {
                  if (err) {
                    console.error(err);
                  } else {
                    if (stats.isDirectory()) {
                      racer.add((done) => {
                        // File which must be renamed exists: Mark open writer and rename file
                        fs.rename(paths.confNewFilePath(dir), paths.confFilePath(dir), (err) => {
                          if (err && err.code != 'ENOENT') {
                            errors.addError(dir + '.conf.new cannot be renamed');
                          }

                          done();
                        });
                      });
                    }
                  }

                  done();
                });
              });
            }
          });
        }

        done();
      });
    }).run(() => {
      callback(errors);
    });
  };
              fs.stat(moduleDir, (err, stats) => {
                if (err) {
                  console.error(err);
                } else {
                  if (stats.isDirectory()) {
                    racer.add((done) => {
                      // Try reading module info file
                      var infoFile = paths.infoFilePath(dir);

                      fs.readFile(infoFile, (err, data) => {
                        if (err) {
                          errors.addError({ message: dir + '.info cannot be opened' });
                        } else {
                          // Add module to module list
                          var module = { id: dir, info: {} };
                          try {
                            module.info = JSON.parse(data);
                          } catch(e) {
                            if (e instanceof SyntaxError) {
                              errors.addError({ message: dir + '.info cannot be parsed due to syntax errors' });
                            }
                          }

                          modules.push(module);
                        }

                        done();
                      });
                    });
                  }
                }

                done();
              });
          files.forEach((dir) => {
            if (dir.startsWith('module_')) {
              var moduleDir = paths.moduleConfDir(dir);

              racer.add((done) => {
                fs.stat(moduleDir, (err, stats) => {
                  if (err) {
                    console.error(err);
                  } else {
                    if (stats.isDirectory()) {
                      racer.add((done) => {
                        // File which must be renamed exists: Mark open writer and rename file
                        fs.rename(paths.confNewFilePath(dir), paths.confFilePath(dir), (err) => {
                          if (err && err.code != 'ENOENT') {
                            errors.addError(dir + '.conf.new cannot be renamed');
                          }

                          done();
                        });
                      });
                    }
                  }

                  done();
                });
              });
            }
          });
  exports.readModules = (callback) => {
    var modules = [];
    var errors = new ErrorCatcher();

    var racer = new Racer();

    fs.readdir(conf.staticPath, (err, files) => {
      if (err) {
        errors.addError({ message: 'Could not open module directory' });
        callback(errors);
      } else {
        files.forEach((dir) => {
          if (dir.startsWith('module_')) {
            var moduleDir = paths.moduleShareDir(dir);

            racer.add((done) => {
              fs.stat(moduleDir, (err, stats) => {
                if (err) {
                  console.error(err);
                } else {
                  if (stats.isDirectory()) {
                    racer.add((done) => {
                      // Try reading module info file
                      var infoFile = paths.infoFilePath(dir);

                      fs.readFile(infoFile, (err, data) => {
                        if (err) {
                          errors.addError({ message: dir + '.info cannot be opened' });
                        } else {
                          // Add module to module list
                          var module = { id: dir, info: {} };
                          try {
                            module.info = JSON.parse(data);
                          } catch(e) {
                            if (e instanceof SyntaxError) {
                              errors.addError({ message: dir + '.info cannot be parsed due to syntax errors' });
                            }
                          }

                          modules.push(module);
                        }

                        done();
                      });
                    });
                  }
                }

                done();
              });
            })
            .run(() => {
              callback(errors, modules);
            });
          }
        });
      }
    });
  };
 fs.stat(moduleDir, (err, stats) => {
   if (err) {
     console.error(err);
   } else {
     if (stats.isDirectory()) {
       // module exists so add check for .new file to the racer
       racer.add(checkFile(paths.confNewFilePath(dir)));
     }
   }
   done();
 });
  exports.sendAndroidNotifierData = (res) => {
    var response = {};
    var errors = new ErrorCatcher();

    var racer = new Racer();

    racer.add((done) => {
      // Read hook file to get device token
      fs.readFile(paths.hookDataFilePath('module_firebase'), (err, data) => {
        if (err) {
          // If a error occurs add a error to the response
          errors.addError('Could not load device token');
        } else {
          // Else, set the device token and read the config file
          try {
            response.token = JSON.parse(data).token;
          } catch (e) {
            errors.add(e);
          }
        }

        done();
      });
    }).add((done) => {
      exports.getModuleConfiguration('module_firebase', (conf) => {
        if (conf) {
          response.server = conf.server;
          response.port = conf.port;
        }

        done();
      });
    }).run(() => {
      response.err = errors.errors;
      res.json(response);
    });
  };
        files.forEach((dir) => {
          var moduleDir = paths.moduleConfDir(dir);

          if (dir.startsWith('module_')) {
            racer.add((done) => {
              fs.stat(moduleDir, (err, stats) => {
                if (err) {
                  console.error(err);
                } else {
                  if (stats.isDirectory()) {
                    // module exists so add check for .new file to the racer
                    racer.add(checkFile(paths.confNewFilePath(dir)));
                  }
                }
                done();
              });
            });
          }
        });
    fs.readdir(conf.configPath, (err, files) => {
      if (err) {
        // errors occurred so add them to the errors
        errors.addError({ message: 'Could not open module config directory' });
      } else {
        // if no errors occurred add for each module a check if the new file exists
        // to the racer
        files.forEach((dir) => {
          var moduleDir = paths.moduleConfDir(dir);

          if (dir.startsWith('module_')) {
            racer.add((done) => {
              fs.stat(moduleDir, (err, stats) => {
                if (err) {
                  console.error(err);
                } else {
                  if (stats.isDirectory()) {
                    // module exists so add check for .new file to the racer
                    racer.add(checkFile(paths.confNewFilePath(dir)));
                  }
                }
                done();
              });
            });
          }
        });
      }
      // Now start the racer
      racer.run(
        // callback if all files are checked and none existed
        () => {
          callback(errors, false);
        },
        // callback if a new file was found
        () => {
          callback(errors, true);
        }
      );

    });  // read config path callback
  exports.hasUncommitedChanges = (callback) => {
    var errors = new ErrorCatcher();
    var racer = new Racer();


    /**
     * Creates a function that checks if the file exists and if so,
     * the function calls the callback.
     * @return function that checks the file
     */
    var checkFile = (path) => {
      // return a function
      return (done, abort) => {
        // check if the file exists
        exports.exists(path, (err, exists) => {
          if (exists) {
            // yes the file exists, so abort the search for .new files
            abort()
          } else if (err.hasErrors()) {
            // there are some errors, add them
            errors.addError({ message: 'Could not determine if file: ' + path + ' exists' });
            done();
          } else {
            done();
          }
        });
      };
    };

    // add lock file check to loc racer
    racer.add(checkFile(paths.lockFilePath()));

    // add rules.new file check to lock racer
    racer.add(checkFile(paths.rulesNewFilePath()));

    // add modules .new file checks to racer
    fs.readdir(conf.configPath, (err, files) => {
      if (err) {
        // errors occurred so add them to the errors
        errors.addError({ message: 'Could not open module config directory' });
      } else {
        // if no errors occurred add for each module a check if the new file exists
        // to the racer
        files.forEach((dir) => {
          var moduleDir = paths.moduleConfDir(dir);

          if (dir.startsWith('module_')) {
            racer.add((done) => {
              fs.stat(moduleDir, (err, stats) => {
                if (err) {
                  console.error(err);
                } else {
                  if (stats.isDirectory()) {
                    // module exists so add check for .new file to the racer
                    racer.add(checkFile(paths.confNewFilePath(dir)));
                  }
                }
                done();
              });
            });
          }
        });
      }
      // Now start the racer
      racer.run(
        // callback if all files are checked and none existed
        () => {
          callback(errors, false);
        },
        // callback if a new file was found
        () => {
          callback(errors, true);
        }
      );

    });  // read config path callback

  };