master 7c2e2139becc cached
19 files
157.8 KB
35.2k tokens
1 requests
Download .txt
Repository: andreas-trad/express-happiness
Branch: master
Commit: 7c2e2139becc
Files: 19
Total size: 157.8 KB

Directory structure:
gitextract_icssqfkl/

├── .idea/
│   ├── .name
│   ├── encodings.xml
│   ├── expresshapinnes-official.iml
│   ├── misc.xml
│   ├── modules.xml
│   ├── scopes/
│   │   └── scope_settings.xml
│   ├── vcs.xml
│   └── workspace.xml
├── ErrorHandler.js
├── README.md
├── RESTcallsValidator.js
├── conf/
│   ├── conf.js
│   ├── errors.js
│   └── restConf.js
├── expressHappiness.js
├── fieldsLoader.js
├── helpers/
│   └── helpers.js
├── package.json
└── views/
    └── index.html

================================================
FILE CONTENTS
================================================

================================================
FILE: .idea/.name
================================================
expresshapinnes-official

================================================
FILE: .idea/encodings.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
</project>

================================================
FILE: .idea/expresshapinnes-official.iml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
  <component name="NewModuleRootManager">
    <content url="file://$MODULE_DIR$" />
    <orderEntry type="inheritedJdk" />
    <orderEntry type="sourceFolder" forTests="false" />
  </component>
</module>

================================================
FILE: .idea/misc.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ProjectRootManager" version="2" />
</project>

================================================
FILE: .idea/modules.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ProjectModuleManager">
    <modules>
      <module fileurl="file://$PROJECT_DIR$/.idea/expresshapinnes-official.iml" filepath="$PROJECT_DIR$/.idea/expresshapinnes-official.iml" />
    </modules>
  </component>
</project>

================================================
FILE: .idea/scopes/scope_settings.xml
================================================
<component name="DependencyValidationManager">
  <state>
    <option name="SKIP_IMPORT_STATEMENTS" value="false" />
  </state>
</component>

================================================
FILE: .idea/vcs.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="VcsDirectoryMappings">
    <mapping directory="" vcs="" />
  </component>
</project>

================================================
FILE: .idea/workspace.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ChangeListManager">
    <list default="true" id="d9269681-97c6-4fc2-9aef-be25035f51df" name="Default" comment="" />
    <ignored path="expresshapinnes-official.iws" />
    <ignored path=".idea/workspace.xml" />
    <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
    <option name="TRACKING_ENABLED" value="true" />
    <option name="SHOW_DIALOG" value="false" />
    <option name="HIGHLIGHT_CONFLICTS" value="true" />
    <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
    <option name="LAST_RESOLUTION" value="IGNORE" />
  </component>
  <component name="ChangesViewManager" flattened_view="true" show_ignored="false" />
  <component name="CreatePatchCommitExecutor">
    <option name="PATCH_PATH" value="" />
  </component>
  <component name="DaemonCodeAnalyzer">
    <disable_hints />
  </component>
  <component name="ExecutionTargetManager" SELECTED_TARGET="default_target" />
  <component name="FavoritesManager">
    <favorites_list name="expresshapinnes-official" />
  </component>
  <component name="FileEditorManager">
    <leaf>
      <file leaf-file-name="server.js" pinned="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/test/server.js">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="795">
              <caret line="37" column="15" selection-start-line="37" selection-start-column="15" selection-end-line="37" selection-end-column="15" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="reusableFields.js" pinned="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/test/reusableFields.js">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="0.0" vertical-offset="540" max-vertical-offset="3585">
              <caret line="33" column="30" selection-start-line="33" selection-start-column="16" selection-end-line="33" selection-end-column="30" />
              <folding>
                <element signature="n#!!doc" expanded="true" />
              </folding>
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="RESTcallsValidator.js" pinned="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/test/node_modules/express-happiness/RESTcallsValidator.js">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="0.0" vertical-offset="2823" max-vertical-offset="4020">
              <caret line="47" column="0" selection-start-line="47" selection-start-column="0" selection-end-line="47" selection-end-column="0" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="layer.js" pinned="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/test/node_modules/express/lib/router/layer.js">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="0.0" vertical-offset="846" max-vertical-offset="2580">
              <caret line="83" column="0" selection-start-line="83" selection-start-column="0" selection-end-line="83" selection-end-column="0" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="route.js" pinned="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/test/node_modules/express/lib/router/route.js">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="0.0" vertical-offset="996" max-vertical-offset="2835">
              <caret line="93" column="0" selection-start-line="93" selection-start-column="0" selection-end-line="93" selection-end-column="0" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="expressHappiness.js" pinned="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/test/node_modules/express-happiness/expressHappiness.js">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="0.0" vertical-offset="6813" max-vertical-offset="8010">
              <caret line="449" column="15" selection-start-line="449" selection-start-column="8" selection-end-line="449" selection-end-column="15" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="ErrorHandler.js" pinned="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/test/node_modules/express-happiness/ErrorHandler.js">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="675">
              <caret line="20" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="39" selection-end-column="30" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="helpers.js" pinned="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/helpers/helpers.js">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="1035">
              <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="ErrorHandler.js" pinned="false" current-in-tab="true">
        <entry file="file://$PROJECT_DIR$/ErrorHandler.js">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="0.48872182" vertical-offset="0" max-vertical-offset="1197">
              <caret line="39" column="30" selection-start-line="39" selection-start-column="30" selection-end-line="39" selection-end-column="30" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
    </leaf>
  </component>
  <component name="IdeDocumentHistory">
    <option name="CHANGED_PATHS">
      <list>
        <option value="$PROJECT_DIR$/test/package.json" />
        <option value="$PROJECT_DIR$/controllerFunctions.js" />
        <option value="$PROJECT_DIR$/package.json" />
        <option value="$PROJECT_DIR$/views/index.html" />
        <option value="$PROJECT_DIR$/test/mockdata/getTraffic.json" />
        <option value="$PROJECT_DIR$/test/conf/conf.js" />
        <option value="$PROJECT_DIR$/test/controllerFunctions.js" />
        <option value="$PROJECT_DIR$/expressHappiness.js" />
        <option value="$PROJECT_DIR$/test/conf/errors.js" />
        <option value="$PROJECT_DIR$/test/server.js" />
        <option value="$PROJECT_DIR$/test/conf/restConf.js" />
        <option value="$PROJECT_DIR$/test/reusableFields.js" />
        <option value="$PROJECT_DIR$/test/errors.log" />
        <option value="$PROJECT_DIR$/test/node_modules/express-happiness/RESTcallsValidator.js" />
        <option value="$PROJECT_DIR$/RESTcallsValidator.js" />
        <option value="$PROJECT_DIR$/test/node_modules/express-happiness/ErrorHandler.js" />
        <option value="$PROJECT_DIR$/ErrorHandler.js" />
      </list>
    </option>
  </component>
  <component name="JsGulpfileManager">
    <detection-done>true</detection-done>
  </component>
  <component name="ProjectFrameBounds">
    <option name="x" value="1920" />
    <option name="y" value="-295" />
    <option name="width" value="1200" />
    <option name="height" value="1920" />
  </component>
  <component name="ProjectLevelVcsManager" settingsEditedManually="false">
    <OptionsSetting value="true" id="Add" />
    <OptionsSetting value="true" id="Remove" />
    <OptionsSetting value="true" id="Checkout" />
    <OptionsSetting value="true" id="Update" />
    <OptionsSetting value="true" id="Status" />
    <OptionsSetting value="true" id="Edit" />
    <ConfirmationsSetting value="0" id="Add" />
    <ConfirmationsSetting value="0" id="Remove" />
  </component>
  <component name="ProjectView">
    <navigator currentView="ProjectPane" proportions="" version="1">
      <flattenPackages />
      <showMembers />
      <showModules />
      <showLibraryContents />
      <hideEmptyPackages />
      <abbreviatePackageNames />
      <autoscrollToSource />
      <autoscrollFromSource />
      <sortByType />
    </navigator>
    <panes>
      <pane id="ProjectPane">
        <subPane>
          <PATH>
            <PATH_ELEMENT>
              <option name="myItemId" value="expresshapinnes-official" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
            </PATH_ELEMENT>
          </PATH>
          <PATH>
            <PATH_ELEMENT>
              <option name="myItemId" value="expresshapinnes-official" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="expresshapinnes-official" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
          </PATH>
          <PATH>
            <PATH_ELEMENT>
              <option name="myItemId" value="expresshapinnes-official" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="expresshapinnes-official" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="views" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
          </PATH>
          <PATH>
            <PATH_ELEMENT>
              <option name="myItemId" value="expresshapinnes-official" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="expresshapinnes-official" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="test" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
          </PATH>
          <PATH>
            <PATH_ELEMENT>
              <option name="myItemId" value="expresshapinnes-official" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="expresshapinnes-official" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="test" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="node_modules" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
          </PATH>
          <PATH>
            <PATH_ELEMENT>
              <option name="myItemId" value="expresshapinnes-official" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="expresshapinnes-official" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="test" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="node_modules" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="express-happiness" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
          </PATH>
          <PATH>
            <PATH_ELEMENT>
              <option name="myItemId" value="expresshapinnes-official" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="expresshapinnes-official" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="test" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="mockdata" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
          </PATH>
          <PATH>
            <PATH_ELEMENT>
              <option name="myItemId" value="expresshapinnes-official" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="expresshapinnes-official" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="test" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="conf" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
          </PATH>
          <PATH>
            <PATH_ELEMENT>
              <option name="myItemId" value="expresshapinnes-official" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="expresshapinnes-official" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="helpers" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
          </PATH>
        </subPane>
      </pane>
      <pane id="Scope" />
    </panes>
  </component>
  <component name="PropertiesComponent">
    <property name="WebServerToolWindowFactoryState" value="false" />
    <property name="last_opened_file_path" value="$PROJECT_DIR$" />
    <property name="HbShouldOpenHtmlAsHb" value="" />
    <property name="FullScreen" value="false" />
    <property name="recentsLimit" value="5" />
    <property name="restartRequiresConfirmation" value="true" />
  </component>
  <component name="RecentsManager">
    <key name="CopyFile.RECENT_KEYS">
      <recent name="$PROJECT_DIR$/test" />
      <recent name="$PROJECT_DIR$/test/conf" />
      <recent name="$PROJECT_DIR$/views" />
      <recent name="$PROJECT_DIR$" />
    </key>
    <key name="MoveFile.RECENT_KEYS">
      <recent name="$PROJECT_DIR$/test" />
    </key>
  </component>
  <component name="RunManager" selected="Node.js.server.js">
    <configuration default="false" name="server.js" type="NodeJSConfigurationType" factoryName="Node.js" temporary="true" path-to-node="/usr/local/bin/node" path-to-js-file="server.js" working-dir="$PROJECT_DIR$/test">
      <RunnerSettings RunnerId="Basic" />
      <RunnerSettings RunnerId="debuggableProgram" />
      <ConfigurationWrapper RunnerId="Basic" />
      <ConfigurationWrapper RunnerId="debuggableProgram" />
      <method />
    </configuration>
    <configuration default="false" name="RESTcallsValidator.js" type="NodeJSConfigurationType" factoryName="Node.js" temporary="true" path-to-node="/usr/local/bin/node" path-to-js-file="RESTcallsValidator.js" working-dir="$PROJECT_DIR$/test/node_modules/express-happiness">
      <RunnerSettings RunnerId="debuggableProgram" />
      <ConfigurationWrapper RunnerId="debuggableProgram" />
      <method />
    </configuration>
    <configuration default="false" name="route.js" type="NodeJSConfigurationType" factoryName="Node.js" temporary="true" path-to-node="/usr/local/bin/node" path-to-js-file="route.js" working-dir="$PROJECT_DIR$/test/node_modules/express/lib/router">
      <RunnerSettings RunnerId="debuggableProgram" />
      <ConfigurationWrapper RunnerId="debuggableProgram" />
      <method />
    </configuration>
    <configuration default="true" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application">
      <method />
    </configuration>
    <configuration default="true" type="DartUnitRunConfigurationType" factoryName="DartUnit">
      <method />
    </configuration>
    <configuration default="true" type="JavaScriptTestRunnerKarma" factoryName="Karma" config-file="">
      <envs />
      <method />
    </configuration>
    <configuration default="true" type="JSTestDriver:ConfigurationType" factoryName="JsTestDriver">
      <setting name="configLocationType" value="CONFIG_FILE" />
      <setting name="settingsFile" value="" />
      <setting name="serverType" value="INTERNAL" />
      <setting name="preferredDebugBrowser" value="Chrome" />
      <method />
    </configuration>
    <configuration default="true" type="JavascriptDebugType" factoryName="JavaScript Debug">
      <method />
    </configuration>
    <configuration default="true" type="NodeJSConfigurationType" factoryName="Node.js" working-dir="">
      <method />
    </configuration>
    <configuration default="true" type="cucumber.js" factoryName="Cucumber.js">
      <option name="cucumberJsArguments" value="" />
      <option name="executablePath" />
      <option name="filePath" />
      <method />
    </configuration>
    <configuration default="true" type="js.build_tools.gulp" factoryName="Gulp.js">
      <node-options />
      <gulpfile />
      <tasks />
      <pass-parent-envs>true</pass-parent-envs>
      <envs />
      <method />
    </configuration>
    <list size="3">
      <item index="0" class="java.lang.String" itemvalue="Node.js.server.js" />
      <item index="1" class="java.lang.String" itemvalue="Node.js.RESTcallsValidator.js" />
      <item index="2" class="java.lang.String" itemvalue="Node.js.route.js" />
    </list>
    <recent_temporary>
      <list size="3">
        <item index="0" class="java.lang.String" itemvalue="Node.js.server.js" />
        <item index="1" class="java.lang.String" itemvalue="Node.js.RESTcallsValidator.js" />
        <item index="2" class="java.lang.String" itemvalue="Node.js.route.js" />
      </list>
    </recent_temporary>
  </component>
  <component name="ShelveChangesManager" show_recycled="false" />
  <component name="SvnConfiguration">
    <configuration />
  </component>
  <component name="TaskManager">
    <task active="true" id="Default" summary="Default task">
      <changelist id="d9269681-97c6-4fc2-9aef-be25035f51df" name="Default" comment="" />
      <created>1426774221260</created>
      <option name="number" value="Default" />
      <updated>1426774221260</updated>
    </task>
    <servers />
  </component>
  <component name="ToolWindowManager">
    <frame x="1920" y="-295" width="1200" height="1920" extended-state="6" />
    <editor active="true" />
    <layout>
      <window_info id="Changes" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
      <window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="FLOATING" visible="true" weight="0.3298687" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" x="490" y="61" width="1179" height="840" />
      <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
      <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="0" side_tool="true" content_ui="tabs" />
      <window_info id="Application Servers" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
      <window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.21289228" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
      <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.3298687" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
      <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.3298687" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
      <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="0" side_tool="true" content_ui="tabs" />
      <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="0" side_tool="true" content_ui="tabs" />
      <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
    </layout>
    <layout-to-restore>
      <window_info id="Changes" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
      <window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
      <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
      <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="0" side_tool="true" content_ui="tabs" />
      <window_info id="Application Servers" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
      <window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.20747761" sideWeight="0.5" order="1" side_tool="false" content_ui="combo" />
      <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
      <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
      <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
      <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="5" side_tool="true" content_ui="tabs" />
      <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
    </layout-to-restore>
  </component>
  <component name="Vcs.Log.UiProperties">
    <option name="RECENTLY_FILTERED_USER_GROUPS">
      <collection />
    </option>
    <option name="RECENTLY_FILTERED_BRANCH_GROUPS">
      <collection />
    </option>
  </component>
  <component name="VcsContentAnnotationSettings">
    <option name="myLimit" value="2678400000" />
  </component>
  <component name="VcsManagerConfiguration">
    <option name="myTodoPanelSettings">
      <TodoPanelSettings />
    </option>
  </component>
  <component name="XDebuggerManager">
    <breakpoint-manager>
      <breakpoints>
        <line-breakpoint enabled="true" type="javascript">
          <url>file://$PROJECT_DIR$/test/node_modules/express-happiness/RESTcallsValidator.js</url>
          <line>47</line>
          <option name="timeStamp" value="19" />
        </line-breakpoint>
      </breakpoints>
      <option name="time" value="24" />
    </breakpoint-manager>
    <watches-manager />
  </component>
  <component name="editorHistoryManager">
    <entry file="file://$PROJECT_DIR$/test/package.json">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="150" max-vertical-offset="270">
          <caret line="10" column="2" selection-start-line="10" selection-start-column="2" selection-end-line="10" selection-end-column="2" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/server.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="555" max-vertical-offset="795">
          <caret line="37" column="13" selection-start-line="37" selection-start-column="13" selection-end-line="37" selection-end-column="13" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/views/index.html">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="105" max-vertical-offset="1185">
          <caret line="14" column="0" selection-start-line="14" selection-start-column="0" selection-end-line="14" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/conf/conf.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="45" max-vertical-offset="195">
          <caret line="3" column="0" selection-start-line="3" selection-start-column="0" selection-end-line="3" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/conf/restConf.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="300" max-vertical-offset="7020">
          <caret line="53" column="44" selection-start-line="53" selection-start-column="32" selection-end-line="53" selection-end-column="44" />
          <folding>
            <element signature="n#!!doc" expanded="true" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/expressHappiness.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="5845" max-vertical-offset="7110">
          <caret line="402" column="20" selection-start-line="402" selection-start-column="20" selection-end-line="402" selection-end-column="20" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/errors.log">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="195" max-vertical-offset="285">
          <caret line="13" column="0" selection-start-line="13" selection-start-column="0" selection-end-line="13" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/conf/errors.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="405">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/fieldsLoader.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="600" max-vertical-offset="825">
          <caret line="40" column="16" selection-start-line="40" selection-start-column="16" selection-end-line="44" selection-end-column="17" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/controllerFunctions.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="30" max-vertical-offset="120">
          <caret line="2" column="0" selection-start-line="2" selection-start-column="0" selection-end-line="2" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/ErrorHandler.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="225" max-vertical-offset="555">
          <caret line="15" column="16" selection-start-line="15" selection-start-column="16" selection-end-line="15" selection-end-column="16" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/RESTcallsValidator.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="75" max-vertical-offset="2790">
          <caret line="5" column="8" selection-start-line="5" selection-start-column="7" selection-end-line="5" selection-end-column="8" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/package.json">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="375" max-vertical-offset="465">
          <caret line="25" column="1" selection-start-line="25" selection-start-column="1" selection-end-line="25" selection-end-column="1" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/package.json">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="150" max-vertical-offset="270">
          <caret line="10" column="2" selection-start-line="10" selection-start-column="2" selection-end-line="10" selection-end-column="2" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/server.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="660" max-vertical-offset="795">
          <caret line="44" column="0" selection-start-line="44" selection-start-column="0" selection-end-line="44" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/conf/conf.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="45" max-vertical-offset="195">
          <caret line="3" column="0" selection-start-line="3" selection-start-column="0" selection-end-line="3" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/expressHappiness.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="5557" max-vertical-offset="6630">
          <caret line="422" column="31" selection-start-line="422" selection-start-column="15" selection-end-line="422" selection-end-column="31" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/fieldsLoader.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="825">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/controllerFunctions.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="30" max-vertical-offset="120">
          <caret line="2" column="0" selection-start-line="2" selection-start-column="0" selection-end-line="2" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/ErrorHandler.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="450">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/RESTcallsValidator.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="75" max-vertical-offset="2790">
          <caret line="5" column="8" selection-start-line="5" selection-start-column="7" selection-end-line="5" selection-end-column="8" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/package.json">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="375" max-vertical-offset="465">
          <caret line="25" column="1" selection-start-line="25" selection-start-column="1" selection-end-line="25" selection-end-column="1" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/package.json">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="150" max-vertical-offset="270">
          <caret line="10" column="2" selection-start-line="10" selection-start-column="2" selection-end-line="10" selection-end-column="2" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/server.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="660" max-vertical-offset="795">
          <caret line="44" column="0" selection-start-line="44" selection-start-column="0" selection-end-line="44" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/conf/conf.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="45" max-vertical-offset="195">
          <caret line="3" column="0" selection-start-line="3" selection-start-column="0" selection-end-line="3" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/expressHappiness.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="5557" max-vertical-offset="6630">
          <caret line="422" column="31" selection-start-line="422" selection-start-column="15" selection-end-line="422" selection-end-column="31" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/fieldsLoader.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="825">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/controllerFunctions.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="30" max-vertical-offset="120">
          <caret line="2" column="0" selection-start-line="2" selection-start-column="0" selection-end-line="2" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/ErrorHandler.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="450">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/RESTcallsValidator.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="75" max-vertical-offset="2790">
          <caret line="5" column="8" selection-start-line="5" selection-start-column="7" selection-end-line="5" selection-end-column="8" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/package.json">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="150" max-vertical-offset="270">
          <caret line="10" column="2" selection-start-line="10" selection-start-column="2" selection-end-line="10" selection-end-column="2" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/package.json">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="180" max-vertical-offset="480">
          <caret line="12" column="24" selection-start-line="12" selection-start-column="24" selection-end-line="12" selection-end-column="24" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/views/index.html">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="105" max-vertical-offset="1185">
          <caret line="14" column="0" selection-start-line="14" selection-start-column="0" selection-end-line="14" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/mockdata/getTraffic.json">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.008445946" vertical-offset="0" max-vertical-offset="1776">
          <caret line="1" column="12" selection-start-line="1" selection-start-column="12" selection-end-line="1" selection-end-column="12" />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/conf/errors.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="405">
          <caret line="11" column="12" selection-start-line="11" selection-start-column="12" selection-end-line="11" selection-end-column="49" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/controllerFunctions.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="210">
          <caret line="4" column="22" selection-start-line="4" selection-start-column="22" selection-end-line="4" selection-end-column="22" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/conf/restConf.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.5" vertical-offset="0" max-vertical-offset="1800">
          <caret line="60" column="21" selection-start-line="60" selection-start-column="21" selection-end-line="60" selection-end-column="21" />
          <folding>
            <element signature="n#!!doc" expanded="true" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/conf/conf.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="240">
          <caret line="10" column="0" selection-start-line="10" selection-start-column="0" selection-end-line="10" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/expressHappiness.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="1815" max-vertical-offset="8010">
          <caret line="137" column="38" selection-start-line="137" selection-start-column="38" selection-end-line="137" selection-end-column="38" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/fieldsLoader.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.33333334" vertical-offset="0" max-vertical-offset="1800">
          <caret line="40" column="16" selection-start-line="40" selection-start-column="16" selection-end-line="44" selection-end-column="17" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/node_modules/express/lib/router/layer.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="846" max-vertical-offset="2580">
          <caret line="83" column="0" selection-start-line="83" selection-start-column="0" selection-end-line="83" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/node_modules/express/lib/router/route.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="996" max-vertical-offset="2835">
          <caret line="93" column="0" selection-start-line="93" selection-start-column="0" selection-end-line="93" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/RESTcallsValidator.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.9749373" vertical-offset="2763" max-vertical-offset="4020">
          <caret line="262" column="1" selection-start-line="262" selection-start-column="1" selection-end-line="262" selection-end-column="1" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/helpers/helpers.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="1800">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/errors.log">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.924812" vertical-offset="498" max-vertical-offset="1695">
          <caret line="107" column="48" selection-start-line="107" selection-start-column="48" selection-end-line="107" selection-end-column="48" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/reusableFields.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="540" max-vertical-offset="3585">
          <caret line="33" column="30" selection-start-line="33" selection-start-column="16" selection-end-line="33" selection-end-column="30" />
          <folding>
            <element signature="n#!!doc" expanded="true" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/node_modules/express-happiness/RESTcallsValidator.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="306" max-vertical-offset="4020">
          <caret line="47" column="0" selection-start-line="47" selection-start-column="0" selection-end-line="47" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/node_modules/express-happiness/expressHappiness.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="6363" max-vertical-offset="8010">
          <caret line="449" column="15" selection-start-line="449" selection-start-column="8" selection-end-line="449" selection-end-column="15" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/server.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="795">
          <caret line="37" column="15" selection-start-line="37" selection-start-column="15" selection-end-line="37" selection-end-column="15" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/test/node_modules/express-happiness/ErrorHandler.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="675">
          <caret line="20" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="39" selection-end-column="30" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/ErrorHandler.js">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.48872182" vertical-offset="0" max-vertical-offset="1197">
          <caret line="39" column="30" selection-start-line="39" selection-start-column="30" selection-end-line="39" selection-end-column="30" />
          <folding />
        </state>
      </provider>
    </entry>
  </component>
