code: func addModule(name, importPath, modulePath string) {
  	if _, found := ModuleByName(name); found {
  		moduleLog.Panic("Attempt to import duplicate module %s path %s aborting startup", "name", name, "path", modulePath)
  	}
  	Modules = append(Modules, &Module{Name: name,
  		ImportPath: filepath.ToSlash(importPath),
  		Path:       filepath.ToSlash(modulePath),
  		Log:        RootLog.New("module", name)})
  	if codePath := filepath.Join(modulePath, "app"); DirExists(codePath) {
  		CodePaths = append(CodePaths, codePath)
  		if viewsPath := filepath.Join(modulePath, "app", "views"); DirExists(viewsPath) {
  			TemplatePaths = append(TemplatePaths, viewsPath)
  		}
  	}
  
  	moduleLog.Debug("Loaded module ", "module", filepath.Base(modulePath))
  
  	// Hack: There is presently no way for the testrunner module to add the
  	// "test" subdirectory to the CodePaths.  So this does it instead.
  	if importPath == Config.StringDefault("module.testrunner", "github.com/revel/modules/testrunner") {
  		joinedPath := filepath.Join(BasePath, "tests")
  		moduleLog.Debug("Found testrunner module, adding `tests` path ", "path", joinedPath)
  		CodePaths = append(CodePaths, joinedPath)
  	}
  	if testsPath := filepath.Join(modulePath, "tests"); DirExists(testsPath) {
  		moduleLog.Debug("Found tests path ", "path", testsPath)
  		CodePaths = append(CodePaths, testsPath)
  	}
  }
docs: // called by `loadModules`, creates a new `Module` instance and appends it to the `Modules` list