</project>

================================================
FILE: ErrorHandler.js
================================================
var ErrorHandler = function(logfileUrl){
    var fs = require('fs');
    var moment = require('moment');

    this.handleError = function(erObj, err, req, res){
        var apipath = '';
        if(req.expressHappiness){
            apipath = req.expressHappiness.apipath;
        }

        var toAppend = '\n' + moment().format('YYYY-MM-DD HH:mm:ss') + " | " + err.type + " | " + apipath + ' | ' + erObj.humanReadable;
        if(err.details){
            toAppend += ' | ' + JSON.stringify(err.details);
        }

        if(erObj.log){
            fs.appendFile(logfileUrl, toAppend, function (er) {
            });
        }


        if(erObj.hooks != null && erObj.hooks != undefined){
            for(var i=0; i<erObj.hooks.length; i++){
                hooks[i](req, erObj, err);
            }
        }

        var toSend = erObj.sendToClient.data;
        if(erObj.sendToClient){
            if(erObj.sendToClient.data){
                if(erObj.sendToClient.data === 'err.details'){
                    toSend = err.details;
                }
            }
        }
        res.status(erObj.sendToClient.code || 200).send(toSend || '');
    };
}

module.exports = ErrorHandler;

================================================
FILE: README.md
================================================
Express Happiness
=================

Intro
-----
ExpressHappiness is a rich framework for creating web apps and services, built on top of 
the [Express framework](http://expressjs.com/).

We all use and love Express. When it comes to large and complex apps, some times the 
maintainability of them becomes hard as we keep on adding routes, handle errors and permissions.

ExpressHappiness provides a way to develop robust and maintainable apps or REST APIs using Express.

The main features of the framework are:

* The full routes tree is defined in a single object, in a JSON-like manner
* Error handling is defined in the exact same manner in a single file. You can either define your own error codes or define the way that they'll be handled in the errors configuration file and trigger them any time from any part of your code, letting the framework handle them the way you define.
* Define permissions to each route by specifying the access group(s) that each route belongs to and define middlewares for groups of routes, not for each route separately
* Validate the params of each call by defining their characteristics on the routes definition file
* Automatically generate your rest api documentation
* Work with mock data, by just putting a file in a specific folder and setting the `mock` parameter to true on the route's definition
* Add function hooks to any error type
* and many more...


License
-------
Released under the [WTFPL](http://sam.zoy.org/wtfpl/) license by Andreas Trantidis [@AndreasTrantidi](https://twitter.com/AndreasTrantidi)


<h2>Install</h2>
<code>
$ npm install express-happiness
</code>

<h2>The basics / Structure</h2>
Every ExpressHappiness project consists of a specific set of files that define the project's routes and behaviour.
These files are:
<ul>
<li><b>Routes Tree Configuration</b>: On this file you'll put / define all
of the supported routes of your app with all of their details. These details include the method of the route
(get / post / put / delete), the parameters of the route (parameter type, validation rules) and you can also enable / disable
the mock operation.<br/>
For each route you can define an alias name and also the group(s) that this route belongs to. The "groups" that the
routes belong to are custom groups, with custom names. The groups that a route belongs to define the middlewares that
will be applied to it. More details about grouping and group-specific middlewares will be defined later on.
</li>
<li><b>Reusable Params File</b>: There are cases where many routes have the exact same parameter, with the
 exact same type and validation rules. In order to avoid rewriting the same parameter definition again and
 again throughout all of these routes you can define these params once and just reuse them to any of the routes. The file
 that holds the "reusable params" definitions is the Reusable Params File.
 These type of parameters are called "reusable" params and are defined on the Reusable Fields File</li>
<li><b>Error Handling Configuration File</b>: At any point of the middlewares chain of any call you can
 trigger errors. Errors of custom types, decorated with custom details. Express Happiness provides an error handling
 mechanism that automatically takes care this errors. The way each custom type's error will be handled is defined on this file.
 The developer has the ability to define whether and what is going to be written to the error.log file,
 what code should be sent back to the client (200, 400, 401, etc) and what data will be served. Finally, on each of these
 error types, the developers can define a set of hook functions to be executed (email send, log to db, whatever).<br/>
 All these error handling parameters are defined on the Error Handling Configuration File.</li>
<li><b>error log</b>: Is just a plain text file holding all logs printed out by the Error Handling mechanism</li>
<li><b>Controller Functions</b>: This file defines the function that should be executed on each route.
 The main concept here is not to define / write the body of these functions within this file but to have a "mapper"
 endpoint though which anyone can easily find out what's going on, on any route.<br/>
 The association between routes and controller functions is done by an associative array,
 each key of which is a string, either the full route definition or the route alias and each value the corresponding controller function.
 As mentioned, routes' aliases can be defined on the Routes Tree Configuration File.</li>
</ul>

<h2>Starting with it</h2>
In order to start, you can just clone <a href="https://github.com/andreas-trad/express-happiness-quick-start" target="_blank">this repo</a> to your machine or either follow step
 by step this document.
<h3>Create your Reusable Params File</h3>
Each route expects for some params to be passed on call. As mentioned, Express Happiness includes an automatic params
validation mechanism and the only thing you should do is to define the params and the validation rules that apply for
each route. <br/>
Each parameter, no matter its type, has the following structure:<br/>
<p>Code Snippet 1. <b>Parameter's basic structure</b></p>
<pre lang="javascript"><code>
param: {
    "key": "the-key-name",
    "type": "one-of-the-supported-types",
    "humanReadable": "short title of the param",
    "description": "A human-readable description of the parameter",
    "mandatory": "boolean-true-or-false"
}
</code></pre>
<br/>
Not all of these characteristics are mandatory nor are they all. For each parameter type, special characteristics apply.
For example, for type "int", the definition object of the param may (optionally) include "min" and "max" keys, etc.<br/>
<br/><b>The list of the supported parameter types is:</b>
<p>Table 1. <b>Supported parameter types</b></p>
<table>
<tr>
<td>int</td>
<td>Integer</td>
</tr>
<tr>
<td>date</td>
<td>Date</td>
</tr>
<tr>
<td>oneof</td>
<td>The value must be one of the specified</td>
</tr>
<tr>
<td>boolean</td>
<td>Boolean</td>
</tr>
<tr>
<td>numeric</td>
<td>any number</td>
</tr>
<tr>
<td>string</td>
<td>String</td>
</tr>
<tr>
<td>array</td>
<td>Array</td>
</tr>
<tr>
<td>object</td>
<td>Object</td>
</tr>
</table>

<b>The full list of the supported attributes for each param are listed below:</b>
<p>Table 2. <b>Supported param attrs</b></p>
<table>
<thead>
<tr>
<th>Attribute key</th>
<th>Mandatory</th>
<th>Description</th>
<th>Applies to</th>
</tr>
</thead>
<tbody>
<tr>
<td>key</td>
<td>yes</td>
<td>the key name of the parameter. For example, if on a route you expect for a param with the name "x", then the key
of this param is "x"</td>
<td>all types</td>
</tr>
<tr>
<td>type</td>
<td>yes</td>
<td>the type of the parameter. Might be one of: "int", "date", "oneof", "boolean", "numeric", "string", "array" and "object"</td>
<td></td>
</tr>
<tr>
<td>humanReadable</td>
<td>no</td>
<td>a short title of the parameter. This is used by the parameters validator on the error texts that exports on validation failures</td>
<td>all types</td>
</tr>
<tr>
<td>description</td>
<td>no</td>
<td>the description of the parameter. It will be used on the auto-generated documentation of your API</td>
<td>all types</td>
</tr>
<tr>
<td>mandatory</td>
<td>no</td>
<td>defines whether the parameter is mandatory or not. If it's missing the parameter is not mandatory</td>
<td>all types</td>
</tr>
<tr>
<td>validationFailureTexts</td>
<td>no</td>
<td>An object containing the text messages that will sent back to the client for all (or any) cases that the validation fails. For example,
if a mandatory field is missing the text that will be sent back to the client is defined on the key "mandatory" of this object, etc. The
supported keys of this object are listed on the very next table that follows.</td>
<td>all types</td>
</tr>
<tr>
<td>min</td>
<td>no</td>
<td>the minimum value (including this) that a param can accept</td>
<td>int, numeric</td>
</tr>
<tr>
<td>max</td>
<td>no</td>
<td>the maximum value (including this) that a param can accept</td>
<td>int, numeric</td>
</tr>
<tr>
<td>minChars</td>
<td>no</td>
<td>the minimum characters that a string's type parameter's value might have</td>
<td>string</td>
</tr>
<tr>
<td>maxChars</td>
<td>no</td>
<td>the maximum characters that a string's type parameter's value might have</td>
<td>string</td>
</tr>
<tr>
<td>validationString</td>
<td>yes</td>
<td>the format that a date value should have. The formats are identical as on moment.js</td>
<td>date</td>
</tr>
<tr>
<td>minLength</td>
<td>no</td>
<td>the minimum length an array-type value should have</td>
<td>array</td>
</tr>
<tr>
<td>maxLength</td>
<td>no</td>
<td>the maximum length an array-type value should have</td>
<td>array</td>
</tr>
<tr>
<td>acceptedValues</td>
<td>yes</td>
<td>an array listing all the acceptable values for this param</td>
<td>oneof</td>
</tr>
<tr>
<td>regexp</td>
<td>no</td>
<td>a regular expression to check the provided value against</td>
<td>string</td>
</tr>
<tr>
<td>keys</td>
<td>no</td>
<td>an object that specifies the expected structure of an object type parameter</td>
<td>object</td>
</tr>
</tbody>
</table>

<b>The supported keys of the validationFailureTexts are:</b>
<p>Table 3. <b>validationFailureTexts supported attributes</b></p>
<table>
<thead>
<tr>
<th>Key</th>
<th>In case...</th>
</tr>
</thead>
<tbody>
<tr>
<td>type</td>
<td>the type of the field's value is not of the defined/expected field's type</td>
</tr>
<tr>
<td>mandatory</td>
<td>a mandatory filed is missing</td>
</tr>
<tr>
<td>min</td>
<td>the either of type int or numeric field's value is lower than the minimum accepted, according to the min attribute of the field's definition</td>
</tr>
<tr>
<td>max</td>
<td>the either of type int or numeric field's value is greater than the maximum accepted, according to the max attribute of the field's definition</td>
</tr>
<tr>
<td>minChars</td>
<td>the characters of the provided string are less than the minimum accepted, according to the minChars attribute of the field's definition</td>
</tr>
<tr>
<td>maxChars</td>
<td>the characters of the provided string are more than the maximum accepted, according to the maxChars attribute of the field's definition</td>
</tr>
<tr>
<td>validationString</td>
<td>the value provided for the field of type date is not compatible with the validationString of the field's definition</td>
</tr>
<tr>
<td>minLength</td>
<td>the length of the array passed on the specific field's value is lower than the minimum accepted, according to the minLength attribute of the field's definition</td>
</tr>
<tr>
<td>maxLength</td>
<td>the length of the array passed on the specific field's value is greater than the maximum accepted, according to the maxLength attribute of the field's definition</td>
</tr>
<tr>
<td>acceptedValues</td>
<td>the value of the, of type oneof, field is not present on the acceptedValues array on the field's definition</td>
</tr>
<tr>
<td>regexp</td>
<td>the string provided does not comply with the regular expression from the regexp property of the field's definition</td>
</tr>
</tbody>
</table>

So, as an example:
<p>Code Snippet 2. <b>Parameter's structure including validationFailureTexts object</b></p>
<pre lang="javascript"><code>
param: {
    "key": "user_age",
    "type": "int",
    "humanReadable": "Age",
    "description": "The age of the user",
    "mandatory": "true",
    "min": 18,
    "validationFailureTexts": {
        "mandatory": "Please provide your age",
        "min": "Sorry, you must be at least 18 years old"
    }
}
</code></pre>

In such case if the submitted value for the "age" is under 18 (let's say 17) then on the "errors" array of the response there will be the
text "Sorry, you must be at least 18 years old". If the key "min" was missing from the "validationFailureTexts" object (of if
the "validationFailureTexts" was missing at all on the field's definition), the error text that would be included on the errors array would be the default:
"Age must be greater or equal to 18. 17 provided."<br/>
Finally, in the case that there was the "humanReadable" key missing from the field's definition, then the error text would be:
"user_age must be greater or equal to 18. 17 provided."
<p>
Now it's time to proceed with your Reusable Params File.<br/>
The reusable params file is just a module that exports an object. This object has a number of keys. Each
key holds another object which represents the definition of a parameter. <br/>
The name of the key is the way you'll refer to the parameter from the Routes Tree Configuration File.<br/>
So, let's assume that you want to define two reusable parameters on this file, parameter "id" and parameter
"cat_id". Here's a possible / valid definition of these two params in the Reusable Params File:
<p>Code Snippet 3. <b>Example of Reusable Params File</b></p>
<pre lang="javascript"><code>
module.exports = {
    id:{
        key:'id',
        type:'int',
        humanReadable: 'organization id',
        description:'The Organization from which data is requested',
        mandatory:true
    },
    category: {
        key:'cat_id',
        type:'oneof',
        humanReadable: 'Product category',
        description:'The category of the product',
        mandatory:false,
        acceptedValues: ['shoes', 'clothes'],
        validationFailureTexts: {
            acceptedValues: 'Sorry, only shoes or clothes categories are supported'
        }
    }
}
</code></pre>
Pay attention that we have a unique name for each parameter defined here, which is the key of the
exported module. This name will be used in the Routes Tree Configuration File in order to load and
define the parameters that each route will expect for. <br/>
Though, each of these params have a "key" attribute. This is the name of the parameter as we expect it
during the actual calls that our service will receive.
</p>

<h3>Defining object type params</h3>
As mentioned, one of the supported param types is the "object". Also, one of the supported on object-type parameter's attributes
is "keys".<br/>
You can use the "keys" attribute of an object parameter in order to define (to any depth) the expected structure of the object
and not only this. You can apply / define validation rules of each of them, no matter which depth it is. Here's an example:<br/>
Let's suppose that on a specific call we expect for a parameter with the name "user_data" which will hold the user's information
in a well defined structure. Both the structure of the expected object and the validation rules that apply to it are made
obvious through the following parameter definition:
<p>Code Snippet 4. <b>Example of an object parameter</b></p>
<pre lang="javascript"><code>
user:{
    key:'user_data',
    type:'object',
    humanReadable:'User data',
    description:'Full user information',
    mandatory:true,
    keys:{
        gender:{
            type:'oneof',
            mandatory:true,
            acceptedValues: ['male', 'female'],
            validationFailureTexts: {
                mandatory: 'Please specify your gender',
                acceptedValues: 'Please pick between male and female'
            }
        },
        country:{
            type:'oneof',
            acceptedValues:['Greece', 'Sweden', 'Australia', 'Romania']
        },
        name:{
            type:'object',
            keys:{
                first:{
                    mandatory:true,
                    type:'string'
                },
                last:{
                    mandatory:true,
                    type:'string',
                    validationFailureTexts: {
                        mandatory: 'Please specify your last name'
                    }
                },
                middle: {
                    mandatory: false,
                    type: 'string'
                }
            }
        }
    }
}
</code></pre>
So, as you can see, not only we define the structure of the expected object but we can define the validation rules that might
apply to any of the keys of the object. Please mention that the "name" key is an object itself and it also contains the "keys"
parameter which holds the information regarding the expected keys of it. There's no limit on the depth of the nested objects
and parameters.<br/>
The "keys" param is an object which holds a set of keys. These keys represent / map the expected keys of the object.<br/>
The attributes of each one of these keys are identical with the attributes used in plain (not-object) parameters. All attributes
of table 2 apply just fine to all nested keys of all objects. The only difference between the definition of a plain parameter
and the definition of an object's key is that on the object key's definition there's no "key" attribute. The "key", that is
the expected name of the key on the provided object during a call, is identical to the name of the key itself. E.g. on the
specific example we expect the user_data.name.first to be present.<br/>
This has been implemented this way for two reasons:
<ul>
<li>There's no need and no way to refer to a nested key from services such as the FieldsLoader (we'll see about that later on)</li>
<li>We wanted to mimic the structure of the object in an one-to-one mapping</li>
</ul>
During the parameters validation process, which we'll analyse on following chapter, the full object is been validated according
to the definition of it. Don't worry this process is 100% asynchronous, so you can go ahead and create as deep, as long and
as complex object parameter definitions. It won't block your app during validation.

<h2>Routes Tree Configuration File</h2>
Now that we've defined the parameters that we're going to (re)use on our endpoints, it's time to define
these calls. <i>Of course you can always come back to the Reusable Params File and update it with new
ones.</i>
All of the supported routes of our application are defined in this very file. <br/>
In order to be able to reuse the parameters we defined in the Reusable Params File, we need the (built in) FieldsLoader
module. For this the structure / format of our Routes Tree Configuration File should look like this:
<p>Code Snippet 5. <b>Basic structure of the Routes Tree Configuration File</b></p>
<pre lang="javascript"><code>
module.exports.conf = function(fieldsLoader){
    return {
        routes:{
            // here go all of the supported routes of the application
        }
    }
};
</code></pre>

You might have noticed the term "Tree" in the name of the "Routes Tree Configuration File". Before further analysing the
way we can define your routes in here, it's good to mention a few things regarding its concept.<br/>
In an application there might be routes of the same url (e.g. /a/b) but of different types (e.g. GET, POST). Also, in
an application there might be routes that do something and also subroutes of it that do something else. For example,
there might be the route /a/b and also the route /a/b/c.<br/>
The way the routes are defined on the Routes Tree Definition File respect both of the above facts. On any given path you
can separately define the various supported call types and then you can continue deeper defining the supported subroutes of it.<br/>
In the specific example here's a possible / valid Routes Tree Configuration File:
<p>Code Snippet 6. <b>Routes Tree Configuration File including paths and endpoints</b></p>
<pre lang="javascript"><code>
module.exports.conf = function(fieldsLoader){
    return {
        routes:{
            a:{
                subRoutes: {
                    b: {
                        get: {
                            // here goes the GET /a/b route definition
                        },
                        post: {
                            // here goes the POST /a/b route definition
                        },
                        subRoutes: {
                            c: {
                                get: {
                                    // here goes the GET /a/b/c route definition
                                }
                            }
                        }
                    }
                }
            }
        }
    }
};
</code></pre>

In general, the tree that we are defining here consists of paths and endpoints. Everything starts on the "routes" parameter
of the returned object. "a" represents a path, the path "/a". This path has subRoutes, like "/a/b". So, we define these
subroutes on the "subRoutes" parameter of it.<br/>
"b" is a path itself as well. Following the object's structure, is obvious that it represents the path "/a/b". A path might
have (or might not have) endpoints. For example the path "/a" does not have any endpoints. Though, path "/a/b" has get and post
endpoints. <br/>
The endpoints are defined by the use of the corresponding key (one of "get", "post", "put", "delete"). The endpoints are the "leafs"
of this tree while the paths act as the branches.<br/>
A branch can have sub-branches and leafs. A leaf cannot have neither sub-branches nor sub-leafs, and that's we call then "endpoints".<br/>
Within the "subRoutes" parameter of any path we can only define paths.<br/>
On any endpoint we can define the fields that we're expecting.<br/>
Here's a table with all the supported attributes of each element:
<p>Table 4. <b>Path's supported attributes</b></p>
<table>
<thead>
<tr>
<th>Attribute name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>groups</td>
<td>an array containing all the groups the path belongs to</td>
</tr>
<tr>
<td>subRoutes</td>
<td>an object which keys will represent the next sub-section of the path</td>
</tr>
<tr>
<td>any of the supported call types (one of "get", "post", "put", "delete")</td>
<td>defines an endpoint to the specific path. E.g. by placing the "get" key on a path it's value must be an object defining
the characteristics of the specific endpoint</td>
</tr>
</tbody>
</table>

<p>Table 5. <b>Endpoints's supported attributes</b></p>
<table>
<thead>
<tr>
<th>Attribute name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>groups</td>
<td>an array containing all the groups the path belongs to</td>
</tr>
<tr>
<td>alias (optional)</td>
<td>a string representation / alias name of the specific endpoint</td>
</tr>
<tr>
<td>description (optional)</td>
<td>a human readable description of the endpoint. This will be used on the auto-generated documentation of your API</td>
</tr>
<tr>
<td>fields (optional)</td>
<td>an array containing all the fields that are expected on this endpoint. It will be used both by the validator and the
auto-generated documentation process. If your endpoint does not expect any parameters or you don't want to apply any
params validation you can just skip it</td>
</tr>
<tr>
<td>mock</td>
<td>in cases you want a specific endpoint to serve mock data just put the mock attribute and set it to true</td>
</tr>
</tbody>
</table>

<h3>Groups</h3>
Both on tables 4 and 5 you might have noticed the "groups" attribute. The "groups" attribute helps us organize / categorize
all of our endpoints into categories / groups.<br/>
The grouping mechanism follows a waterfall inheritance mechanism, just like inheritance works on html elements. Every child inherits
by default the groups of its closest parent. If its closest parent has no group definition then that means it inherits its own
closest parent's groups etc.<br/>
For any element in our tree (either endpoint or path), this inheritance goes all the way up until we have an explicit groups definition.<br/>
So if you have endpoints / routes defined on /admin/* and all belong to a specially restricted area of your application, where
admin authentication should take place, the only thing you have to do is to define on the /admin path the groups equal to ['admin']. All
of the child paths and endpoints of it will inherit this groups definition. <br/>
At any point, at any path or endpoint, you can explicitly define the groups attribute. By this way, any inherited value of the
attribute "groups" will be ignored and the explicitly defined will prevail.<br/>
By organizing the endpoints into groups on the Routs Tree Configuration File gives us the opportunity apply middlewares
specially developed for each of these groups. We'll see more details on this later on.<br/>
Finally, as you might have noticed, groups is an array. That means that for an endpoint belonging to more than one groups,
all middlewares of all groups it belongs to will be applied in the sequence the group names have been placed within the array.

<h3>Alias / Mock operation</h3>
The "alias" attribute of each endpoint gives us a way to refer to this endpoint from any other part of the Express Happiness
ecosystem. The most important usage of this "alias" has to do with the mock operation. As mentioned on table 5, along with the
"alias" attribute each endpoint (optionally, default = false) might have a "mock" attribute set to true. <br/>
We will analyse mock operation in details in a following part of this document, though keep just one thing in mind for now.
If any of the endpoints has been set to server mock data then a file containing the mock response should be present somewhere in
your hard drive. The folder that contains all mock files is defined on ExpressHappiness invocation, though the actual name
of the file, for each endpoint, should be identical with its alias.

<h3>fields</h3>
The fields is an array containing all the fields that the specific endpoint supports / expects. As explained, all of the
fields / params have a very specific definition pattern that has been analyzed on the Reusable Params File section. <br/>
The fields array might "load" fields from the reusable fields or can either include newly defined params.<br/>
In order to load a parameter from the params defined on the Reusable Params File you should use the method "getField" of the
FieldsLoader module that comes with the ExpressHappiness framework. <br/>
Here is a complete example, using the fields defined on code snippet 3:
<p>Code Snippet 7. <b>Routes Tree Configuration File example with fields loading</b></p>
<pre lang="javascript"><code>
module.exports.conf = function(fieldsLoader){ // mind the "fieldsLoader" argument
    return {
        routes:{
            a:{
                subRoutes: {
                    b: {
                        get: {
                            alias: 'a_b_get',
                            description: 'a dummy description of a dummy endpoint',
                            fields: [
                                fieldsLoader.getField('id'),
                                fieldsLoader.getField('category', {
                                    mandatory:true
                                }),
                                {
                                    key: 'size',
                                    mandatory: true,
                                    type: 'numeric'
                                }
                            ]
                        }
                    }
                }
            }
        }
    }
};
</code></pre>

As you can see, on the GET "/a/b" endpoint we have defined three fields:
<ul>
<li><b>by loading the "id" field.</b> The resulting field is identical as the definition of the field on the Reusable Params File (code snippet 3)</li>
<li><b>by loading the "category" field and passing second argument on getField.</b> The "getField" method of FieldsLoader takes a second optional
attribute. This attribute is an object. All own keys of this object that are included in the supported params attrs list (table 2) will overwrite the
ones defined on the Reusable Params File.</li>
<li><b>A totally new parameter.</b> There are cases where a parameter might appear only once and only in one endpoint. In such cases there's
absolutely no need to define it on the Reusable Params File but, instead, you can define it directly on the "fields" array of the endpoint.</li>
</ul>

<h3>Dynamic routes</h3>
A question that arises has to do with the dynamic routes (e.g. "/a/b/:c"). This is of course supported by ExpressHappiness
and you can totally use it on your Routes Tree Configuration File. You can access these fields as you would usually do through
the <a href="http://expressjs.com/api.html#req" target="_blank">req object</a> of express.</br>
Here's a simple demonstration on how to define routes including dynamic params:

<p>Code Snippet 8. <b>Dynamic Route Params</b></p>
<pre lang="javascript"><code>
module.exports.conf = function(fieldsLoader){ // mind the "fieldsLoader" argument
    return {
        routes:{
            a:{
                subRoutes: {
                    ":b": { // check the ":b" on the subRoute key
                        get: {
                            // endpoint definition
                        }
                    }
                }
            }
        }
    }
};
</code></pre>

<h2>Error Handling and Error Handling Configuration File</h2>
The way errors are handled by Express Happiness is centralized and configurable. All errors, including the unknown, are
handled by the framework itself and the developer has the ability to configure the behaviour of the app in each error type.
Express Happiness also provides the ability to define custom error types, define the behaviour of the app in each of them,
trigger such errors from anywhere in your middlewares chain and let the framework take care of them accordingly.<br/>
The way each error type should be treated by the application is defined on the Error Handling Configuration File.
<br/>The basic structure of this file is the following:
<p>Code snippet 9. <b>Error Handling Configuration File Basic Structure</b>
<pre language="javascript"><code>
exports.errors = {
    undefinedError:{
        log:true,
        humanReadable: 'Unresolved error code',
        sendToClient: {
            code:500,
            data: 'ErrCode: 1 - There was an error fulfilling your request at the moment. Please try again in a while'
        },
        hooks:[
            // here you can put whatever you want
        ]
    },
    '404':{
        log:true,
        sendToClient: {
            code:404,
            data:'Invalid route'
        }
    },
    'my_custom_error_code':{
        log:false,
        sendToClient:{
            code:500,
            data:'There was an error fulfilling your request'
        }
    }
}
</code></pre>

The Error Handling Configuration File exports an object. Each object key represents the "type" of the error. So, in our
example, if an undefined error gets triggered by the app, our application will log it, it will write to the log file the
text "Unresolved error code" and the client will receive a 500 code along with the body "ErrCode: 1 - There was an error
fulfilling your request at the moment. Please try again in a while".</br>
Let's dive deeper and see which attributes are supported for each error type defined on this file.
<p>Table 6. <b>Supported attributes on error configuration</b></p>
<table>
<thead>
<tr>
<th>Attribute name</th>
<th>Type</th>
<th>Mandatory</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>log</td>
<td>boolean</td>
<td>no (default: false)</td>
<td>If log is set to true, this error will be logged to the error.log file</td>
</tr>
<tr>
<td>humanReadable</td>
<td>string</td>
<td>no</td>
<td>a human readable description of the error. This is what it will get logged to the error.log file if log is set to true</td>
</tr>
<tr>
<td>sendToClient</td>
<td>object with two keys: code and data</td>
<td>no</td>
<td>with the use of this attribute you can define the response code and the response body that will be sent back to the client. If you
want to send to the client the details of the error object just put there (in quotes) 'err.details'</td>
</tr>
<tr>
<td>hooks</td>
<td>array</td>
<td>no</td>
<td>a list of functions to be executed whenever an error of this type occurs. The hook functions should take 3 arguments:
<ul>
<li>req (the req object)</li>
<li>errorDefinitionObject (the error definition object taken from the Error Handling Configuration File)</li>
<li>err (the actual error triggered during the call stack)</li>
</ul>
These hook functions get executed before your app responds to the client they are not part of the calls chain (they do not
act as middlewares)
</td>
</tr>
</tbody>
</table>

<h3>Triggering Errors</h3>
Once you define all of your error on the Error Handling Configuration File you can at any time, from anywhere on your code
trigger any of these by the use of this, simple, code:
<p>Code Snippet 10. <b>Triggering errors</b></p>
<pre language="javascript"><code>
var err = new Error();
err.type = 'my_custom_error';
err.details = 'The details of the error. Might be either a string, such as this, or any other data type (object, array etc)';
return next(err);
</code></pre>

In order for this part of code to work you must have the "next" function available.
Fot those who are not that familiar with "next" function, please have a look <a href="http://expressjs.com/guide/using-middleware.html" target="_blank">here</a>.
<br/>Once you trigger this event the rest is on Express Happiness to take care of, according to the Error Handling Configuration File.

<h3>Predefined Errors</h3>
Express Happiness comes with a series of error types predefined. These are:
<ul>
<li><b>undefinedError</b> It's triggered for errors that don't belong to any of the defined errors. It's default configuration
is: <br/>
<p>Code Snippet 11.1. <b>Default undefinedError configuration</b></p>
<pre language="javascript"><code>
{
    log:true,
    humanReadable: 'Unresolved error code',
    sendToClient: {
        code:500
    }
}
</code></pre>
</li>

<li><b>invalidAttrs</b> It's triggered on parameters validation failure. It's default configuration
is: <br/>
<p>Code Snippet 11.2. <b>Default invalidAttrs configuration</b></p>
<pre language="javascript"><code>
{
    log:true,
    humanReadable: 'Invalid attributes passed',
    sendToClient: {
        code:400,
        data:'err.details'
    }
}
</code></pre>
</li>

<li><b>404</b> It's triggered whenever a route does not exist. It's default configuration
is: <br/>
<p>Code Snippet 11.3. <b>Default 404 configuration</b></p>
<pre language="javascript"><code>
{
    log:false,
    humanReadable: 'The requested resource does not exist',
    sendToClient: {
        code:404
    }
}
</code></pre>
</li>

<li><b>noMockData</b> It's triggered whenever a route that is defined to serve mock data, does not have any mock data file.
It's default configuration
is: <br/>
<p>Code Snippet 11.4. <b>Default noMockData configuration</b></p>
<pre language="javascript"><code>
{
    log: true,
    humanReadable: 'There is no mock data available for this route yet',
    sendToClient: {
        code: 404,
        data:'There is no mock data available for this route yet'
    }
}
</code></pre>
</li>

<li><b>underDevelopment</b> It's triggered in cases there's no controller function defined for a specific route.
It's default configuration is:<br/>
<p>Code Snippet 11.5. <b>Default underDevelopment configuration</b></p>
<pre language="javascript"><code>
{
    log: false,
    humanReadable: 'A call to a route under development has been made',
    sendToClient:{
        code:501,
        data:'This route is currently under development'
}
</code></pre>
</li>
</ul>
The default behaviour on any of these errors can be altered by redefining them on the Error Handling Configuration File.

<h3>error.log file</h3>
As mentioned earlier in this document, Express Happiness logs errors on an error log file. This file is defined on application
start. Express Happiness does not log all the errors but only those which have log:true on their definition on the Error
Handling Configuration File.<br/>
What's been logged on this document, for each error, is:
<p>Code Snippet 12. <b>Error Line structure logged on the error log file</b></p>
<pre language="javascript"><code>
date | error code | route | human readable explanation of the error | error details
</code></pre>

<h2>Mock Operation</h2>
For any endpoint that you define on your Routes Tree Configuration File, you have the chance to put it in mock operation
status. By "mock operation status" we mean that whenever a user hits the endpoint a static, predefined, mock response will
be served. <br/>
In order to do that you need two things:
<ul>
<li>Configure the endpoint to serve only mock data</li>
<li>Create a JSON file and put it in you mock files folder</li>
</ul>

<h3>How to set mock operation on</h3>
There are multiple ways to do that. First of all, in order to enable mock operations you have to set the mockData operation
on during the initialization of your application. We will see more details regarding the initial configuration object
passed on application start later on, though for now just keep in mind that when we start our application we pass a configuration
object which on "mockData" key holds an object that defines the folder of your mock files and the flag that set mock operation
on or off.<br/>
Having our mock folder defined and set mock operation to on we can force an endpoint to serve mock data by:
<ul>
<li>Putting in our mock files folder a file with the name --endpoint-alias--.json, where "--endpoint-alias--" is the alias
of the endpoint defined on the key "alias" of the endpoint on the Routes Tree Configuration File</li>
<li>Setting the operation status of the endpoint to mock by setting the "mock" attribute of the endpoint on the Routes Tree
Configuration File to true</li>
<li>Or by passing the parameter "mock" equals to 1 during the call</li>
</ul>
By this way, whenever you hit the specific endpoint you'll always get back the mock data defined on the specified file on
the mock files folder.

<h2>Controller Functions</h2>
Up to now we've seen almost everything regarding the definition process of an endpoint, the params validation and the error
handling mechanisms but we've said nothing regarding the actual controller function.<br/>
Assuming that a call passes all the middlewares, all the checks and it's not on mock operation status it reaches to the point
where something actual needs to take place, a controller function should take care of the call.<br/>
All controller functions are defined in a single file. As stated in the beginning of this document, the actual aim of this
architectural decision is not, of course, to pack all the code within this file but more to have one single point where you
can assign responsibilities and define the controllers of all of your routes in a clean and readable way.<br/>
This single file is called Controller Functions File and it looks like this:

<p>Code Snippet 12. <b>Example of Controller Functions File</b></p>
<pre language="javascript"><code>
var adminFunctions = require('./functions/admin.js');
var userFunctions = require('./functions/user.js');

var functions = {};

functions['route-alias-1'] = adminFunctions.doSomething;
functions['route-alias-2'] = userFunctions.doSomethingElse;

exports.functions = functions;
</code></pre>
It's just a mapping of all controller functions to the routes. As you can see from the example snippet 12, the Controller
Functions File should export an array. An associative array the keys of which are alias name of each route and the values
the corresponding controller functions of them. <br/>
The controller function for each endpoint is in the exact same format as a simple controller function that you would define
if you used express without Express Happiness. That is:
<p>Code Snippet 13. <b>Controller Function format</b></p>
<pre language="javascript"><code>
var my_controller_function = function(req, res, next){
    // do your magic here
}
</code></pre>
The third argument (next) is optional though if you want to use the automatic error handling mechanism within these functions
(that means to create a custom error, trigger it and let the Error Handling mechanism take care of it) you
certainly need the next function (see code snippet 10).

<h2>Application Configuration on start</h2>
Having the full of your application configured it's now time to fire it up. Express Happiness starts with the command:
<p>Code Snippet 15. <b>Starting your Express Happiness Server</b></p>
<pre language="javascript"><code>
var app = express();
var router = express.Router();

var eh = new expressHappiness(app, router, {
    mockData:{
        enable: true,
        folder: '/path/to/mockdatafolder',
        global: true
    },
    reusableFieldsFile: '/path/to/reusableFields.js',
    errorFile: '/path/to/errors.log',
    errorsConfigurationFile: '/path/to/conf/errors.js',
    apiConfigurationFile: 'path/to/conf/restConf.js',
    controllersFile: '/path/to/controllerFunctions.js'
});


eh.generate('/v1',
    {
        'userAccess':[middlewareA, middlewareB],
        'adminAccess':[middlewareC, middlewareD],
        'eh-allRoutes':[middlewareX]
    },
    {
        'userAccess':[middlewareA, middlewareB],
        'adminAccess':[middlewareC, middlewareD],
        'eh-allRoutes':[middlewareX]
    }
);
</code></pre>

First thing to do is to create a new Express Happiness instance. This is done by calling "new expressHappiness" function.
This function takes three parameters:
<ul>
<li><b>app</b>: the application initialized by the express() function invocation</li>
<li><b>router</b>: The Router object provided by express which we can get through express.Router() invocation</li>
<li><b>configuration</b>: a configuration object that sets the full Express Happiness environment up. Here we define the
path of each file needed by EH and also the mock operation configuration.</li>
</ul>

After creating the EH instance we call the "generate" function of it. The "generate" function takes three parameters:
<ul>
<li><b>route path</b>: this is the base url that our application will support. For example if we are developing a REST
API that listens to paths under /v1/ then we don't need to define this on the Routes Tree Configuration File. We can
define it here by passing the '/v1' value on the first argument of the generate function</li>
<li><b>pre-validation middlewares</b>: On the middlewares chain that are been executed on each call on our application,
EH always includes a middleware that performs the params validation for the given endpoint. The second argument
of the "generate" function provides us the ability to define a series of middlewares we want to get executed before reaching
the params validation step. The middlewares defined here, most often have to do with authentication issues. <br/>
The way we define our middlewares provides us the ability to explicitly define which middlewares should be executed according
the group that each route belongs to (see table 5). As mentioned, each endpoint might belong to one or more groups and this
is defined by the "groups" attribute (which holds an array). So, in our example for all endpoints that belong to the 'userAccess' group
the middlewareA and middlewareB functions will be executed before the middlewares chain reaches the params validation step. For
all middlewares that belong to the 'adminAccess' group the middlewareC and middlewareD will be executed before the params
validation middleware gets execute and so on. <br/>
If we want to define pre-validation middlewares for all of our endpoints, no matter the groups they belong to, we can use
the "eh-allRoutes" key to define them. All middlewares included on this array are going to be executed, in the order they
appear within the array, on all of our endpoints.
</li>
<li><b>post-validation middlewares</b>: The exact same things stand here. The third argument of the "generate" function
expects an object that though its keys defines the middlewares to be executed after the params validation process, on
our routes, depending on the groups they belong to.
</li>
</ul>

The form of our middlewares should be the typical middleware form of express: function(req, res, next).

<h2>Auto-generated API documentation</h2>
After defining all of your endpoints with types and parameters on the root of your application there will be the documentation
of your API. So, for example, if you run your app on localhost, port 7000, on http://localhost:7000 you'll find an
auto-generated REST API documentation page.







































================================================
FILE: RESTcallsValidator.js
================================================
var erH, reusableRequiredFields;
var validator = require('validator');
var moment = require('moment');
var restConf = {};

exports.assignConf = function(conf){
    restConf = conf;
}

exports.init = function(confObj){
    errorHandler = require('./ErrorHandler.js');
    erH = new errorHandler(confObj.errorFile, confObj.errorsConfigurationFile);
    reusableRequiredFields = require(confObj.reusableFieldsFile);
}

var validateEmail = function(email){
    var re = /^[a-zA-Z0-9+._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/;
    return re.test(email);
}

var hasTheErrorKey = function(field, errorKey){
    if(field.validationFailureTexts != null && field.validationFailureTexts != undefined){
        if(field.validationFailureTexts[errorKey] != null && field.validationFailureTexts[errorKey] != undefined){
            return field.validationFailureTexts[errorKey]
        }
    }
    return false;
}

var unitValidator = {
    int: function(field, value, path, errors, callback){
        var fieldNameOnResponse = field.humanReadable || path.join('.');

        if(!validator.isInt(value)){
            var er_message = hasTheErrorKey(field, 'type');
            if(er_message === false){
                errors.push(fieldNameOnResponse + ' must be an integer. ' + value + ' provided.');
            } else {
                errors.push(er_message);
            }
        } else {
            if(!!field.min){
                if(value < field.min){
                    var er_message = hasTheErrorKey(field, 'min');
                    if(er_message === false){
                        errors.push(fieldNameOnResponse + ' must be greater or equal to ' + field.min + '. ' + value + ' provided.');
                    } else {
                        errors.push(er_message);
                    }
                }
            }
            if(!!field.max){
                if(value > field.min){
                    var er_message = hasTheErrorKey(field, 'max');
                    if(er_message === false) {
                        errors.push(fieldNameOnResponse + ' must be lower or equal to ' + field.max + '. ' + value + ' provided.');
                    } else {
                        errors.push(er_message);
                    }
                }
            }
        }
        callback();
    },

    date: function(field, value, path, errors, callback){
        var fieldNameOnResponse = field.humanReadable || path.join('.');

        var momentObj = moment(value, field.validationString);
        if(!momentObj.isValid()){
            var er_message = hasTheErrorKey(field, 'validationString');
            if(er_message === false) {
                errors.push(fieldNameOnResponse + ' must be a date in the format: ' + field.validationString + '. ' + value + ' provided.');
            } else {
                errors.push(er_message);
            }
        } else {
            // in case of dates, for easiness we keep the momentObj representation of the passed variable, no matter
            // which is the format of the date that we expect
            //req.filteredParams[path.join('.') + field.key].momentObj = momentObj;
        }
        callback();
    },

    oneof: function(field, value, path, errors, callback){
        var fieldNameOnResponse = field.humanReadable || path.join('.');

        if(field.acceptedValues.indexOf(value) == -1){
            var er_message = hasTheErrorKey(field, 'acceptedValues');
            if(er_message === false) {
                errors.push(fieldNameOnResponse + ' must be one of ' + field.acceptedValues.join(', ') + '. ' + value + ' provided.');
            } else {
                errors.push(er_message);
            }
        }
        callback();
    },

    boolean: function(field, value, path, errors, callback){
        var fieldNameOnResponse = field.humanReadable || path.join('.');

        if(value !== true && value !== false && value !== 'true' && value !== 'false'){
            var er_message = hasTheErrorKey(field, 'type');
            if(er_message === false) {
                errors.push(fieldNameOnResponse + ' must be a boolean. ' + value + ' provided.');
            } else {
                errors.push(er_message);
            }
        }
        callback();
    },

    numeric: function(field, value, path, errors, callback){
        var fieldNameOnResponse = field.humanReadable || path.join('.');

        if(!validator.isFloat(value)){
            var er_message = hasTheErrorKey(field, 'type');
            if(er_message === false) {
                errors.push(fieldNameOnResponse + ' must be a number. ' + value + ' provided.');
            } else {
                errors.push(er_message);
            }
        }
        callback();
    },

    email: function(field, value, path, errors, callback){
        var fieldNameOnResponse = field.humanReadable || path.join('.');

        if(!validateEmail(value)){
            var er_message = hasTheErrorKey(field, 'type');
            if(er_message === false) {
                errors.push(fieldNameOnResponse + ' must be a valid email address. ' + value + ' provided.');
            } else {
                errors.push(er_message);
            }
        }
        callback();
    },

    string: function(field, value, path, errors, callback){
        var fieldNameOnResponse = field.humanReadable || path.join('.');

        if(!!field.minChars){
            if(value.length < field.minChars){
                var er_message = hasTheErrorKey(field, 'minChars');
                if(er_message === false) {
                    errors.push(fieldNameOnResponse + ' must be of at least ' + field.minChars + ' long. ' + value + ' provided.');
                } else {
                    errors.push(er_message);
                }
            }
        }
        if(!!field.maxChars){
            if(value.length > field.maxChars){
                var er_message = hasTheErrorKey(field, 'maxChars');
                if(er_message === false) {
                    errors.push(fieldNameOnResponse + ' must be of at max ' + field.maxChars + ' long. ' + value + ' provided.');
                } else {
                    errors.push(er_message);
                }
            }
        }
        if(!!field.regexp){
            var er_message = hasTheErrorKey(field, 'type');
            try{
                var passes = field.regexp.test(value);
                if(!passes){
                    if(er_message === false) {
                        errors.push(fieldNameOnResponse + ' do not match the provided regular expression');
                    } else {
                        errors.push(er_message);
                    }
                }
            } catch(err){
                if(er_message === false) {
                    errors.push(fieldNameOnResponse + ' do not match the provided regular expression');
                } else {
                    errors.push(er_message);
                }
            }
        }
        callback();
    },

    array: function(field, value, path, errors){
        var fieldNameOnResponse = field.humanReadable || path.join('.');

        if(!(variable.constructor === Array)){
            var er_message = hasTheErrorKey(field, 'type');
            if(er_message === false) {
                errors.push(fieldNameOnResponse + ' must be of type array. ' + value + ' provided.');
            } else {
                errors.push(er_message);
            }
        }
        if(!!field.minLength){
            if(value.length < field.minLength){
                var er_message = hasTheErrorKey(field, 'minLength');
                if(er_message === false) {
                    errors.push(fieldNameOnResponse + ' must be of at least of ' + field.minLength + ' length. ' + value + ' provided.');
                } else {
                    errors.push(er_message);
                }
            }
        }
        if(!!field.maxLength){
            if(value.length > field.maxLength){
                var er_message = hasTheErrorKey(field, 'maxLength');
                if(er_message === false) {
                    errors.push(fieldNameOnResponse + ' must be of max length ' + field.maxLength + '. ' + value + ' provided.');
                } else {
                    errors.push(er_message);
                }
            }
        }
        callback();
    }

};


var firstLevelIterator = function(fields, errors, req, func, callback){
    var index = 0;
    var done = false;
    var iterations = fields.length;
    var loop = {
        next: function(){
            if(done){
                return;
            }

            if(index < iterations){
                var self = this;
                var theField = fields[index];
                unitValidate(theField, errors, req, [theField.key],
                    function(){
                        index++;
                        func(self);
                    }
                );
            } else {
                done = true;
                callback();
            }
        }
    }

    loop.next();
    return loop;
}


var validate = function(obj, errors, req, path, func, callback) {
    var index = 0;
    var done = false;
    var iterations = Object.keys(obj.keys).length;
    var objKeys = Object.keys(obj.keys);
    var loop = {
        next: function() {
            if (done) {
                return;
            }

            if (index < iterations) {
                var newPath = path.slice();
                newPath.push(objKeys[index]);
                var self = this;
                unitValidate(obj.keys[objKeys[index]], errors, req, newPath, function(){
                    index++;
                    func(self);
                });

            } else {
                done = true;
                callback();
            }
        }
    };

    loop.next();
    return loop;
};

/*
 @unit: the unit to be validated taken from the signature
 @req: the request object
 @path: the base path of the current unit. It's an array
 @isRoot: a boolean indicating whether the passed unit is the root definition object or not
 @unitValidator: an instance of the unitValidator object defined above
 @callback: the callback to be called after the validation process
 */
var unitValidate = function(unit, errors, req, path, callback){
    var get = req.expressHappiness.get;
    var set = req.expressHappiness.set;

    // step 1: check if the parameter is present if it's mandatory according to the signature
    var mandatoryIssue = false;
    if(path.length > 0){
        if(unit.mandatory){
            try{
                var test_var = get(path[0]);
                for(var i=1; i<path.length; i++){
                    test_var = test_var[path[i]];
                }
                if(test_var === undefined || test_var === null){
                    errors.push(path.join('.') + ' is mandatory. Though is missing');
                    mandatoryIssue = true;
                }
            } catch(e){
                errors.push(path.join('.') + ' is mandatory. Though is missing');
                mandatoryIssue = true;
            }
        }
    }

    if(!mandatoryIssue){
        if(unit.type === 'object'){
            validate(unit, errors, req, path, function(loop){
                loop.next();
            }, callback)
        } else {
            try{
                var value = get(path[0]);
                for(var i=1; i<path.length; i++){
                    value = value[path[i]];
                }
                if(value === undefined || value === null){
                    callback();
                } else {
                    var validationFunct = unitValidator[unit.type];
                    validationFunct(unit, value, path, errors, callback);
                }
            } catch(e){
                callback();
            }
        }
    } else {
        callback();
    }

};



exports.validateAttrs = function(req, res, next){
    var get = req.expressHappiness.get;
    var set = req.expressHappiness.set;

    if(! restConf.routes[req.expressHappiness.apipath[0]] && !req.isRoot){
        var err = new Error();
        err.type = '404';
        return next(err);
    } else if(! restConf.routes[req.expressHappiness.apipath[0]] && req.isRoot){
        return next();
    } else {
        var currentNode = restConf.routes[req.expressHappiness.apipath[0]];
        for(var i=1; i<req.expressHappiness.apipath.length; i++){
            currentNode = currentNode.subRoutes[req.expressHappiness.apipath[i]];
            if(!currentNode){
                var err = new Error();
                err.type = '404';
                return next(err);
                break;
            }
        }

        if(!currentNode[req.expressHappiness.apiMethod].fields){
            return next();
        }

        var errors = [];

        firstLevelIterator(currentNode[req.expressHappiness.apiMethod].fields, errors, req, function(loop){
            loop.next();
        }, function() {
            if (errors.length > 0) {
                var err = new Error();
                err.type = 'invalidAttrs';
                err.details = errors;
                return next(err);
            } else {
                return next();
            }
        });
    }
}

var turnToFiltered = function(params){
    var filtered = {};
    for(k in params){
        filtered[k] = {
            value: params[k]
        };
    }
    return filtered;
}

================================================
FILE: conf/conf.js
================================================
var path = require('path');

exports.conf = {
    errorLogFile: path.resolve(__dirname, '../') + '/logs/error.log',
    mockOperations:{
        "get:/kpis/traffic":false,
        "get:/kpis/traffic/powerHours": false,
        "get:/kpis/traffic/entrances":false,
        "get:/kpis/dwellTime":false,
        "get:/kpis/loyalty":false,
        "get:/kpis/grossShoppingHours":false,
        "get:/kpis/shoppersVsTravellers":true,
        "get:/kpis/mallUse":true,
        "get:/kpis/areaUse":true,
        "get:/kpis/visitFrequency":true,
        "get:/kpis/abandonmentRate":false,
        "get:/kpis/drawRate":false,
        "get:/kpis/opportunity":false,
        "get:/kpis/hierarchy": true,
        "get:/sites/:site_id/locations": false
    },
    jwtSecret: 'N##$%W$&SFGHY$$^#W#%YLK"HBH4l5hjhbkdsljly5%$elawkjgy3%Y4foijfAWT$QTJQALDGKSDJFY$%L^KJ%^'
};


================================================
FILE: conf/errors.js
================================================
exports.errors = {
    undefinedError:{
        log:false,
        humanReadable: 'Unresolved error code',
        sendToClient: {
            code:200,
            data: 'ErrCode: 1 - There was an error fulfilling your request at the moment. Please try again in a while'
        },
        hooks:[
            // here you can put whatever you want
        ]
    }
}

================================================
FILE: conf/restConf.js
================================================
/*
All routes might belong to none, one or more groups.
Grouping routes helps us apply middlewares targeting only specific sets of routes
Grouping routes follows waterfall inheritance model. A group assigned to a route is been inherited by default by
    all of its subroutes. For example:
    routes:{
        routeA:{
            groups:['groupA'],
            subRoutes:{
                routeB:{
                    // routeB by default belongs to 'groupA'
                }
            }
        }
    }
    we can always change the groups that groupB (or any other sub-route) belongs to by redefining the groups attribute
    for example if want routeB not to belong on groupA but to belong on groupB then we can do it by:
    routes:{
        routeA:{
            groups:['groupA'],
            subRoutes:{
                routeB:{
                    groups:['groupB']
                }
            }
        }
    }
    and if want groupB to belong on groups at all then an empty groups attribute would do it:
    routes:{
        routeA:{
            groups:[],
            subRoutes:{
                routeB:{
                    // routeB by default belongs to 'groupA'
                }
            }
        }
    }
 */


module.exports.conf = function(fieldsLoader){
    return {
        // API routes signatures
        routes:{
            kpis:{
                groups:['userAccess'],
                subRoutes:{
                    traffic:
                    {
                        get:{
                            description:'Get the traffic',
                            fields:[
                                fieldsLoader.getField('orgId'),
                                fieldsLoader.getField('siteId'),
                                fieldsLoader.getField('locationId'),
                                fieldsLoader.getField('reportStartDate'),
                                fieldsLoader.getField('reportEndDate'),
                                fieldsLoader.getField('compareStartDate'),
                                fieldsLoader.getField('compareEndDate'),
                                fieldsLoader.getField('groupBy'),
                                fieldsLoader.getField('countType'),
                                fieldsLoader.getField('includeUnique'),
                                fieldsLoader.getField('includeReturning')
                            ]
                        },
                        subRoutes:{
                            powerHours: {
                                get:{
                                    description:'Get the traffic power hours',
                                    fields:[
                                        fieldsLoader.getField('orgId'),
                                        fieldsLoader.getField('siteId'),
                                        fieldsLoader.getField('reportStartDate'),
                                        fieldsLoader.getField('reportEndDate'),
                                        fieldsLoader.getField('countType'),
                                        fieldsLoader.getField('basePercentage')
                                    ]
                                }
                            }
                            ,entrances:{
                                get:{
                                    description:'Get the traffic monitoring point / quarter hour data',
                                    fields:[
                                        fieldsLoader.getField('orgId'),
                                        fieldsLoader.getField('siteId'),
                                        fieldsLoader.getField('reportStartDate'),
                                        fieldsLoader.getField('reportEndDate'),
                                        fieldsLoader.getField('countType'),
                                        fieldsLoader.getField('groupBy', {mandatory:true})
                                    ]
                                }
                            }
                        }
                    }
                    ,
                    dwellTime:{
                        get:{
                            description:'Get dwell time',
                            fields:[
                                fieldsLoader.getField('orgId'),
                                fieldsLoader.getField('siteId'),
                                fieldsLoader.getField('locationId'),
                                fieldsLoader.getField('reportStartDate'),
                                fieldsLoader.getField('reportEndDate'),
                                fieldsLoader.getField('compareStartDate'),
                                fieldsLoader.getField('compareEndDate'),
                                fieldsLoader.getField('groupBy'),
                                fieldsLoader.getField('includeDist'),
                                {
                                    key:'allLocations',
                                    type:'boolean',
                                    humanReadable: 'get massive report for all locations',
                                    description:'Get data for all locations of a given site but for each location separately',
                                    mandatory:false,
                                    default:false
                                }
                            ]
                        }
                    },
                    loyalty:{
                        get:{
                            description:'Get loyalty',
                            fields:[
                                fieldsLoader.getField('orgId'),
                                fieldsLoader.getField('siteId'),
                                fieldsLoader.getField('locationId'),
                                fieldsLoader.getField('reportStartDate'),
                                fieldsLoader.getField('reportEndDate'),
                                fieldsLoader.getField('compareStartDate', {mandatory:true}),
                                fieldsLoader.getField('compareEndDate', {mandatory:true}),
                                fieldsLoader.getField('type')
                            ]
                        }
                    },
                    grossShoppingHours:{
                        get:{
                            description:'Get gross shopping hours',
                            fields:[
                                fieldsLoader.getField('orgId'),
                                fieldsLoader.getField('siteId'),
                                fieldsLoader.getField('locationId'),
                                fieldsLoader.getField('reportStartDate'),
                                fieldsLoader.getField('reportEndDate'),
                                fieldsLoader.getField('compareStartDate'),
                                fieldsLoader.getField('compareEndDate'),
                                fieldsLoader.getField('groupBy'),
                                fieldsLoader.getField('includeUnique'),
                                fieldsLoader.getField('includeReturning')
                            ]
                        }
                    },
                    shoppersVsTravellers:{
                        get:{
                            description:'Get shoppers vs travellers',
                            fields:[
                                fieldsLoader.getField('orgId'),
                                fieldsLoader.getField('reportStartDate'),
                                fieldsLoader.getField('reportEndDate'),
                                fieldsLoader.getField('compareStartDate'),
                                fieldsLoader.getField('compareEndDate'),
                                fieldsLoader.getField('groupBy')
                            ]
                        }
                    },
                    abandonmentRate:{
                        get:{
                            description:'Get abandonment rates',
                            fields:[
                                fieldsLoader.getField('orgId'),
                                fieldsLoader.getField('siteId'),
                                fieldsLoader.getField('locationId'),
                                fieldsLoader.getField('reportStartDate'),
                                fieldsLoader.getField('reportEndDate'),
                                fieldsLoader.getField('compareStartDate'),
                                fieldsLoader.getField('compareEndDate'),
                                fieldsLoader.getField('groupBy')
                            ]
                        }
                    },
                    drawRate:{
                        get:{
                            description:'Get draw rate',
                            fields:[
                                fieldsLoader.getField('orgId'),
                                fieldsLoader.getField('siteId'),
                                fieldsLoader.getField('locationId'),
                                fieldsLoader.getField('reportStartDate'),
                                fieldsLoader.getField('reportEndDate'),
                                fieldsLoader.getField('compareStartDate'),
                                fieldsLoader.getField('compareEndDate'),
                                fieldsLoader.getField('groupBy')
                            ]
                        }
                    },
                    opportunity:{
                        get:{
                            description:'Get opportunity',
                            fields:[
                                fieldsLoader.getField('orgId'),
                                fieldsLoader.getField('siteId'),
                                fieldsLoader.getField('locationId'),
                                fieldsLoader.getField('reportStartDate'),
                                fieldsLoader.getField('reportEndDate'),
                                fieldsLoader.getField('compareStartDate'),
                                fieldsLoader.getField('compareEndDate'),
                                fieldsLoader.getField('groupBy')
                            ]
                        }
                    }
                }
            },
            auth: {
                post: {
                    description:'Authenticate user',
                    fields:[
                        fieldsLoader.getField('username'),
                        fieldsLoader.getField('user_password')
                    ]
                }
            },
            users:{
                groups:['superUserAccess'],
                get:{
                    description:'Get users',
                    fields:[]
                },
                post:{
                    description:'Post new user',
                    fields:[
                        fieldsLoader.getField('username'),
                        fieldsLoader.getField('user_password')
                    ]
                },
                subRoutes:{
                    ':user_id':{
                        get:{
                            description:'Get a specific user info',
                            fields:[]
                        },
                        put:{
                            description: 'Edit user\'s info',
                            fields:[
                                fieldsLoader.getField('user_password', {mandatory: false}),
                                fieldsLoader.getField('expired'),
                                fieldsLoader.getField('accessMap')
                            ]
                        },
                        delete:{
                            description: 'Delete user',
                            fields:[]
                        }
                    }
                }
            },
            organizations:{
                groups:['userAccess'],
                get:{
                    groups:[],  // the endpoint will check access to filter down org list
                    description:'Get organizations list',
                    fields:[]
                },
                post:{
                    groups:['superUserAccess'],
                    description:'Create a new organization',
                    fields:[
                        fieldsLoader.getField('orgId'),
                        fieldsLoader.getField('name')
                    ]
                },
                subRoutes:{
                    ':orgId':{
                        get:{
                            description: 'Organization\'s details',
                            fields:[]
                        },
                        put:{

                            description:'Edit organization\'s data',
                            fields:[
                                fieldsLoader.getField('name'),
                                fieldsLoader.getField('expired')
                            ]
                        },
                        delete:{

                            description: 'Delete organization',
                            fields:[]
                        },
                        subRoutes:{
                            users:{
                                groups:['orgAdmin'],
                                get:{
                                    description:'Get all users for which current user is an org admin',
                                    fields:[]
                                },
                                post:{
                                    description:'Add user to the current organization.  Create user if it does not exist.',
                                    fields:[
                                        fieldsLoader.getField('username'),
                                        fieldsLoader.getField('user_password', {mandatory: false})
                                    ]
                                },
                                subRoutes:{
                                    ':user_id':{
                                        get:{
                                            description:'get the user data, including access map. if user does not exist OR is not in org, return not found',
                                            fields:[]
                                        },
                                        put:{
                                            description:'update user data, including access map. if user does not exist OR is not in org, return not found',
                                            fields:[
                                                fieldsLoader.getField('user_password', {mandatory: false}),
                                                fieldsLoader.getField('expired'),
                                                fieldsLoader.getField('accessMap')
                                            ]
                                        },
                                        delete:{
                                            description:'remove user from organization. Never removes the user completely',
                                            fields:[]
                                        }
                                    }
                                }
                            },
                            sites:{
                                get:{
                                    description:'Get sites list',
                                    fields:[]
                                },
                                post:{

                                    description:'Create a new site',
                                    fields:[
                                        fieldsLoader.getField('siteId'),
                                        fieldsLoader.getField('name', {
                                            description:'Site name',
                                            humanReadable: 'Site name'
                                        }),
                                        fieldsLoader.getField('name', {
                                            key:'organization_name'
                                        }),
                                        fieldsLoader.getField('geo')
                                    ]
                                },
                                subRoutes:{
                                    ':siteId':{
                                        get:{
                                            description: 'Site\'s details',
                                            fields:[]
                                        },
                                        put:{

                                            description:'Edit site\'s data',
                                            fields:[
                                                fieldsLoader.getField('name', {
                                                    description:'Site name',
                                                    humanReadable: 'Site name'
                                                }),
                                                fieldsLoader.getField('name', {
                                                    key:'organization_name'
                                                }),
                                                fieldsLoader.getField('geo'),
                                                fieldsLoader.getField('expired')
                                            ]
                                        },
                                        delete:{

                                            description: 'Delete site',
                                            fields:[]
                                        },
                                        subRoutes:{
                                            locations:{
                                                get:{
                                                    description: 'Get site\'s locations',
                                                    fields:[]
                                                },
                                                post:{

                                                    description:'Create a new location',
                                                    fields:[
                                                        fieldsLoader.getField('location_id'),
                                                        fieldsLoader.getField('location_type'),
                                                        fieldsLoader.getField('name', {
                                                            key:'site_name',
                                                            description:'Site name',
                                                            humanReadable: 'Site name'
                                                        }),
                                                        fieldsLoader.getField('name', {
                                                            key:'organization_name',
                                                            description:'Organization name',
                                                            humanReadable: 'Organization name'
                                                        }),
                                                        fieldsLoader.getField('description'),
                                                        fieldsLoader.getField('beacon_id'),
                                                        fieldsLoader.getField('generic_other', {
                                                            key:'nested_set_left'
                                                        }),
                                                        fieldsLoader.getField('generic_other', {
                                                            key:'nested_set_right'
                                                        }),
                                                        fieldsLoader.getField('generic_other', {
                                                            key:'nested_set_depth'
                                                        }),
                                                        fieldsLoader.getField('traffic_monitoring_point_entrance_id'),
                                                        fieldsLoader.getField('traffic_monitoring_point_description')
                                                    ]
                                                },
                                                subRoutes:{
                                                    ':locationId':{
                                                        get:{
                                                            description: 'locations\'s details',
                                                            fields:[]
                                                        },
                                                        put:{

                                                            description:'Edit locations\'s data',
                                                            fields:[
                                                                fieldsLoader.getField('location_type'),
                                                                fieldsLoader.getField('name', {
                                                                    key:'site_name',
                                                                    description:'Site name',
                                                                    humanReadable: 'Site name'
                                                                }),
                                                                fieldsLoader.getField('name', {
                                                                    key:'organization_name',
                                                                    description:'Organization name',
                                                                    humanReadable: 'Organization name'
                                                                }),
                                                                fieldsLoader.getField('description'),
                                                                fieldsLoader.getField('beacon_id'),
                                                                fieldsLoader.getField('generic_other', {
                                                                    key:'nested_set_left'
                                                                }),
                                                                fieldsLoader.getField('generic_other', {
                                                                    key:'nested_set_right'
                                                                }),
                                                                fieldsLoader.getField('generic_other', {
                                                                    key:'nested_set_depth'
                                                                }),
                                                                fieldsLoader.getField('traffic_monitoring_point_entrance_id'),
                                                                fieldsLoader.getField('traffic_monitoring_point_description'),
                                                                fieldsLoader.getField('expired')
                                                            ]
                                                        },
                                                        delete:{

                                                            description: 'Delete locations',
                                                            fields:[]
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
};

================================================
FILE: expressHappiness.js
================================================
var restConf = {
    routes:[]
}
var kpis
    ,rcv;
var fs = require('fs');
var colors = require('colors');
var flatSignature = [];
var app, router, confObj;


var eh = function(p_app, p_router, conf){
    app = p_app;
    router = p_router;
    var path = require('path');
    var appDir = path.dirname(require.main.filename);
    this.generate = successGenerate;

    confObj = {
        mockData:{
            enable: true,
            folder: appDir + '/mockJSONs',
            global:false
        },
        reusableFieldsFile: appDir + '/expressHappiness/reusableFields.js',
        errorFile:appDir + '/expressHappiness/errors.log',
        errorsConfigurationFile:appDir + '/expressHappiness/conf/errors.js',
        apiConfigurationFile:appDir + '/expressHappiness/conf/restConf.js',
        controllersFile:appDir + '/expressHappiness/controllerFunctions.js'
    };

    if(!conf){
        conf = {};
    }
    for(var propertyName in conf) {
        if(conf.hasOwnProperty(propertyName)){
            confObj[propertyName] = conf[propertyName];
        }
    }

    var errorOccurred = false;
    if(!fs.existsSync(confObj.reusableFieldsFile)){
        errorOccurred = true;
        var msg = "Reusable fields file (" + confObj.reusableFieldsFile + ") does not exist. Please create it according the documentation";
        console.log(msg.red.bgWhite);
    }
    if(!fs.existsSync(confObj.errorFile)){
        errorOccurred = true;
        var msg = "Error log file (" + confObj.errorFile + ") does not exist. Please create it according the documentation";
        console.log(msg.red.bgWhite);
    }
    if(!fs.existsSync(confObj.errorsConfigurationFile)){
        errorOccurred = true;
        var msg = "Errors configuration file (" + confObj.errorsConfigurationFile + ") does not exist. Please create it according the documentation"
        console.log(msg.red.bgWhite);
    }
    if(!fs.existsSync(confObj.apiConfigurationFile)){
        errorOccurred = true;
        var msg = "REST API configuration file (" + confObj.apiConfigurationFile + ") does not exist. Please create it according the documentation"
        console.log(msg.red.bgWhite);
    }
    if(!fs.existsSync(confObj.controllersFile)){
        errorOccurred = true;
        var msg = "Controller functions definition file (" + confObj.controllersFile + ") does not exist. Please create it according the documentation"
        console.log(msg.red.bgWhite);
    }
    if(confObj.mockData.enable && !fs.existsSync(confObj.mockData.folder)){
        errorOccurred = true;
        var msg = "Mock data folder (" + confObj.mockData.folder + ") does not exist. Please create it according the documentation"
        console.log(msg.red.bgWhite);
    }

    if(errorOccurred){
        this.generate = failureGenerate;
    } else {
        // Rest validation initialization
        var FL = require('./fieldsLoader.js');
        var fieldsLoader = new FL(confObj.reusableFieldsFile);
        restConf = require(confObj.apiConfigurationFile).conf(fieldsLoader);

        global.expressHappiness = {
            confObj: confObj
        };
        // TODO change the folder
        rcv = require('./RESTcallsValidator.js');
        rcv.init(confObj);
        rcv.assignConf(restConf);
        kpis = require(confObj.controllersFile);
    }

    this.start = function(port){
        if(!port){
            var msg = "Please enter the port number for the app to run. Exiting.";
            console.log(msg.red.bgWhite);
            process.exit(1);
        } else {
            isPortTaken(port, function(err, taken){
                if(taken) {
                    var msg = 'Port ' + port + ' is been used by another application. Exiting.';
                    console.log(msg.red.bgWhite);
                    process.exit(1);
                } else {
                    p_app.listen(port);
                    var msg = 'The application is listening on port ' + port + ' for connections.';
                    console.log(msg.green);
                }
            });
        }
    }

}

/*
checks if the port is taken
 */
var isPortTaken = function(port, fn) {
    var net = require('net')
    var tester = net.createServer()
        .once('error', function (err) {
            if (err.code != 'EADDRINUSE') return fn(err)
            fn(null, true)
        })
        .once('listening', function() {
            tester.once('close', function() { fn(null, false) })
                .close()
        })
        .listen(port)
}


/* Reads the restConf and generates all available routes according to it.
 Also, it acts as debugger. For each of the generated routes the generate function checks if there is
 a corresponding method defined on the kpi controller, if there is mock data file available and it logs everything
 to the console.
 Missing methods are replaced by a generic one which handles their absence.
 Also, routes that do not provide mock data are configured so noMockAvailable function will be called whenever
 mock operation is on for them. For routes that actually have corresponding mock data files available the
 makeMockQuery function will be invoked for mock operation cases. Also, for efficiency reasons the makeMockQuery function
 for each of the routes that actually provide mock data is been generated once here (by reading the corresponding file)
 and it's been passed, so only one file read occurs for each route, only once, only at the kick off.
 It takes three parameters:
 @ router [object]: express framework router object
 @ baseUrl [string]: the base url of the routes to create
 @ preValidationMiddlewares [array][array]: holds all the middlewares that should be applied to the specific routes. These middlewares are been applied before validation
 it is an associative array. On restConf.js file each route might belong to one or more groups. For each group there might be different middlewares applied.
 This is achieved by using the group names as the first level keys of the array. Each key will hold another array which actual holds
 all the middlewares to be applied to the specific groups. Example:
 preValidationMiddlewares ~=
 [
 'userAccess':[middlewareName1, middleware2],
 'adminAccess':[middlewareName3, middleware4]
 ]
 if we want to apply a middleware to all of the routes, no matter what then we can define this by including it on the key "eh-allRoutes".
 Example:
 preValidationMiddlewares ~=
 [
 'groupNameOne':[middlewareName1, middleware2],
 'groupNameTwo':[middlewareName3, middleware4],
 'eh-allRoutes':[middlewareToBeAppliedToAllRoutes1, middlewareToBeAppliedToAllRoutes2]
 ]
 @ postValidationMiddlewares [array][array]: holds all the middlewares that should be applied after the validation process and before the controller function invocation
 it is an associative array. On restConf.js file each route might belong to one or more groups. For each group there might be different middlewares applied.
 This is achieved by using the group names as the first level keys of the array. Each key will hold another array which actual holds
 all the middlewares to be applied to the specific groups. Example:
 postValidationMiddlewares ~=
 [
 'groupNameOne':[middlewareName1, middleware2],
 'groupNameTwo':[middlewareName3, middleware4]
 ]
 if we want to apply a middleware to all of the routes, no matter what then we can define this by including it on the key "eh-allRoutes".
 Example:
 postValidationMiddlewares ~=
 [
 'groupNameOne':[middlewareName1, middleware2],
 'groupNameTwo':[middlewareName3, middleware4],
 'eh-allRoutes':[middlewareToBeAppliedToAllRoutes1, middlewareToBeAppliedToAllRoutes2]
 ]
 */
var successGenerate = function(baseUrl, preValidationMiddlewares, postValidationMiddlewares){
    var theRoute = router.route(baseUrl + '/');
    theRoute.get(putMethodsOnReq('get'));
    theRoute.get(putApipathToReq([], ''));
    theRoute.get(function(req, res, next){
        req.isRoot = true;
        return next();
    });
    for(var i=0; i<preValidationMiddlewares.length; i++){
        theRoute.all(preValidationMiddlewares[i]);
    }
    theRoute.get(function(req, res){
        var fs = require('fs');
        fs.readFile(__dirname + '/views/index.html', { 'encoding':'utf8'}, function(err, data){
            if(err){
                console.log(err);
            } else {
                var _ = require('underscore');
                var template = _.template(data);
                res.send(template({signature:flatSignature}));
            }
        });
        //res.render('null', {layout:'./index', signature:flatSignature});
    });


    var routeObject = {
        subRoutes:  restConf.routes
    };

    generateNodeRoutes(routeObject, '', [], router, baseUrl, preValidationMiddlewares, postValidationMiddlewares, []);
    registerErrors(app, confObj.errorsConfigurationFile, confObj.errorFile);
};

var failureGenerate = function(){
    console.log("Routes generation process skipped due to errors. Please fix the errors accordingly and retry".red.bgWhite);
    process.exit(0);
}

module.exports = eh;

var generateNodeRoutes = function(node, nodeName, path, router, baseUrl, preValidationMiddlewares, postValidationMiddlewares, inheritedGroups){
    if(node.hasOwnProperty('groups')){
        inheritedGroups = node.groups;
    }
    var supportedTypes = ['get', 'post', 'put', 'delete'];

    for(var k=0; k<supportedTypes.length; k++){
        if(node.hasOwnProperty(supportedTypes[k])){
            if(node[supportedTypes[k]].hasOwnProperty('groups')){
                inheritedGroups = node[supportedTypes[k]].groups;
            }
            flatSignature.push({
                type: supportedTypes[k],
                node:node[supportedTypes[k]],
                path:baseUrl + path.join('/') + '/' + nodeName
            });

            var mockQueryMiddleware = mockQueryGenerationMiddleWare(supportedTypes[k], path, nodeName, node[supportedTypes[k]].alias);

            var theRoute = router.route(baseUrl + path.join('/') + '/' + nodeName);
            theRoute[supportedTypes[k]](putMethodsOnReq(supportedTypes[k]));
            theRoute[supportedTypes[k]](putApipathToReq(path, nodeName,
                node[supportedTypes[k]].alias, node[supportedTypes[k]].mock));

            if(preValidationMiddlewares.hasOwnProperty('eh-allRoutes')){
                for(var ii=0; ii<preValidationMiddlewares['eh-allRoutes'].length; ii++){
                    theRoute[supportedTypes[k]](preValidationMiddlewares['eh-allRoutes'][ii]);
                }
            }
            for(var i=0; i<inheritedGroups.length; i++){
                if(preValidationMiddlewares.hasOwnProperty(inheritedGroups[i])){
                    for(var ii=0; ii<preValidationMiddlewares[inheritedGroups[i]].length; ii++){
                        theRoute[supportedTypes[k]](preValidationMiddlewares[inheritedGroups[i]][ii]);
                    }
                }
            }

            theRoute[supportedTypes[k]](rcv.validateAttrs);
            theRoute[supportedTypes[k]](mockQueryMiddleware);
            theRoute[supportedTypes[k]](mockMiddlewareApplied);

            if(postValidationMiddlewares){
                if(postValidationMiddlewares.hasOwnProperty('eh-allRoutes')){
                    for(var ii=0; ii<postValidationMiddlewares['eh-allRoutes'].length; ii++){
                        theRoute[supportedTypes[k]](postValidationMiddlewares['eh-allRoutes'][ii]);
                    }
                }
                for(var i=0; i<inheritedGroups.length; i++){
                    if(postValidationMiddlewares.hasOwnProperty(inheritedGroups[i])){
                        for(var ii=0; ii<postValidationMiddlewares[inheritedGroups[i]].length; ii++){
                            theRoute[supportedTypes[k]](postValidationMiddlewares[inheritedGroups[i]][ii]);
                        }
                    }
                }
            }

            var aliasedFunction = false;
            if(node[supportedTypes[k]].alias){
                if(kpis.functions[node[supportedTypes[k]].alias] != undefined && kpis.functions[node[supportedTypes[k]].alias] != null){
                    theRoute[supportedTypes[k]](kpis.functions[node[supportedTypes[k]].alias]);
                    aliasedFunction = true;
                }
            }

            if(!aliasedFunction){
                if(kpis.functions[supportedTypes[k] + ":" + path.join('/') + '/' + nodeName] != undefined && kpis.functions[supportedTypes[k] + ":" + path.join('/') + '/' + nodeName] != null){
                    theRoute[supportedTypes[k]](kpis.functions[supportedTypes[k] + ":" + path.join('/') + '/' + nodeName]);
                } else {
                    var msg = '-- WARNING -- There is currently no control method defined for route ' + path.join('/') + '/' + nodeName + '. Please create it on /controllers/routesControllerFunctions.js and assign it to functions["' + path.join('/') + '/' + nodeName + '"]';
                    console.log(msg.red.bgWhite);
                    theRoute[supportedTypes[k]](noControlMethodCallback);
                }
            }


            console.log('Route ' + supportedTypes[k].toUpperCase() + ' "'  + path.join('/') + '/' + nodeName + '" created successfully'.green);
        }
    }

    if(node.hasOwnProperty('subRoutes')){
        var newPath = path.slice(0);
        newPath.push(nodeName);
        for(var property in node.subRoutes) {
            if(node.subRoutes.hasOwnProperty(property)){ // first we check that the property is not an inherited one
                generateNodeRoutes(node.subRoutes[property], property, newPath, router, baseUrl, preValidationMiddlewares, postValidationMiddlewares, inheritedGroups);
            }
        }
    }

    app.use('', router);
    app.get('*', function(req, res, next){
        var err = new Error();
        err.type = '404';
        return next(err);
    });
}


var putMethodsOnReq = function(method){
    return function(req, res, next){
        req.expressHappiness = {};
        req.expressHappiness.apiMethod = method;
        req.expressHappiness.get = getGetter(req);
        req.expressHappiness.set = getSetter(req);
        return next();
    }
}


var mockQueryGenerationMiddleWare = function(type, path, nodeName, alias){
    if(!global.expressHappiness.confObj.mockData.enable){
        return function(req, res, next){
            return next();
        }
    }

    var filename = '';
    var route = '';
    for(var i=1; i<path.length; i++){
        filename += path[i] + '.';
        route += path[i] + '/';
    }
    route += nodeName;
    filename += nodeName;

    if(alias){
        if(fs.existsSync(global.expressHappiness.confObj.mockData.folder + '/' + alias + '.json')){
            var mockData = require(global.expressHappiness.confObj.mockData.folder + '/' + alias + '.json');

            return function(req, res, next){
                req.expressHappiness.mockQuery = function(success){
                    success(mockData);
                }
                return next();
            }
        }
    }


    if(fs.existsSync(global.expressHappiness.confObj.mockData.folder + '/' + type + '.' + filename + '.json')){
        var mockData = require(global.expressHappiness.confObj.mockData.folder + '/' + type + '.' + filename + '.json');

        return function(req, res, next){
            req.expressHappiness.mockQuery = function(success){
                success(mockData);
            }
            return next();
        }
    } else {
        var msg = '-- WARNING -- No mock data found for ' + route + ' route. Please create file named ' + filename + '.json and place it on mockJSONs folder';
        console.log(msg.red.bgWhite);
        return function(req, res, next){
            req.expressHappiness.mockQuery = function(success){
                var err = new Error();
                err.type = 'noMockData';
                return next(err);
            };
            return next();
        }
    }
}

var getGetter = function(req){
    if(req.expressHappiness.apiMethod == 'get'){
        return function(key){
            return req.query[key];;
        }
    } else {
        return function (key) {
            return req.body[key];
        }
    }
}

var getSetter = function(req){
    if(req.expressHappiness.apiMethod == 'get'){
        return function(key, value){
            req.query[key] = value;
        }
    } else {
        return function(key, value){
            req.body[key] = value;
        }
    }
}


var noControlMethodCallback = function(req, res, next){
    var err = new Error("Under Development");
    err.type = 'underDevelopment';
    return next(err);
}

var putApipathToReq = function(path, nodeName, alias, mock){
    return function(req, res, next){
        var newPath = path.slice(0);
        newPath.shift();
        newPath.push(nodeName);
        req.expressHappiness.apipath = newPath;
        req.expressHappiness.routeAlias = alias;
        req.expressHappiness.mock = mock;
        return next();
    }
}


var mockMiddlewareApplied = function(req, res, next){
    if(global.expressHappiness.confObj.mockData.global){
        req.expressHappiness.mockQuery(function(results){
            return res.send(results);
        });
    } else if((req.expressHappiness.get('mock') != 1 && !req.expressHappiness.mock) || !global.expressHappiness.confObj.mockData.enable){
        return next();
    } else {
        req.expressHappiness.mockQuery(function(results){
            return res.send(results);
        });
    }
}

var registerErrors = function(app, errorsConfigurationFile, errorFile){
    var errors = require(errorsConfigurationFile).errors;
    var undefinedError = {
        log:true,
        humanReadable: 'Unresolved error code',
        sendToClient: {
            code:500
        }
    };

    var invalidAttrs = {
        log:true,
        humanReadable: 'Invalid attributes passed',
        sendToClient: {
            code:400,
            data:'err.details'
        }
    };

    var fourZeroFour = {
        log:false,
        humanReadable: 'The requested resource does not exist',
        sendToClient: {
            code:404
        }
    };

    var noMockData = {
        log: true,
        humanReadable: 'There is no mock data available for this route yet',
        sendToClient: {
            code: 404,
            data:'There is no mock data available for this route yet'
        }
    };

    var underDevelopment = {
        log: false,
        humanReadable: 'A call to a route under development has been made',
        sendToClient:{
            code:501,
            data:'This route is currently under development'
        }
    };

    if(!errors.hasOwnProperty('undefinedError')) {
        errors.undefinedError = undefinedError;
    } else {
        errors.undefinedError = formatError(undefinedError, errors.undefinedError)
    }
    if(!errors.hasOwnProperty('invalidAttrs')) {
        errors.invalidAttrs = invalidAttrs;
    } else {
        errors.invalidAttrs = formatError(invalidAttrs, errors.invalidAttrs)
    }
    if(!errors.hasOwnProperty('404')) {
        errors['404'] = fourZeroFour;
    } else {
        errors['404'] = formatError(fourZeroFour, errors['404'])
    }
    if(!errors.hasOwnProperty('noMockData')) {
        errors.noMockData = noMockData;
    } else {
        errors.noMockData = formatError(noMockData, errors.noMockData)
    }
    if(!errors.hasOwnProperty('underDevelopment')) {
        errors.underDevelopment = underDevelopment;
    } else {
        errors.underDevelopment = formatError(underDevelopment, errors.underDevelopment)
    }

    var ErrorHandlerModule = require('./ErrorHandler.js');
    var ErrorHanlder = new ErrorHandlerModule(errorFile);
    app.use(function (err, req, res, next) {
        if(errors.hasOwnProperty(err.type)){
            ErrorHanlder.handleError(errors[err.type], err, req, res);
        } else {
            ErrorHanlder.handleError(errors.undefinedError, err, req, res);
        }
    });
};

var formatError = function(error, options){
    var keys = Object.keys(options);
    for(var i=0; i<keys.length; i++){
        var key = keys[i];
        error[key] = options[key];
    }
    return error;
}

================================================
FILE: fieldsLoader.js
================================================
module.exports = function(reusableFile){
    var reusableRequiredFields = require(reusableFile);

    /*
     Returns the corresponding field object from the reusableRequiredFields variable

     @name: the name of the field
     @options: optionally pass an options object. All keys of this object will be used to overwrite the default values
     of the the corresponding keys of the original field definition.

     Example:
     getField('orgId')
     Returns:
     {
     key:'orgId',
     type:'int',
     humanReadable: 'organization id',
     description:'The Organization from which data is requested',
     mandatory:true
     }

     getField('orgId', {mandatory:false});
     Returns:
     {
     key:'orgId',
     type:'int',
     humanReadable: 'organization id',
     description:'The Organization from which data is requested',
     mandatory:false
     }
     */
    this.getField = function(name, options){
        if(!reusableRequiredFields[name]){
            console.log('The requested field ' + name + ' does not exist on the reusableRequiredFields object');
            return {
                key:'invalid_key'
            };
        } else {
            var toReturn = JSON.parse(JSON.stringify(reusableRequiredFields[name]));
            if(!!options){
                var keys = Object.keys(options);
                for(var i=0; i<keys.length; i++){
                    var key = keys[i];
                    toReturn[key] = options[key];
                }
            }
            return toReturn;
        }
    }
}

================================================
FILE: helpers/helpers.js
================================================
var validate = function(obj, func, callback) {
    var index = 0;
    var done = false;
    var iterations = Object.keys(obj).length;
    var objKeys = Object.keys(obj);
    console.log('got into validate');
    console.log('Number of keys: ' + iterations);
    var loop = {
        next: function() {
            if (done) {
                return;
            }

            if (index < iterations) {
                var self = this;
                unitValidate(obj[objKeys[index]], function(){
                    index++;
                    func(self);
                });

            } else {
                done = true;
                callback();
            }
        }
    };

    loop.next();
    return loop;
};


var unitValidate = function(unit, callback){
    console.log('unit: ');
    console.log(unit);
    if(typeof unit === 'object'){
        console.log('unit is object')
        validate(unit, function(loop){
            loop.next();
        }, callback)
    } else {
        console.log('unit is primitive');
        console.log('validating unit');
        callback();
    }
};

var obj = {
    a:4,
    b:'test',
    c:{
        ca:'ca',
        cb:4,
        d:{
            da:'abc',
            db:1412
        }
    }
}

unitValidate(obj, function() {
        console.log('done');
    }
);

================================================
FILE: package.json
================================================
{
  "name": "express-happiness",
  "version": "0.7.2",
  "description": "Express framework wrapper",
  "main": "expressHappiness.js",
  "dependencies" : {
    "validator" : "^3.34.0"
  , "colors" : "^1.0.3"
  , "moment" : "^2.9.0"
  , "underscore":"^1.8.2"
  },
  "repository": {
    "type": "git",
    "url": "git://github.com/andreas-trad/express-happiness.git"
  },
  "keywords": [
    "express"
  ],
  "author": "Andreas Trantidis <atrantidis@gmail.com>",
  "license": "BSD-2-Clause",
  "bugs": {
    "url": "https://github.com/andreas-trad/express-happiness/issues"
  }
}

================================================
FILE: views/index.html
================================================

<!DOCTYPE html>
<html lang="en">
<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 name="description" content="">
    <meta name="author" content="">

    <title>KPIS documentation</title>

    <!-- Bootstrap core CSS -->
    <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">

</head>

<body role="document">
<div class="container theme-showcase" role="main">

    <% _.each(signature, function(item){ %>
    <div class="page-header">
        <h1><%= item.type.toUpperCase() %> <%= item.path %></h1>
    </div>

    <div class="well">
        <p><%= item.node.description %></p>
    </div>

    <div class="row">
        <div class="col-md-12">
            <h2>Parameters</h2>
            <table class="table table-striped">
                <thead>
                <tr>
                    <th>Name</th>
                    <th>Type</th>
                    <th>Description</th>
                    <th>Mandatory</th>
                    <th>Extra Info</th>
                </tr>
                </thead>
                <tbody>
                <% _.each(item.node.fields, function(field){ %>
                <tr>
                    <td><%= field.key %></td>
                    <td><%= field.type %></td>
                    <td><%= field.description %></td>
                    <td><% if(field.mandatory){ %>Yes<% } else { %>No<% } %></td>
                    <td>
                        <% if(field.type == 'oneof'){ %>Must be one of: <%= field.acceptedValues.join(', ') %><% } %>
                        <% if(field.type == 'date'){ %>Accepted date format: <%= field.validationString %><% } %>
                        <% if(field.type == 'string' && !!field.minChars){ %>Must be at least <%= field.minChars %> characters long <% } %>
                        <% if(field.type == 'string' && !!field.maxChars){ %>Must be at max <%= field.maxChars %> characters long <% } %>
                    </td>
                </tr>
                <% }); %>
                </tbody>
            </table>
        </div>
    </div>
    <% }); %>

</div> <!-- /container -->


<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="/js/jquery.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
</body>
</html>
Download .txt
gitextract_icssqfkl/

├── .idea/
│   ├── .name
│   ├── encodings.xml
│   ├── expresshapinnes-official.iml
│   ├── misc.xml
│   ├── modules.xml
│   ├── scopes/
│   │   └── scope_settings.xml
│   ├── vcs.xml
│   └── workspace.xml
├── ErrorHandler.js
├── README.md
├── RESTcallsValidator.js
├── conf/
│   ├── conf.js
│   ├── errors.js
│   └── restConf.js
├── expressHappiness.js
├── fieldsLoader.js
├── helpers/
│   └── helpers.js
├── package.json
└── views/
    └── index.html
Condensed preview — 19 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (169K chars).
[
  {
    "path": ".idea/.name",
    "chars": 24,
    "preview": "expresshapinnes-official"
  },
  {
    "path": ".idea/encodings.xml",
    "chars": 164,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"Encoding\" useUTFGuessing=\"true\" native2A"
  },
  {
    "path": ".idea/expresshapinnes-official.iml",
    "chars": 281,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"WEB_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\">\n"
  },
  {
    "path": ".idea/misc.xml",
    "chars": 125,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"ProjectRootManager\" version=\"2\" />\n</pro"
  },
  {
    "path": ".idea/modules.xml",
    "chars": 300,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"ProjectModuleManager\">\n    <modules>\n   "
  },
  {
    "path": ".idea/scopes/scope_settings.xml",
    "chars": 139,
    "preview": "<component name=\"DependencyValidationManager\">\n  <state>\n    <option name=\"SKIP_IMPORT_STATEMENTS\" value=\"false\" />\n  </"
  },
  {
    "path": ".idea/vcs.xml",
    "chars": 164,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"VcsDirectoryMappings\">\n    <mapping dire"
  },
  {
    "path": ".idea/workspace.xml",
    "chars": 49328,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"ChangeListManager\">\n    <list default=\"t"
  },
  {
    "path": "ErrorHandler.js",
    "chars": 1192,
    "preview": "var ErrorHandler = function(logfileUrl){\n    var fs = require('fs');\n    var moment = require('moment');\n\n    this.handl"
  },
  {
    "path": "README.md",
    "chars": 44421,
    "preview": "Express Happiness\n=================\n\nIntro\n-----\nExpressHappiness is a rich framework for creating web apps and services"
  },
  {
    "path": "RESTcallsValidator.js",
    "chars": 13471,
    "preview": "var erH, reusableRequiredFields;\nvar validator = require('validator');\nvar moment = require('moment');\nvar restConf = {}"
  },
  {
    "path": "conf/conf.js",
    "chars": 855,
    "preview": "var path = require('path');\n\nexports.conf = {\n    errorLogFile: path.resolve(__dirname, '../') + '/logs/error.log',\n    "
  },
  {
    "path": "conf/errors.js",
    "chars": 366,
    "preview": "exports.errors = {\n    undefinedError:{\n        log:false,\n        humanReadable: 'Unresolved error code',\n        sendT"
  },
  {
    "path": "conf/restConf.js",
    "chars": 24545,
    "preview": "/*\nAll routes might belong to none, one or more groups.\nGrouping routes helps us apply middlewares targeting only specif"
  },
  {
    "path": "expressHappiness.js",
    "chars": 20251,
    "preview": "var restConf = {\n    routes:[]\n}\nvar kpis\n    ,rcv;\nvar fs = require('fs');\nvar colors = require('colors');\nvar flatSign"
  },
  {
    "path": "fieldsLoader.js",
    "chars": 1546,
    "preview": "module.exports = function(reusableFile){\n    var reusableRequiredFields = require(reusableFile);\n\n    /*\n     Returns th"
  },
  {
    "path": "helpers/helpers.js",
    "chars": 1321,
    "preview": "var validate = function(obj, func, callback) {\n    var index = 0;\n    var done = false;\n    var iterations = Object.keys"
  },
  {
    "path": "package.json",
    "chars": 576,
    "preview": "{\n  \"name\": \"express-happiness\",\n  \"version\": \"0.7.2\",\n  \"description\": \"Express framework wrapper\",\n  \"main\": \"expressH"
  },
  {
    "path": "views/index.html",
    "chars": 2496,
    "preview": "\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=e"
  }
]

About this extraction

This page contains the full source code of the andreas-trad/express-happiness GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 19 files (157.8 KB), approximately 35.2k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!