Merge branch 'graphs' of steve/monitor into master

master
Steve L. Nyemba 7 years ago committed by Gogs
commit 8d4f895bea

Binary file not shown.

1
.gitignore vendored

@ -1,2 +1,3 @@
sandbox sandbox
*.pyc *.pyc
.DS_Store

@ -0,0 +1,7 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="useProjectProfile" value="false" />
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 2.7.10 virtualenv at ~/Documents/Programming/monitor/sandbox" project-jdk-type="Python SDK" />
</project>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/monitor.iml" filepath="$PROJECT_DIR$/.idea/monitor.iml" />
</modules>
</component>
</project>

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TemplatesService">
<option name="TEMPLATE_CONFIGURATION" value="Jinja2" />
<option name="TEMPLATE_FOLDERS">
<list>
<option value="$MODULE_DIR$/src/api/templates" />
</list>
</option>
</component>
<component name="TestRunnerService">
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
</component>
</module>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

@ -0,0 +1,583 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="834735bc-31bd-474a-9b31-c9bb58743d7d" name="Default" comment="">
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/config.json" afterPath="$PROJECT_DIR$/config.json" />
</list>
<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="CreatePatchCommitExecutor">
<option name="PATCH_PATH" value="" />
</component>
<component name="ExecutionTargetManager" SELECTED_TARGET="default_target" />
<component name="FileEditorManager">
<splitter split-orientation="horizontal" split-proportion="0.54361874">
<split-first>
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
<file leaf-file-name="dashboard.html" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/src/api/templates/dashboard.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="213">
<caret line="65" column="5" lean-forward="true" selection-start-line="65" selection-start-column="5" selection-end-line="65" selection-end-column="5" />
<folding>
<element signature="e#2414#2713#0#HTML" expanded="false" />
</folding>
</state>
</provider>
</entry>
</file>
<file leaf-file-name="dashboard.js" pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/src/api/static/js/dashboard.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="226">
<caret line="26" column="0" lean-forward="true" selection-start-line="26" selection-start-column="0" selection-end-line="26" selection-end-column="0" />
<folding>
<marker date="1499136933000" expanded="true" signature="63:670" ph="{...}" />
<marker date="1499136933000" expanded="true" signature="638:670" ph="{...}" />
</folding>
</state>
</provider>
</entry>
</file>
</leaf>
</split-first>
<split-second>
<leaf>
<file leaf-file-name="index.py" pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/src/api/index.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="259">
<caret line="81" column="15" lean-forward="false" selection-start-line="81" selection-start-column="14" selection-end-line="81" selection-end-column="15" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="config.json" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/config.json">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="270">
<caret line="18" column="0" lean-forward="true" selection-start-line="18" selection-start-column="0" selection-end-line="18" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
</file>
</leaf>
</split-second>
</splitter>
</component>
<component name="FindInProjectRecents">
<findStrings>
<find>nodes</find>
<find>console.log</find>
</findStrings>
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="IdeDocumentHistory">
<option name="CHANGED_PATHS">
<list>
<option value="$PROJECT_DIR$/src/api/index.py" />
<option value="$PROJECT_DIR$/config.json" />
<option value="$PROJECT_DIR$/src/api/templates/dashboard.html" />
<option value="$PROJECT_DIR$/src/api/static/js/dashboard.js" />
</list>
</option>
</component>
<component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
<component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" />
<component name="JsGulpfileManager">
<detection-done>true</detection-done>
<sorting>DEFINITION_ORDER</sorting>
</component>
<component name="ProjectFrameBounds">
<option name="y" value="22" />
<option name="width" value="1280" />
<option name="height" value="774" />
</component>
<component name="ProjectView">
<navigator currentView="ProjectPane" proportions="" version="1">
<flattenPackages />
<showMembers />
<showModules />
<showLibraryContents />
<hideEmptyPackages />
<abbreviatePackageNames />
<autoscrollToSource />
<autoscrollFromSource />
<sortByType />
<manualOrder />
<foldersAlwaysOnTop value="true" />
</navigator>
<panes>
<pane id="ProjectPane">
<subPane>
<PATH>
<PATH_ELEMENT>
<option name="myItemId" value="monitor" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="monitor" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
</PATH>
<PATH>
<PATH_ELEMENT>
<option name="myItemId" value="monitor" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="monitor" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="src" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
</PATH>
<PATH>
<PATH_ELEMENT>
<option name="myItemId" value="monitor" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="monitor" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="src" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="api" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
</PATH>
<PATH>
<PATH_ELEMENT>
<option name="myItemId" value="monitor" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="monitor" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="src" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="api" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="templates" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
</PATH>
<PATH>
<PATH_ELEMENT>
<option name="myItemId" value="monitor" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="monitor" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="src" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="api" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="static" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="js" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
</PATH>
<PATH>
<PATH_ELEMENT>
<option name="myItemId" value="monitor" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="monitor" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="src" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="api" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="static" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
</PATH>
</subPane>
</pane>
<pane id="Scope" />
<pane id="Scratches" />
</panes>
</component>
<component name="PropertiesComponent">
<property name="WebServerToolWindowFactoryState" value="false" />
<property name="settings.editor.selected.configurable" value="vcs.Git" />
</component>
<component name="RunDashboard">
<option name="ruleStates">
<list>
<RuleState>
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
</RuleState>
<RuleState>
<option name="name" value="StatusDashboardGroupingRule" />
</RuleState>
</list>
</option>
</component>
<component name="RunManager">
<configuration default="true" type="BashConfigurationType" factoryName="Bash">
<option name="INTERPRETER_OPTIONS" value="" />
<option name="INTERPRETER_PATH" value="/bin/bash" />
<option name="WORKING_DIRECTORY" value="" />
<option name="PARENT_ENVS" value="true" />
<option name="SCRIPT_NAME" value="" />
<option name="PARAMETERS" value="" />
<module name="" />
<envs />
<method />
</configuration>
<configuration default="true" type="DjangoTestsConfigurationType" factoryName="Django tests">
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="" />
<option name="IS_MODULE_SDK" value="false" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<module name="monitor" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
<option name="TARGET" value="" />
<option name="SETTINGS_FILE" value="" />
<option name="CUSTOM_SETTINGS" value="false" />
<option name="USE_OPTIONS" value="false" />
<option name="OPTIONS" value="" />
<method />
</configuration>
<configuration default="true" type="JavaScriptTestRunnerJest" factoryName="Jest">
<node-interpreter value="project" />
<working-dir value="" />
<envs />
<scope-kind value="ALL" />
<method />
</configuration>
<configuration default="true" type="JavaScriptTestRunnerProtractor" factoryName="Protractor">
<config-file value="" />
<node-interpreter value="project" />
<envs />
<method />
</configuration>
<configuration default="true" type="JavascriptDebugType" factoryName="JavaScript Debug">
<method />
</configuration>
<configuration default="true" type="PyBehaveRunConfigurationType" factoryName="Behave">
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs />
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="" />
<option name="IS_MODULE_SDK" value="false" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<module name="monitor" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
<option name="ADDITIONAL_ARGS" value="" />
<method />
</configuration>
<configuration default="true" type="PyLettuceRunConfigurationType" factoryName="Lettuce">
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs />
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="" />
<option name="IS_MODULE_SDK" value="false" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<module name="monitor" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
<option name="ADDITIONAL_ARGS" value="" />
<method />
</configuration>
<configuration default="true" type="PythonConfigurationType" factoryName="Python">
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="" />
<option name="IS_MODULE_SDK" value="false" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<module name="monitor" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
<option name="SCRIPT_NAME" value="" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<method />
</configuration>
<configuration default="true" type="Tox" factoryName="Tox">
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs />
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="" />
<option name="IS_MODULE_SDK" value="false" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
<module name="monitor" />
<method />
</configuration>
<configuration default="true" type="js.build_tools.gulp" factoryName="Gulp.js">
<method />
</configuration>
<configuration default="true" type="js.build_tools.npm" factoryName="npm">
<command value="run" />
<scripts />
<node-interpreter value="project" />
<envs />
<method />
</configuration>
<configuration default="true" type="tests" factoryName="Doctests">
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs />
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="" />
<option name="IS_MODULE_SDK" value="false" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<module name="monitor" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
<option name="SCRIPT_NAME" value="" />
<option name="CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="FOLDER_NAME" value="" />
<option name="TEST_TYPE" value="TEST_SCRIPT" />
<option name="PATTERN" value="" />
<option name="USE_PATTERN" value="false" />
<method />
</configuration>
<configuration default="true" type="tests" factoryName="Unittests">
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs />
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="" />
<option name="IS_MODULE_SDK" value="false" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<module name="monitor" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
<option name="_new_additionalArguments" value="&quot;&quot;" />
<option name="_new_target" value="&quot;.&quot;" />
<option name="_new_targetType" value="&quot;PATH&quot;" />
<method />
</configuration>
</component>
<component name="ShelveChangesManager" show_recycled="false">
<option name="remove_strategy" value="false" />
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="834735bc-31bd-474a-9b31-c9bb58743d7d" name="Default" comment="" />
<created>1499042529793</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1499042529793</updated>
</task>
<servers />
</component>
<component name="ToolWindowManager">
<frame x="0" y="22" width="1280" height="774" extended-state="6" />
<editor active="true" />
<layout>
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" 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" show_stripe_button="true" weight="0.32991204" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Python Console" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.32991204" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.15347335" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
<window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32991204" 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" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Data View" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
</layout>
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="processedProjectFiles" value="true" />
</component>
<component name="VcsContentAnnotationSettings">
<option name="myLimit" value="2678400000" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager />
<watches-manager />
</component>
<component name="editorHistoryManager">
<entry file="file://$PROJECT_DIR$/src/api/index.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" 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$/src/api/templates/dashboard.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="855">
<caret line="57" column="17" lean-forward="false" selection-start-line="57" selection-start-column="16" selection-end-line="57" selection-end-column="17" />
<folding>
<element signature="e#2414#2713#0#HTML" expanded="false" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/config.json">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" 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$/start.sh">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="120">
<caret line="8" column="0" lean-forward="false" selection-start-line="8" selection-start-column="0" selection-end-line="8" selection-end-column="0" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/config.json">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" 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$/start.sh">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/config.json">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" 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$/start.sh">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/config.json">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" 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$/start.sh">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/start.sh">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="120">
<caret line="8" column="0" lean-forward="false" selection-start-line="8" selection-start-column="0" selection-end-line="8" selection-end-column="0" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/config.json">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="270">
<caret line="18" column="0" lean-forward="true" selection-start-line="18" selection-start-column="0" selection-end-line="18" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/src/api/index.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="259">
<caret line="81" column="15" lean-forward="false" selection-start-line="81" selection-start-column="14" selection-end-line="81" selection-end-column="15" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/src/api/templates/dashboard.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="213">
<caret line="65" column="5" lean-forward="true" selection-start-line="65" selection-start-column="5" selection-end-line="65" selection-end-column="5" />
<folding>
<element signature="e#2414#2713#0#HTML" expanded="false" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/src/api/static/js/dashboard.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="226">
<caret line="26" column="0" lean-forward="true" selection-start-line="26" selection-start-column="0" selection-end-line="26" selection-end-column="0" />
<folding>
<marker date="1499136933000" expanded="true" signature="63:670" ph="{...}" />
<marker date="1499136933000" expanded="true" signature="638:670" ph="{...}" />
</folding>
</state>
</provider>
</entry>
</component>
</project>

@ -1,10 +1,18 @@
{ {
"id":"lab", "id":"michaels-MBP",
"key":"4q-h8r5-247&!570p=[0v8]x360",
"api":"dev.the-phi.com",
"delay":10.0,
"store":{ "store":{
"class":{"read":"CouchdbReader","write":"CouchdbWriter"}, "class":{"read":"CouchdbReader","write":"CouchdbWriter"},
"args":{"uri":"http://dev.the-phi.com:5984","dbname":"mike-db","uid":"log_linode"} "args":{"uri":"http://dev.the-phi.com:5984","dbname":"mike-db","uid":"logs"}
}, },
"procs":["systemd", "rcu_sched"], "procs":["mail","safari", "chrome", "terminal"],
"folders":["~/monitor/monitor"], "folders":["/Users/michaelmead/Downloads"],
"delay":2 "actions":{
"folders":{"threshold":"10mb","action":"archive","key":""},
"apps":{"mail":"","safari":"","chrome":"" }
}
} }

@ -0,0 +1,15 @@
{
"virtual-env":{
"class":"Sandbox",
"config":{
"3-launchpad":{"requirements":"/Users/michaelmead/Documents/git/repair-file/required.txt","sandbox":"/Users/michaelmead/Documents/git/sandbox"}
}
},
"processes":{
"class":"DetailProcess",
"config":{
"system":["postgresql","couchdb","httpd"]
}
}
}

@ -0,0 +1,35 @@
{
"_id": "_design/summary",
"_rev": "29-38cc3d8e8351778b31ad280af5f517c7",
"language": "javascript",
"views": {
"app_resources": {
"map": "function(doc) {\n\tfor(id in doc){\n\t\tif(id.match(/^apps.+$/i) && doc[id].length > 0){\n\t\t\tindex = doc[id].length -1 \n\t\t\tvar logs = doc[id][index]\n\t\t\tfor(var i=0; i < logs.length; i++){\n\t\t\t\temit(doc._id,logs[i])\n\t\t\t}\n\t\t\t//emit(doc._id,doc[id][index][0])//doc[id][index])\n\t\t}\n\t}\n}",
"reduce": "function(keys,values){\n\tvar cpu = 0 ;\n\tvar mem_avail = 0 ;\n\tvar mem_used = 0\n\n\tfor(i in values){\n\t\trow = values[i]\n\t\tmem_avail \t= (mem_avail < row.memory_available)?row.memory_available:mem_avail\n\t\tmem_used \t+= (row.memory_available*row.memory_usage/100)\n\t\tcpu\t\t+= row.cpu_usage\n\t}\n\n\tif(mem_avail > 999 && mem_avail < 999999){\n\t\tunits=\"MB\"\n\t}else {\n\t\tunits=\"GB\"\n\t}\n\tmem_avail = parseFloat(mem_avail.toFixed(2))\n\tmem_used = parseFloat(mem_used.toFixed(2))\n\n\treturn {\"app_count\":values.length,\"memory_available\":mem_avail,\"memory_usage\":mem_used,\"cpu_usage\":cpu,\"units\":units}\n}"
},
"app_names": {
"map": "function(doc) {\n\tfor(id in doc){\n\t\tif(id.match(/^apps.+$/i) && doc[id].length > 0){\n\t\t\tindex = doc[id].length -1 \n\t\t\tvar size = doc[id].length\n\t\t\tvar offset = 25\n\t\t\t//\n\t\t\t// We get the last 25 rows ( a days worth of observations\n\t\t\t//\n\t\t\tvar rows = doc[id].slice(size-offset,size)\n\t\t\tfor(var i=0; i < rows.length; i++){\n\t\t\t\tfor(var j=0; j < rows[i].length; j++){\n\t\t\t\t\tvar info = {}\n\t\t\t\t\tinfo[id]=rows[i][j]\n\t\t\t\t\t\n\t\t\t\t\temit(doc._id,info)\t\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t}\n\t}\n}",
"reduce": "function(keys,values){\n\tvar m = {} ;\n\tvar r = {}\n\tfor (var i =0; i < values.length; i++){\n\t\tvar rows = values[i]\n\t\tfor (node in rows){\n\t\t\tvar log = rows[node]\n\t\t\tif(m[node] == null){\n\t\t\t\tm[node]={}\n\t\t\t\tr[node]=[]\n\t\t\t}\n\t\t\tvar app = log.label.toLowerCase()\n\t\t\tif(m[node][app] == null){\n\t\t\t\tm[node][app] = 1\n\t\t\t\tr[node].push(app)\n\t\t\t}\n\t\t}\n\t}\n\treturn r\n\t\n}"
},
"folder_size": {
"map": "function(doc) {\n\tfor(id in doc){\n\t\tif(id.match(/^folder.+/) && doc[id].length > 0){\n\t\t\tindex = doc[id].length -1 \n\t\t\tvar logs = doc[id][index]\n\t\t\tfor(var i=0; i < logs.length; i++){\n\t\t\t\temit(doc._id,logs[i])\n\t\t\t}\n\t\t}\n\t}\n}",
"reduce": "function(keys,values){\n\tvar size=0\n\tvar units = {\"MB\":1000,\"GB\":1000000,\"TB\":1000000000}\n\tfor(i in values){\n\t\trow = values[i]\n\t\tsvalue = row.size.match(/^[\\d,.]+/i)\n\t\tukey \t= row.size.match(/[a-z]+$/i)\n\t\tsize\t+= parseFloat(svalue*units[ukey])\n\t}\n\tif (size > 999 && size < 999999){\n\t\tunits=\"MB\"\n\t\tsize /=1000\n\t}else if(size > 999999 && 999999999){\n\t\tunits=\"GB\"\n\t\tsize /=1000000\n\t}else{ \n\t\tunits = \"TB\"\n\t\tsize /=1000000000\n\t}\n\tsize = parseFloat(size.toFixed(2))\n\treturn {\"folder_count\":values.length,\"size\":size,\"units\":units} //parseFloat(values[0].size.match(/^[\\d,.]+/))\n}"
},
"app_status": {
"map": "function(doc) {\n\tfor(id in doc){\n\t\tif(id.match(/^apps.+$/i) && doc[id].length > 0){\n\t\t\tindex = doc[id].length -1 \n\n\t\t\tif(doc[id][index].length > 0){\n\t\t\t\temit(doc._id,doc[id][index])\n\t\t\t}\n\t\t}\n\t}\n}",
"reduce": "function(keys,values){\n\tvar status = {\"crash\":0,\"idle\":0,\"running\":0}\n\tfor(i in values){\n\t\tfor(ii in values[i]){\n\t\t\trow = values[i][ii]\n\t\t\tid = row.status\n\t\t\tif(status[id] != null){\n\t\t\t\tstatus[id] += 1\n\t\t\t}\n\n\t\t}\n\t}\n\treturn status\n}"
},
"resource_usage_trend": {
"map": "function(doc) {\n\tfor(id in doc){\n\t\tif(id.match(/^apps.+$/i)){\n\t\t\tend = doc[id].length -1\n\t\t\tbeg = (doc[id].length > 25 )?doc[id].length - 25:0\n\t\t\tfor(var i = end; i > beg ; --i){\n\t\t\t\temit(doc._id,doc[id][i])//doc[id][index])\n\t\t\t}\n\t\t}\n\t}\n}",
"reduce": "function(keys,values){\n\tvar cpu = [] ;\n\tvar mem_avail = [] ;\n\tvar mem_used = []\n\tvar size = 20\n\tvar beg = null\n\tvar end = null\n\tapps = {}\n\tapp_count = 0\n\tfor(i in values){\n\t\t//end = values[i].length -1\n\t\t//beg = end - size\n\t\tfor(ii in values[i]){\n\t\t\trow = values[i][ii]\n\t\t\tapps[row.label] = 1\n\t\t\tif(beg == null){\n\t\t\t\tbeg = ([row.year,row.month,row.day]).join('/')+' ' +([row.hour,row.minute]).join(':')\n\t\t\t}\n\t\t\tmem_avail.push( parseFloat(row.memory_available.toFixed(2)))\n\t\t\tmem_used.push(row.memory_available*row.memory_usage/100)\n\t\t\tcpu.push(row.cpu_usage)\n\t\t\t\n\t\t}\n\t\tend = ([row.year,row.month,row.day]).join('/')+' ' +([row.hour,row.minute]).join(':')\n\t\n\t\t\n\t}\n\t//\n\t// counting applications found in the logs\n\t// There is no requirement on consistency of the logs\n\t//\n\tfor(i in apps){\n\t\tapp_count += 1\n\t}\n\t\n\t//return row\t//return values[0].slice(beg,end)\n\treturn {\"app_count\":app_count,\"beg\":beg,\"end\":end,\"memory_available\":mem_avail,\"memory_usage\":mem_used,\"cpu_usage\":cpu}\n}"
},
"app_status_details": {
"map": "function(doc) {\n\tfor(id in doc){\n\t\tif(id.match(/^apps.+$/i)){\n\t\t\tindex = doc[id].length -1 \n\t\t\tbeg = (doc[id].length > 0)?doc[id].length -25 : 0\n\t\t\tvar logs = doc[id].slice(beg,index);//[index]\n\n\t\t\tfor(var i=0; i < logs.length; i++){\n\t\t\t\tvar rec = logs[i]\n\t\t\t\tfor (ii in rec){\n\t\t\t\t\tr = {}\n\t\t\t\t\tr[id] = rec[ii]\n\t\t\t\t\temit(doc._id,r)\n\t\t\t\t}\n\t\t\t}\n\t\t\t//emit(doc._id,doc[id][index][0])//doc[id][index])\n\t\t}\n\t}\n}",
"reduce": "function(keys,values){\n\tvar cpu = 0 ;\n\tvar mem_avail = 0 ;\n\tvar mem_used = 0\n\tr = {}\n\t//\n\t// retrieving the memory available\n\n\tfor(i in values){\n\t\trow = values[i]\n\t\tfor(id in row){\n\t\t\tmem_avail = (mem_avail < row[id].memory_available)?row[id].memory_available:mem_avail \n\t\t}\n\t}\n\t//\n\t// Determining appropriate units of measurement\n\t//\n\t\t\n\tif(mem_avail > 999 && mem_avail < 999999){\n\t\tunits=\"MB\"\n\t}else {\n\t\tunits=\"GB\"\n\t}\n\n\n\tfor(i in values){\n\n\t\trec = values[i]\n\t\tfor(key in rec){\n\t\t\trow = rec[key]\n\t\t\tvar id = row.label\n\t\t\tif(r[key] == null){ r[key] = {} }\n\t\t\tif (r[key][id] == null){\n\t\t\t\tr[key][id] = {\"beg\":null,\"end\":null,\"crash\":0,\"idle\":0,\"running\":0}\n\t\t\t}\n\t\t\tr[key][id][row.status] += 1\n\t\t\tif(r[key][id].beg == null){\n\t\t\t\tr[key][id].beg = ([row.year,row.month,row.day]).join('/')+' '+([row.hour,row.minute]).join(':')\n\t\t\t}\n\t\t\tr[key][id].end = ([row.year,row.month,row.day]).join('/')+' '+([row.hour,row.minute]).join(':')\n\t\t}\n\t}\n\n\n\t//mem_avail = parseFloat(mem_avail.toFixed(2))\n\t//mem_used = parseFloat(mem_used.toFixed(2))\n\n\treturn r //{\"app_count\":values.length,\"memory_available\":mem_avail,\"memory_usage\":mem_used,\"cpu_usage\":cpu,\"units\":units}\n}"
},
"app_resource_usage_details": {
"map": "function(doc) {\n\tfor(id in doc){\n\t\tif(id.match(/^apps.+$/i)){\n\t\t\tindex = doc[id].length -1 \n\t\t\tbeg = (doc[id].length > 25)?doc[id].length -25 :0\n\t\t\tvar logs = doc[id].slice(beg,index);//[index]\n\n\t\t\tfor(var i=0; i < logs.length; i++){\n\t\t\t\tvar rec = logs[i]\n\t\t\t\tfor (ii in rec){\n\t\t\t\t\tvar info = {}\n\t\t\t\t\tinfo[id] = rec[ii]\n\t\t\t\t\temit(doc._id,info)//rec[ii])\n\t\t\t\t}\n\t\t\t}\n\t\t\t//emit(doc._id,doc[id][index][0])//doc[id][index])\n\t\t}\n\t}\n}",
"reduce": "function(keys,values){\n\tvar cpu = 0 ;\n\tvar mem_avail = 0 ;\n\tvar mem_used = 0\n\tr = {}\n\t//\n\t// retrieving the memory available\n\tfor(i in values){\n\t\tvar rvalues = values[i]\n\t\tfor(id in rvalues){\n\t\t\trow = rvalues[id]\n\t\t\tmem_avail = parseFloat(row.memory_available) ;//mem_avail < row.memory_available)?row.memory_available:mem_avail \n\t\t\tapp_id = row.label.toLowerCase()\n\t\t\tif(r[id] == null){\n\t\t\t\t\n\t\t\t\tr[id] = {}\n\t\t\t}\n\t\t\tif(r[id][app_id] == null){\n\t\t\t\tr[id][app_id] = {memory_available:0,cpu:[],memory_used:[],dates:[]}\n\t\t\t}\n\n\t\t\tr[id][app_id].memory_available += mem_avail\n\t\t\t//app_id = row.label.toLowerCase()\n\n\t\t\tif(mem_avail > 999 && mem_avail < 999999){\n\t\t\t\tunits=\"MB\"\n\t\t\t\t\n\t\t\t}else {\n\t\t\t\tunits=\"GB\"\n\t\t\t}\t\n\t\t\tr[id][app_id].units = units\n\t\t}\n\t\tfor(var id in rvalues){\n\t\t\trow = rvalues[id]\n\t\t\tapp_id = row.label.toLowerCase()\n\t\t\tif(r[id][app_id].units == 'MB'){\n\t\t\t\tr[id][app_id].memory_available = parseFloat((r[id][app_id].memory_available/ 1000).toFixed(2))\n\t\t\t}else{\n\t\t\t\t//\n\t\t\t\t// assuming we have GB\n\t\t\t\tr[id][app_id].memory_available = parseFloat((r[id][app_id].memory_available/ 1000000).toFixed(2))\n\t\t\t}\n\t\t\tdate = new Date(row.year,row.month,row.day,row.hour,row.minute)\n\t\t\tdate = ([row.hour,row.minute]).join('H:')//{month:row.month,year:row.year,day:row.day,hour:row.hour,minute:row.minute}\n\t\t\tr[id][app_id].dates.push(date)\t\t\t\t\t\n\t\t\t//r[id][app_id].end = \t([row.year,row.month,row.day]).join('/')+' '+([row.hour,row.minute]).join(':')\n\t\t\tmem_avail = r[id][app_id].memory_available == 0?1:r[id][app_id].memory_available\n\t\t\tr[id][app_id].memory_used.push(parseFloat((mem_avail*row.memory_usage).toFixed(2)))\n\t\t\tr[id][app_id].cpu.push(row.cpu_usage)\n\t\t\t\n\t\t\t\n\t\t}\n\t\t\n\t}\n\treturn r\n}"
}
}
}

@ -0,0 +1,67 @@
#!/bin/bash
#
# This script is designed to handle various operations related to setting up, starting, stopping the python application
# It will assume the requirements file is at the root (not with the source code)
#
export PYTHONPATH=$PWD/src
pip_upgrade='sandbox/bin/pip freeze|sort |diff requirements.txt -|grep \<|grep -E " .+$" -o'
install(){
virtualenv sandbox
sandbox/bin/pip install -r requirements.txt
`sandbox/bin/pip freeze|sort |diff requirements.txt -|grep \<|grep -E " .+$" -o|sandbox/bin/pip install --upgrade`
}
upgrade(){
git pull
count=`sandbox/bin/pip freeze|sort |diff requirements.txt -|grep \<|grep -E " .+$" -o|wc -l`
if [ ! "$count" = "0" ]; then
`sandbox/bin/pip freeze|sort |diff requirements.txt -|grep \<|grep -E " .+$" -o|sandbox/bin/pip install --upgrade`
else
echo "No Upgrade required for sandbox"
fi
}
start(){
if [ "$1" = "collector" ]; then
sandbox/bin/python src/utils/agents/data-collector.py --path $PWD/config.json
else
sandbox/bin/python src/api/index.py --path $PWD/config.json &
fi
}
stop(){
ps -eo pid,command|grep python|grep -E "$PWD"|grep index.py|grep -E "^ {0,}[0-9]+" -o |xargs kill -9
ps -eo pid,command|grep python|grep -E "$PWD"|grep data-collector|grep -E "^ {0,}[0-9]+" -o |xargs kill -9
}
status(){
pid=`ps -eo pid,command|grep python|grep -E "$PWD"|grep index.py|grep -E "^ {0,}[0-9]+" -m 1 -o`
if [ "$pid" = "" ]; then
echo "API IS OFFLINE"
else
echo "API IS ONLINE $pid"
fi
pid=`ps -eo pid,command|grep python|grep -E "$PWD"|grep data-collector|grep -E "^ {0,}[0-9]+" -m 1 -o`
if [ "$pid" = "" ]; then
echo "DATA-COLLECTOR IS OFFLINE"
else
echo "DATA-COLLECTOR IS ONLINE $pid"
fi
}
if [ "$1" = "start" ]; then
if [ "$2" = "collector" ]; then
start "collector"
else
start
fi
else
$1
fi

@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
git clone https://github.com/lnyemba/jx src/api/static/js/jx git clone https://github.com/lnyemba/jx src/api/static/js/jx
virtualenv sandbox virtualenv sandbox --python=python2.7
source sandbox/bin/activate source sandbox/bin/activate
pip install -r requirements.txt pip install -r requirements.txt
export PYTHONPATH=$PWD/src export PYTHONPATH=$PWD/src

@ -6,6 +6,20 @@ The program answers basic questions:
- Is a given program still running - Is a given program still running
- How much resource (memory/cpu) a program is using up - How much resource (memory/cpu) a program is using up
- The number of processes found - The number of processes found
- Folder monitoring ...
#Architecture
The architecture of the system is distributed with a central master node,
{
"id":"",
"key":"",
"apps":[],
"sandbox":[{"path":"","requirements":""}],
"folders":["path-1"],
"store":{}
"actions":{}
}
The agent will perform three basic functions : The agent will perform three basic functions :

@ -1,13 +1,16 @@
aniso8601==1.2.0
click==6.6
couchdbkit==0.6.5
Flask==0.11.1 Flask==0.11.1
Flask-Session==0.3.0 Flask-Session==0.3.0
Flask-SocketIO==2.8.2 Flask-SocketIO==2.8.2
http-parser==0.8.3
itsdangerous==0.24
Jinja2==2.8 Jinja2==2.8
MarkupSafe==0.23 MarkupSafe==0.23
Werkzeug==0.11.11
aniso8601==1.2.0
argparse==1.2.1
click==6.6
couchdbkit==0.6.5
http-parser==0.8.3
itsdangerous==0.24
ngram==3.3.0
numpy==1.11.3 numpy==1.11.3
pika==0.10.0 pika==0.10.0
python-dateutil==2.6.0 python-dateutil==2.6.0
@ -17,4 +20,4 @@ pytz==2016.10
restkit==4.2.2 restkit==4.2.2
six==1.10.0 six==1.10.0
socketpool==0.5.3 socketpool==0.5.3
Werkzeug==0.11.11 wsgiref==0.1.2

Binary file not shown.

@ -1,13 +1,16 @@
""" """
This is a RESTful interface implemented using Flask micro framework. This is a RESTful interface implemented using Flask micro framework.
The API is driven by configuration that is organized in terms of the monitoring classes The API is driven by configuration that is organized in terms of the monitoring classes
The API is both restful and websocket/socketio enabled. The API is both restful and websocket/socketio enabled.
We designed the classes to be reusable (and powered by labels): We designed the classes to be reusable (and powered by labels):
'monitoring-type': 'monitoring-type':
'class':'<class-name>' 'class':'<class-name>'
'config':<labeled-class-specific-configuration>' 'config':<labeled-class-specific-configuration>'
@TODO:
- In order to make this Saas we need to have the configuration be session driven
- Add socketio, so that each section of the dashboard updates independently
""" """
from flask import Flask, session, request, redirect, Response from flask import Flask, session, request, redirect, Response
@ -45,51 +48,180 @@ class_write= CONFIG['store']['class']['write']
factory = DataSourceFactory() factory = DataSourceFactory()
# gReader = factory.instance(type=class_read,args=p) # gReader = factory.instance(type=class_read,args=p)
atexit.register(ThreadManager.stop) @app.route('/')
@app.route('/get/<id>') def home():
def procs(id): context = PARAMS['context']
if 'title' in PARAMS :
title = PARAMS['title']
else:
title = 'Dashboard'
apps = []
try: try:
gReader = factory.instance(type=class_read,args=p) gReader = factory.instance(type=class_read,args=p)
data = gReader.read() apps = gReader.view('summary/nodes',key=p['uid'])
ahandler = AnalyzeAnomaly()
learn = {}
if 'learn' in data :
for row in data['learn'] :
label = row['label']
learn[label] = row
r = {}
for label in data :
if label not in ['learn','folders'] :
index = len(data[label]) - 1
row = data[label][index]
r[label] = row
#
# Let us determine if this is a normal operation or not
# We will update the status of the information ...
#
for row in r[label] :
index = r[label].index(row)
if row['label'] in learn:
id = row['label']
px = ahandler.predict([row],learn[id])
if px :
# row['anomaly'] = px[1]==1
print ""
print label,' *** ',index
row = dict(row,**px)
r[label][index] =row
#
# @TODO:
# Compile a report here that will be sent to the mailing list
#
except Exception, e: except Exception, e:
print (e)
return render_template('dashboard.html',context=context,title=title,app_names=apps)
@app.route('/1/get/nodes')
def get_nodes():
"""
This function returns the labels of applications for every node registered
@param None
"""
r = []
try:
gReader = factory.instance(type=class_read,args=p)
r = gReader.view('summary/nodes',key=p['uid'])
except Exception,e:
print (e)
return json.dumps(r)
@app.route('/1/get/apps')
def get_apps():
"""
This function returns the applications for a given node
@param node identifier e.g: apps@zulu.org <--------------------no it doesnt
"""
r = []
try:
node_id = request.args.get('node')
gReader = factory.instance(type=class_read,args=p)
r = gReader.view('summary/app_names',key=p['uid'])
r = r[node_id]
print r
except Exception,e:
print (e)
return json.dumps(r)
@app.route('/1/get/summary/<id>')
def get_summary(id):
"""
This function returns the summary i.e an overall assessment of resource usage
It will pull information out of the user's data-store (database & document) specified in the configuration
@param id {app_resources|app_status|folder_size}
"""
r = []
try:
gReader = factory.instance(type=class_read,args=p)
#if id == 'apps_resources' :
# r = gReader.view('summary/app_resources',key=p['uid'])
#else:
# r = gReader.view('summary/folder_size',key=p['uid'])
id='summary/'+id.strip()
print p
print id
r = gReader.view(id,key=p['uid'])
except Exception,e:
print (e)
return json.dumps(r)
@app.route("/1/sys/usage/trend")
def get_usage_trend():
"""
This function returns cpu/memory usage for the entire system being monitored. It will return the 24 most recent observations in the logs
@param None
@return {memory_usage:[],cpu_usage:[],app_count:value,memory_available:[]}
"""
r = {}
try:
gReader = factory.instance(type=class_read,args=p)
r = gReader.view('summary/resource_usage_trend',key=p['uid'])
except Exception,e:
print (e)
return json.dumps(r)
@app.route("/1/app/usage/trend")
def get_usage_detail():
"""
This function returns detailed information about usage per application monitored. It will return the 24 most recent observations in the logs
@param node node identifier e.g: apps@zulu.io
@return {node_x:{app_1:{memory_usage:[],cpu_usage:[]}},...}
"""
r = {}
try:
id = request.args.get('node')
app_id = request.args.get('app')
gReader = factory.instance(type=class_read,args=p)
r = gReader.view('summary/app_resource_usage_details',key=p['uid'])
r = r[id][app_id]
except Exception,e:
print (e)
return json.dumps(r)
@app.route('/1/app/status')
def app_status() :
"""
This function aggregates the number of crashes/running/idle instances found in the past 24 log entries
for a particular application
@param nid node identifier e.g: app@zulu.io
@param app application identifier e.g: kate, firefox, chrome ... specified in the configuraiton
"""
r = []
try:
nid = request.args.get('node') # Node identifier
aid = request.args.get('app') # application identifier
gReader = factory.instance(type=class_read,args=p)
r = gReader.view('summary/app_status_details',key=p['uid'])
#
#@TODO: Once the back-end enables the nodes in which the application is running, uncomment the line below
#
print[nid,aid]
r = r[nid][aid]
except Exception,e:
print e print e
r = []
return json.dumps(r) return json.dumps(r)
#@app.route('/get/<id>')
#def procs(id):
#try:
#gReader = factory.instance(type=class_read,args=p)
#data = gReader.read()
#ahandler = AnalyzeAnomaly()
#learn = {}
#if 'learn' in data :
#for row in data['learn'] :
#label = row['label']
#learn[label] = row
#r = {}
#for label in data :
#if label not in ['learn','folders'] :
#index = len(data[label]) - 1
#row = data[label][index]
#r[label] = row
##
## Let us determine if this is a normal operation or not
## We will update the status of the information ...
##
#for row in r[label] :
#index = r[label].index(row)
#if row['label'] in learn:
#id = row['label']
#px = ahandler.predict([row],learn[id])
#if px :
## row['anomaly'] = px[1]==1
#print ""
#print label,' *** ',index
#row = dict(row,**px)
#r[label][index] =row
##
## @TODO:
## Compile a report here that will be sent to the mailing list
##
#except Exception, e:
#print e
#r = []
#return json.dumps(r)
""" """
This function/endpoint will assess n-virtual environments and return the results This function/endpoint will assess n-virtual environments and return the results
@ -98,7 +230,7 @@ def procs(id):
@app.route('/sandbox') @app.route('/sandbox')
def sandbox(): def sandbox():
global CONFIG global CONFIG
if 'sandbox' in CONFIG: #CONFIG['monitor']: if 'sandbox' in CONFIG: #CONFIG['monitor']:
#handler = HANDLERS['sandbox']['class'] #handler = HANDLERS['sandbox']['class']
#conf = HANDLERS['sandbox']['config'] #conf = HANDLERS['sandbox']['config']
@ -106,7 +238,7 @@ def sandbox():
# p = Factory.instance('sandbox',CONFIG) # p = Factory.instance('sandbox',CONFIG)
handler = monitor.Sandbox() handler = monitor.Sandbox()
conf = CONFIG['sandbox'] conf = CONFIG['sandbox']
for id in conf: for id in conf:
try: try:
handler.init(conf[id]) handler.init(conf[id])
@ -114,182 +246,207 @@ def sandbox():
except Exception,e: except Exception,e:
pass pass
else: else:
r = [] r = []
return json.dumps(r) return json.dumps(r)
@app.route('/trends') #@app.route('/trends')
def trends (): #def trends ():
id = request.args.get('id') #id = request.args.get('id')
app = request.args.get('app').strip() #app = request.args.get('app').strip()
p = CONFIG['store']['args'] #p = CONFIG['store']['args']
class_read = CONFIG['store']['class']['read'] #class_read = CONFIG['store']['class']['read']
gReader = factory.instance(type=class_read,args=p) #gReader = factory.instance(type=class_read,args=p)
r = gReader.read() #r = gReader.read()
if id in r: #if id in r:
r = r[id] #--matrix #r = r[id] #--matrix
series = [] #series = []
for row in r: #for row in r:
series += [item for item in row if str(item['label'])== app] #series += [item for item in row if str(item['label'])== app]
if len(series) > 12 : #if len(series) > 12 :
beg = len(series) - 13 #beg = len(series) - 8
series = series[beg:] #series = series[beg:]
return json.dumps(series) #return json.dumps(series)
else: #else:
return "[]" #return "[]"
@app.route('/download',methods=['POST']) #@app.route('/download',methods=['POST'])
def requirements(): #def requirements():
stream = request.form['missing'] #stream = request.form['missing']
print stream #print stream
stream = "\n".join(json.loads(stream)) #stream = "\n".join(json.loads(stream))
headers = {"content-disposition":"attachment; filename=requirements.txt"} #headers = {"content-disposition":"attachment; filename=requirements.txt"}
return Response(stream,mimetype='text/plain',headers=headers) #return Response(stream,mimetype='text/plain',headers=headers)
@app.route('/dashboard') @app.route('/dashboard')
def dashboard(): def dashboard():
context = PARAMS['context'] context = PARAMS['context']
if 'title' in PARAMS : if 'title' in PARAMS :
title = PARAMS['title'] title = PARAMS['title']
else: else:
title = 'Zulu OverWatch' title = 'Dashboard'
return render_template('dashboard.html',context=context,title=title) apps = []
try:
gReader = factory.instance(type=class_read,args=p)
apps = gReader.view('summary/app_names',key=p['uid'])
except Exception, e:
print (e)
return render_template('dashboard.html',context=context,title=title,app_names=apps)
@app.route('/upgrade')
def upgrade():
context = PARAMS['context']
if 'title' in PARAMS :
title = PARAMS['title']
else:
title = 'Upgrade'
return render_template('upgrade.html',context=context,title=title)
@app.route('/user')
def user():
context = PARAMS['context']
if 'title' in PARAMS :
title = PARAMS['title']
else:
title = 'Upgrade'
return render_template('user.html',context=context,title=title)
#"""
#This function is designed to trigger learning for anomaly detection
#@TODO: forward this to a socket i.e non-blocking socket
#"""
#@app.route('/anomalies/get')
#def learn():
#global CONFIG
#p = CONFIG['store']['args']
#class_read = CONFIG['store']['class']['read']
#gReader = factory.instance(type=class_read,args=p)
#d = gReader.read()
#if 'learn' in d :
#info = d['learn']
#del d['learn']
#else :
#info = []
#r = []
#if 'id' in request.args:
#id = request.args['id']
#d = d[id]
#params = {}
#for item in info:
#label = item['label']
#params[label] = item
##apps = list(set(ML.Extract(['label'],d)))
#r = []
#if params :
##
## If we have parameters available
#p = AnomalyDetection()
#apps = params.keys()
#for name in apps :
#if name not in params:
#continue
#_info = params[name]
#try:
#xo = ML.Filter('label',name,d)
#except Exception,e:
#xo = []
##print name,e
#if len(xo) == 0:
#continue
#xo = [xo[ len(xo) -1]]
#value = p.predict(xo,_info)[0]
#if len(value):
#report = dict(_info,**{'predicton':value})
#r.append(report)
##print app,value
##if value is not None:
## r.append(value)
#return json.dumps(r)
"""
This function is designed to trigger learning for anomaly detection
@TODO: forward this to a socket i.e non-blocking socket
"""
@app.route('/anomalies/get')
def learn():
global CONFIG
p = CONFIG['store']['args']
class_read = CONFIG['store']['class']['read']
gReader = factory.instance(type=class_read,args=p)
d = gReader.read()
if 'learn' in d :
info = d['learn']
del d['learn']
else :
info = []
r = []
if 'id' in request.args:
id = request.args['id']
d = d[id]
params = {}
for item in info:
label = item['label']
params[label] = item
#apps = list(set(ML.Extract(['label'],d)))
r = []
if params :
#
# If we have parameters available
p = AnomalyDetection()
apps = params.keys()
for name in apps :
if name not in params:
continue
_info = params[name]
try:
xo = ML.Filter('label',name,d)
except Exception,e:
xo = []
#print name,e
if len(xo) == 0:
continue
xo = [xo[ len(xo) -1]]
value = p.predict(xo,_info)[0]
if len(value):
report = dict(_info,**{'predicton':value})
r.append(report)
#print app,value
#if value is not None:
# r.append(value)
return json.dumps(r)
""" """
This function returns anomalies for a given context or group of processes This function returns anomalies for a given context or group of processes
The information returned is around precision/recall and f-score and parameters The information returned is around precision/recall and f-score and parameters
""" """
@app.route('/anomalies/status') #@app.route('/anomalies/status')
def anomalies_status(): #def anomalies_status():
global CONFIG #global CONFIG
p = CONFIG['store']['args'] #p = CONFIG['store']['args']
class_read = CONFIG['store']['class']['read'] #class_read = CONFIG['store']['class']['read']
gReader = factory.instance(type=class_read,args=p) #gReader = factory.instance(type=class_read,args=p)
d = gReader.read() #d = gReader.read()
if 'learn' in d : #if 'learn' in d :
info = d['learn'] #info = d['learn']
del d['learn'] #del d['learn']
else : #else :
info = [] #info = []
print info #print info
r = [] #r = []
if 'id' in request.args: #if 'id' in request.args:
id = request.args['id'] #id = request.args['id']
r = info #r = info
return json.dumps(r) #return json.dumps(r)
@app.route('/folders') #@app.route('/folders')
def get_folders(): #def get_folders():
global CONFIG #global CONFIG
p = CONFIG['store']['args'] #p = CONFIG['store']['args']
class_read = CONFIG['store']['class']['read'] #class_read = CONFIG['store']['class']['read']
gReader = factory.instance(type=class_read,args=p) #gReader = factory.instance(type=class_read,args=p)
d = gReader.read() #d = gReader.read()
if 'folders' in d: #if 'folders' in d:
d = d['folders'] #d = d['folders']
hosts = set([row[0]['id'] for row in d]) #hosts = set([row[0]['id'] for row in d])
m = {} #m = {}
for id in hosts: #for id in hosts:
for row in d: #for row in d:
if id == row[0]['id'] : #if id == row[0]['id'] :
m[id] = row #m[id] = row
d = m.values() #d = m.values()
for row in d: #for row in d:
print row[0]['id'] #print row[0]['id']
# index = len(d) - 1 ## index = len(d) - 1
# d = d[index] ## d = d[index]
# m = {} ## m = {}
# for row in d : ## for row in d :
# key = row.keys()[0] ## key = row.keys()[0]
# row = row[key] ## row = row[key]
# if key not in m: ## if key not in m:
# r.append(row) ## r.append(row)
# m[key] = len(r) -1 ## m[key] = len(r) -1
# else: ## else:
# index = m[key] ## index = m[key]
# r[index] = row ## r[index] = row
# d = r ## d = r
else: #else:
d = [] #d = []
return json.dumps(d) #return json.dumps(d)
if __name__== '__main__': if __name__== '__main__':
# ThreadManager.start(CONFIG) # ThreadManager.start(CONFIG)
if 'port' not in SYS_ARGS.PARAMS : if 'port' not in SYS_ARGS.PARAMS :
SYS_ARGS.PARAMS['port'] = 5000 SYS_ARGS.PARAMS['port'] = 8484
PORT = int(SYS_ARGS.PARAMS['port']) PORT = int(SYS_ARGS.PARAMS['port'])
app.run(host='0.0.0.0' ,port=PORT,debug=True,threaded=True) app.run(host='0.0.0.0' ,port=PORT,debug=True,threaded=True)

@ -0,0 +1,615 @@
.ct-label {
fill: rgba(0, 0, 0, 0.4);
color: rgba(0, 0, 0, 0.4);
font-size: 0.75rem;
line-height: 1; }
.ct-chart-line .ct-label,
.ct-chart-bar .ct-label {
display: block;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex; }
.ct-chart-pie .ct-label,
.ct-chart-donut .ct-label {
dominant-baseline: central; }
.ct-label.ct-horizontal.ct-start {
-webkit-box-align: flex-end;
-webkit-align-items: flex-end;
-ms-flex-align: flex-end;
align-items: flex-end;
-webkit-box-pack: flex-start;
-webkit-justify-content: flex-start;
-ms-flex-pack: flex-start;
justify-content: flex-start;
text-align: left;
text-anchor: start; }
.ct-label.ct-horizontal.ct-end {
-webkit-box-align: flex-start;
-webkit-align-items: flex-start;
-ms-flex-align: flex-start;
align-items: flex-start;
-webkit-box-pack: flex-start;
-webkit-justify-content: flex-start;
-ms-flex-pack: flex-start;
justify-content: flex-start;
text-align: left;
text-anchor: start; }
.ct-label.ct-vertical.ct-start {
-webkit-box-align: flex-end;
-webkit-align-items: flex-end;
-ms-flex-align: flex-end;
align-items: flex-end;
-webkit-box-pack: flex-end;
-webkit-justify-content: flex-end;
-ms-flex-pack: flex-end;
justify-content: flex-end;
text-align: right;
text-anchor: end; }
.ct-label.ct-vertical.ct-end {
-webkit-box-align: flex-end;
-webkit-align-items: flex-end;
-ms-flex-align: flex-end;
align-items: flex-end;
-webkit-box-pack: flex-start;
-webkit-justify-content: flex-start;
-ms-flex-pack: flex-start;
justify-content: flex-start;
text-align: left;
text-anchor: start; }
.ct-chart-bar .ct-label.ct-horizontal.ct-start {
-webkit-box-align: flex-end;
-webkit-align-items: flex-end;
-ms-flex-align: flex-end;
align-items: flex-end;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
text-align: center;
text-anchor: start; }
.ct-chart-bar .ct-label.ct-horizontal.ct-end {
-webkit-box-align: flex-start;
-webkit-align-items: flex-start;
-ms-flex-align: flex-start;
align-items: flex-start;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
text-align: center;
text-anchor: start; }
.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-start {
-webkit-box-align: flex-end;
-webkit-align-items: flex-end;
-ms-flex-align: flex-end;
align-items: flex-end;
-webkit-box-pack: flex-start;
-webkit-justify-content: flex-start;
-ms-flex-pack: flex-start;
justify-content: flex-start;
text-align: left;
text-anchor: start; }
.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-end {
-webkit-box-align: flex-start;
-webkit-align-items: flex-start;
-ms-flex-align: flex-start;
align-items: flex-start;
-webkit-box-pack: flex-start;
-webkit-justify-content: flex-start;
-ms-flex-pack: flex-start;
justify-content: flex-start;
text-align: left;
text-anchor: start; }
.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-start {
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: flex-end;
-webkit-justify-content: flex-end;
-ms-flex-pack: flex-end;
justify-content: flex-end;
text-align: right;
text-anchor: end; }
.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-end {
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: flex-start;
-webkit-justify-content: flex-start;
-ms-flex-pack: flex-start;
justify-content: flex-start;
text-align: left;
text-anchor: end; }
.ct-grid {
stroke: rgba(0, 0, 0, 0.2);
stroke-width: 1px;
stroke-dasharray: 2px; }
.ct-grid-background {
fill: none; }
.ct-point {
stroke-width: 10px;
stroke-linecap: round; }
.ct-line {
fill: none;
stroke-width: 4px; }
.ct-area {
stroke: none;
fill-opacity: 0.1; }
.ct-bar {
fill: none;
stroke-width: 10px; }
.ct-slice-donut {
fill: none;
stroke-width: 60px; }
.ct-series-a .ct-point, .ct-series-a .ct-line, .ct-series-a .ct-bar, .ct-series-a .ct-slice-donut {
stroke: #d70206; }
.ct-series-a .ct-slice-pie, .ct-series-a .ct-slice-donut-solid, .ct-series-a .ct-area {
fill: #d70206; }
.ct-series-b .ct-point, .ct-series-b .ct-line, .ct-series-b .ct-bar, .ct-series-b .ct-slice-donut {
stroke: #f05b4f; }
.ct-series-b .ct-slice-pie, .ct-series-b .ct-slice-donut-solid, .ct-series-b .ct-area {
fill: #f05b4f; }
.ct-series-c .ct-point, .ct-series-c .ct-line, .ct-series-c .ct-bar, .ct-series-c .ct-slice-donut {
stroke: #f4c63d; }
.ct-series-c .ct-slice-pie, .ct-series-c .ct-slice-donut-solid, .ct-series-c .ct-area {
fill: #f4c63d; }
.ct-series-d .ct-point, .ct-series-d .ct-line, .ct-series-d .ct-bar, .ct-series-d .ct-slice-donut {
stroke: #d17905; }
.ct-series-d .ct-slice-pie, .ct-series-d .ct-slice-donut-solid, .ct-series-d .ct-area {
fill: #d17905; }
.ct-series-e .ct-point, .ct-series-e .ct-line, .ct-series-e .ct-bar, .ct-series-e .ct-slice-donut {
stroke: #453d3f; }
.ct-series-e .ct-slice-pie, .ct-series-e .ct-slice-donut-solid, .ct-series-e .ct-area {
fill: #453d3f; }
.ct-series-f .ct-point, .ct-series-f .ct-line, .ct-series-f .ct-bar, .ct-series-f .ct-slice-donut {
stroke: #59922b; }
.ct-series-f .ct-slice-pie, .ct-series-f .ct-slice-donut-solid, .ct-series-f .ct-area {
fill: #59922b; }
.ct-series-g .ct-point, .ct-series-g .ct-line, .ct-series-g .ct-bar, .ct-series-g .ct-slice-donut {
stroke: #0544d3; }
.ct-series-g .ct-slice-pie, .ct-series-g .ct-slice-donut-solid, .ct-series-g .ct-area {
fill: #0544d3; }
.ct-series-h .ct-point, .ct-series-h .ct-line, .ct-series-h .ct-bar, .ct-series-h .ct-slice-donut {
stroke: #6b0392; }
.ct-series-h .ct-slice-pie, .ct-series-h .ct-slice-donut-solid, .ct-series-h .ct-area {
fill: #6b0392; }
.ct-series-i .ct-point, .ct-series-i .ct-line, .ct-series-i .ct-bar, .ct-series-i .ct-slice-donut {
stroke: #f05b4f; }
.ct-series-i .ct-slice-pie, .ct-series-i .ct-slice-donut-solid, .ct-series-i .ct-area {
fill: #f05b4f; }
.ct-series-j .ct-point, .ct-series-j .ct-line, .ct-series-j .ct-bar, .ct-series-j .ct-slice-donut {
stroke: #dda458; }
.ct-series-j .ct-slice-pie, .ct-series-j .ct-slice-donut-solid, .ct-series-j .ct-area {
fill: #dda458; }
.ct-series-k .ct-point, .ct-series-k .ct-line, .ct-series-k .ct-bar, .ct-series-k .ct-slice-donut {
stroke: #eacf7d; }
.ct-series-k .ct-slice-pie, .ct-series-k .ct-slice-donut-solid, .ct-series-k .ct-area {
fill: #eacf7d; }
.ct-series-l .ct-point, .ct-series-l .ct-line, .ct-series-l .ct-bar, .ct-series-l .ct-slice-donut {
stroke: #86797d; }
.ct-series-l .ct-slice-pie, .ct-series-l .ct-slice-donut-solid, .ct-series-l .ct-area {
fill: #86797d; }
.ct-series-m .ct-point, .ct-series-m .ct-line, .ct-series-m .ct-bar, .ct-series-m .ct-slice-donut {
stroke: #b2c326; }
.ct-series-m .ct-slice-pie, .ct-series-m .ct-slice-donut-solid, .ct-series-m .ct-area {
fill: #b2c326; }
.ct-series-n .ct-point, .ct-series-n .ct-line, .ct-series-n .ct-bar, .ct-series-n .ct-slice-donut {
stroke: #6188e2; }
.ct-series-n .ct-slice-pie, .ct-series-n .ct-slice-donut-solid, .ct-series-n .ct-area {
fill: #6188e2; }
.ct-series-o .ct-point, .ct-series-o .ct-line, .ct-series-o .ct-bar, .ct-series-o .ct-slice-donut {
stroke: #a748ca; }
.ct-series-o .ct-slice-pie, .ct-series-o .ct-slice-donut-solid, .ct-series-o .ct-area {
fill: #a748ca; }
.ct-square {
display: block;
position: relative;
width: 100%; }
.ct-square:before {
display: block;
float: left;
content: "";
width: 0;
height: 0;
padding-bottom: 100%; }
.ct-square:after {
content: "";
display: table;
clear: both; }
.ct-square > svg {
display: block;
position: absolute;
top: 0;
left: 0; }
.ct-minor-second {
display: block;
position: relative;
width: 100%; }
.ct-minor-second:before {
display: block;
float: left;
content: "";
width: 0;
height: 0;
padding-bottom: 93.75%; }
.ct-minor-second:after {
content: "";
display: table;
clear: both; }
.ct-minor-second > svg {
display: block;
position: absolute;
top: 0;
left: 0; }
.ct-major-second {
display: block;
position: relative;
width: 100%; }
.ct-major-second:before {
display: block;
float: left;
content: "";
width: 0;
height: 0;
padding-bottom: 88.8888888889%; }
.ct-major-second:after {
content: "";
display: table;
clear: both; }
.ct-major-second > svg {
display: block;
position: absolute;
top: 0;
left: 0; }
.ct-minor-third {
display: block;
position: relative;
width: 100%; }
.ct-minor-third:before {
display: block;
float: left;
content: "";
width: 0;
height: 0;
padding-bottom: 83.3333333333%; }
.ct-minor-third:after {
content: "";
display: table;
clear: both; }
.ct-minor-third > svg {
display: block;
position: absolute;
top: 0;
left: 0; }
.ct-major-third {
display: block;
position: relative;
width: 100%; }
.ct-major-third:before {
display: block;
float: left;
content: "";
width: 0;
height: 0;
padding-bottom: 80%; }
.ct-major-third:after {
content: "";
display: table;
clear: both; }
.ct-major-third > svg {
display: block;
position: absolute;
top: 0;
left: 0; }
.ct-perfect-fourth {
display: block;
position: relative;
width: 100%; }
.ct-perfect-fourth:before {
display: block;
float: left;
content: "";
width: 0;
height: 0;
padding-bottom: 75%; }
.ct-perfect-fourth:after {
content: "";
display: table;
clear: both; }
.ct-perfect-fourth > svg {
display: block;
position: absolute;
top: 0;
left: 0; }
.ct-perfect-fifth {
display: block;
position: relative;
width: 100%; }
.ct-perfect-fifth:before {
display: block;
float: left;
content: "";
width: 0;
height: 0;
padding-bottom: 66.6666666667%; }
.ct-perfect-fifth:after {
content: "";
display: table;
clear: both; }
.ct-perfect-fifth > svg {
display: block;
position: absolute;
top: 0;
left: 0; }
.ct-minor-sixth {
display: block;
position: relative;
width: 100%; }
.ct-minor-sixth:before {
display: block;
float: left;
content: "";
width: 0;
height: 0;
padding-bottom: 62.5%; }
.ct-minor-sixth:after {
content: "";
display: table;
clear: both; }
.ct-minor-sixth > svg {
display: block;
position: absolute;
top: 0;
left: 0; }
.ct-golden-section {
display: block;
position: relative;
width: 100%; }
.ct-golden-section:before {
display: block;
float: left;
content: "";
width: 0;
height: 0;
padding-bottom: 61.804697157%; }
.ct-golden-section:after {
content: "";
display: table;
clear: both; }
.ct-golden-section > svg {
display: block;
position: absolute;
top: 0;
left: 0; }
.ct-major-sixth {
display: block;
position: relative;
width: 100%; }
.ct-major-sixth:before {
display: block;
float: left;
content: "";
width: 0;
height: 0;
padding-bottom: 60%; }
.ct-major-sixth:after {
content: "";
display: table;
clear: both; }
.ct-major-sixth > svg {
display: block;
position: absolute;
top: 0;
left: 0; }
.ct-minor-seventh {
display: block;
position: relative;
width: 100%; }
.ct-minor-seventh:before {
display: block;
float: left;
content: "";
width: 0;
height: 0;
padding-bottom: 56.25%; }
.ct-minor-seventh:after {
content: "";
display: table;
clear: both; }
.ct-minor-seventh > svg {
display: block;
position: absolute;
top: 0;
left: 0; }
.ct-major-seventh {
display: block;
position: relative;
width: 100%; }
.ct-major-seventh:before {
display: block;
float: left;
content: "";
width: 0;
height: 0;
padding-bottom: 53.3333333333%; }
.ct-major-seventh:after {
content: "";
display: table;
clear: both; }
.ct-major-seventh > svg {
display: block;
position: absolute;
top: 0;
left: 0; }
.ct-octave {
display: block;
position: relative;
width: 100%; }
.ct-octave:before {
display: block;
float: left;
content: "";
width: 0;
height: 0;
padding-bottom: 50%; }
.ct-octave:after {
content: "";
display: table;
clear: both; }
.ct-octave > svg {
display: block;
position: absolute;
top: 0;
left: 0; }
.ct-major-tenth {
display: block;
position: relative;
width: 100%; }
.ct-major-tenth:before {
display: block;
float: left;
content: "";
width: 0;
height: 0;
padding-bottom: 40%; }
.ct-major-tenth:after {
content: "";
display: table;
clear: both; }
.ct-major-tenth > svg {
display: block;
position: absolute;
top: 0;
left: 0; }
.ct-major-eleventh {
display: block;
position: relative;
width: 100%; }
.ct-major-eleventh:before {
display: block;
float: left;
content: "";
width: 0;
height: 0;
padding-bottom: 37.5%; }
.ct-major-eleventh:after {
content: "";
display: table;
clear: both; }
.ct-major-eleventh > svg {
display: block;
position: absolute;
top: 0;
left: 0; }
.ct-major-twelfth {
display: block;
position: relative;
width: 100%; }
.ct-major-twelfth:before {
display: block;
float: left;
content: "";
width: 0;
height: 0;
padding-bottom: 33.3333333333%; }
.ct-major-twelfth:after {
content: "";
display: table;
clear: both; }
.ct-major-twelfth > svg {
display: block;
position: absolute;
top: 0;
left: 0; }
.ct-double-octave {
display: block;
position: relative;
width: 100%; }
.ct-double-octave:before {
display: block;
float: left;
content: "";
width: 0;
height: 0;
padding-bottom: 25%; }
.ct-double-octave:after {
content: "";
display: table;
clear: both; }
.ct-double-octave > svg {
display: block;
position: absolute;
top: 0;
left: 0; }
/*# sourceMappingURL=chartist.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,241 @@
@import "settings/chartist-settings";
@mixin ct-responsive-svg-container($width: 100%, $ratio: $ct-container-ratio) {
display: block;
position: relative;
width: $width;
&:before {
display: block;
float: left;
content: "";
width: 0;
height: 0;
padding-bottom: $ratio * 100%;
}
&:after {
content: "";
display: table;
clear: both;
}
> svg {
display: block;
position: absolute;
top: 0;
left: 0;
}
}
@mixin ct-align-justify($ct-text-align: $ct-text-align, $ct-text-justify: $ct-text-justify) {
-webkit-box-align: $ct-text-align;
-webkit-align-items: $ct-text-align;
-ms-flex-align: $ct-text-align;
align-items: $ct-text-align;
-webkit-box-pack: $ct-text-justify;
-webkit-justify-content: $ct-text-justify;
-ms-flex-pack: $ct-text-justify;
justify-content: $ct-text-justify;
// Fallback to text-align for non-flex browsers
@if($ct-text-justify == 'flex-start') {
text-align: left;
} @else if ($ct-text-justify == 'flex-end') {
text-align: right;
} @else {
text-align: center;
}
}
@mixin ct-flex() {
// Fallback to block
display: block;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
}
@mixin ct-chart-label($ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-text-line-height: $ct-text-line-height) {
fill: $ct-text-color;
color: $ct-text-color;
font-size: $ct-text-size;
line-height: $ct-text-line-height;
}
@mixin ct-chart-grid($ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray) {
stroke: $ct-grid-color;
stroke-width: $ct-grid-width;
@if ($ct-grid-dasharray) {
stroke-dasharray: $ct-grid-dasharray;
}
}
@mixin ct-chart-point($ct-point-size: $ct-point-size, $ct-point-shape: $ct-point-shape) {
stroke-width: $ct-point-size;
stroke-linecap: $ct-point-shape;
}
@mixin ct-chart-line($ct-line-width: $ct-line-width, $ct-line-dasharray: $ct-line-dasharray) {
fill: none;
stroke-width: $ct-line-width;
@if ($ct-line-dasharray) {
stroke-dasharray: $ct-line-dasharray;
}
}
@mixin ct-chart-area($ct-area-opacity: $ct-area-opacity) {
stroke: none;
fill-opacity: $ct-area-opacity;
}
@mixin ct-chart-bar($ct-bar-width: $ct-bar-width) {
fill: none;
stroke-width: $ct-bar-width;
}
@mixin ct-chart-donut($ct-donut-width: $ct-donut-width) {
fill: none;
stroke-width: $ct-donut-width;
}
@mixin ct-chart-series-color($color) {
.#{$ct-class-point}, .#{$ct-class-line}, .#{$ct-class-bar}, .#{$ct-class-slice-donut} {
stroke: $color;
}
.#{$ct-class-slice-pie}, .#{$ct-class-slice-donut-solid}, .#{$ct-class-area} {
fill: $color;
}
}
@mixin ct-chart($ct-container-ratio: $ct-container-ratio, $ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray, $ct-point-size: $ct-point-size, $ct-point-shape: $ct-point-shape, $ct-line-width: $ct-line-width, $ct-bar-width: $ct-bar-width, $ct-donut-width: $ct-donut-width, $ct-series-names: $ct-series-names, $ct-series-colors: $ct-series-colors) {
.#{$ct-class-label} {
@include ct-chart-label($ct-text-color, $ct-text-size);
}
.#{$ct-class-chart-line} .#{$ct-class-label},
.#{$ct-class-chart-bar} .#{$ct-class-label} {
@include ct-flex();
}
.#{$ct-class-chart-pie} .#{$ct-class-label},
.#{$ct-class-chart-donut} .#{$ct-class-label} {
dominant-baseline: central;
}
.#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} {
@include ct-align-justify(flex-end, flex-start);
// Fallback for browsers that don't support foreignObjects
text-anchor: start;
}
.#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-end} {
@include ct-align-justify(flex-start, flex-start);
// Fallback for browsers that don't support foreignObjects
text-anchor: start;
}
.#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-start} {
@include ct-align-justify(flex-end, flex-end);
// Fallback for browsers that don't support foreignObjects
text-anchor: end;
}
.#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-end} {
@include ct-align-justify(flex-end, flex-start);
// Fallback for browsers that don't support foreignObjects
text-anchor: start;
}
.#{$ct-class-chart-bar} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} {
@include ct-align-justify(flex-end, center);
// Fallback for browsers that don't support foreignObjects
text-anchor: start;
}
.#{$ct-class-chart-bar} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-end} {
@include ct-align-justify(flex-start, center);
// Fallback for browsers that don't support foreignObjects
text-anchor: start;
}
.#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} {
@include ct-align-justify(flex-end, flex-start);
// Fallback for browsers that don't support foreignObjects
text-anchor: start;
}
.#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-end} {
@include ct-align-justify(flex-start, flex-start);
// Fallback for browsers that don't support foreignObjects
text-anchor: start;
}
.#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-start} {
//@include ct-chart-label($ct-text-color, $ct-text-size, center, $ct-vertical-text-justify);
@include ct-align-justify(center, flex-end);
// Fallback for browsers that don't support foreignObjects
text-anchor: end;
}
.#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-end} {
@include ct-align-justify(center, flex-start);
// Fallback for browsers that don't support foreignObjects
text-anchor: end;
}
.#{$ct-class-grid} {
@include ct-chart-grid($ct-grid-color, $ct-grid-width, $ct-grid-dasharray);
}
.#{$ct-class-grid-background} {
fill: $ct-grid-background-fill;
}
.#{$ct-class-point} {
@include ct-chart-point($ct-point-size, $ct-point-shape);
}
.#{$ct-class-line} {
@include ct-chart-line($ct-line-width);
}
.#{$ct-class-area} {
@include ct-chart-area();
}
.#{$ct-class-bar} {
@include ct-chart-bar($ct-bar-width);
}
.#{$ct-class-slice-donut} {
@include ct-chart-donut($ct-donut-width);
}
@if $ct-include-colored-series {
@for $i from 0 to length($ct-series-names) {
.#{$ct-class-series}-#{nth($ct-series-names, $i + 1)} {
$color: nth($ct-series-colors, $i + 1);
@include ct-chart-series-color($color);
}
}
}
}
@if $ct-include-classes {
@include ct-chart();
@if $ct-include-alternative-responsive-containers {
@for $i from 0 to length($ct-scales-names) {
.#{nth($ct-scales-names, $i + 1)} {
@include ct-responsive-svg-container($ratio: nth($ct-scales, $i + 1));
}
}
}
}

@ -0,0 +1,88 @@
// Scales for responsive SVG containers
$ct-scales: ((1), (15/16), (8/9), (5/6), (4/5), (3/4), (2/3), (5/8), (1/1.618), (3/5), (9/16), (8/15), (1/2), (2/5), (3/8), (1/3), (1/4)) !default;
$ct-scales-names: (ct-square, ct-minor-second, ct-major-second, ct-minor-third, ct-major-third, ct-perfect-fourth, ct-perfect-fifth, ct-minor-sixth, ct-golden-section, ct-major-sixth, ct-minor-seventh, ct-major-seventh, ct-octave, ct-major-tenth, ct-major-eleventh, ct-major-twelfth, ct-double-octave) !default;
// Class names to be used when generating CSS
$ct-class-chart: ct-chart !default;
$ct-class-chart-line: ct-chart-line !default;
$ct-class-chart-bar: ct-chart-bar !default;
$ct-class-horizontal-bars: ct-horizontal-bars !default;
$ct-class-chart-pie: ct-chart-pie !default;
$ct-class-chart-donut: ct-chart-donut !default;
$ct-class-label: ct-label !default;
$ct-class-series: ct-series !default;
$ct-class-line: ct-line !default;
$ct-class-point: ct-point !default;
$ct-class-area: ct-area !default;
$ct-class-bar: ct-bar !default;
$ct-class-slice-pie: ct-slice-pie !default;
$ct-class-slice-donut: ct-slice-donut !default;
$ct-class-slice-donut-solid: ct-slice-donut-solid !default;
$ct-class-grid: ct-grid !default;
$ct-class-grid-background: ct-grid-background !default;
$ct-class-vertical: ct-vertical !default;
$ct-class-horizontal: ct-horizontal !default;
$ct-class-start: ct-start !default;
$ct-class-end: ct-end !default;
// Container ratio
$ct-container-ratio: (1/1.618) !default;
// Text styles for labels
$ct-text-color: rgba(0, 0, 0, 0.4) !default;
$ct-text-size: 0.75rem !default;
$ct-text-align: flex-start !default;
$ct-text-justify: flex-start !default;
$ct-text-line-height: 1;
// Grid styles
$ct-grid-color: rgba(0, 0, 0, 0.2) !default;
$ct-grid-dasharray: 2px !default;
$ct-grid-width: 1px !default;
$ct-grid-background-fill: none !default;
// Line chart properties
$ct-line-width: 4px !default;
$ct-line-dasharray: false !default;
$ct-point-size: 10px !default;
// Line chart point, can be either round or square
$ct-point-shape: round !default;
// Area fill transparency between 0 and 1
$ct-area-opacity: 0.1 !default;
// Bar chart bar width
$ct-bar-width: 10px !default;
// Donut width (If donut width is to big it can cause issues where the shape gets distorted)
$ct-donut-width: 60px !default;
// If set to true it will include the default classes and generate CSS output. If you're planning to use the mixins you
// should set this property to false
$ct-include-classes: true !default;
// If this is set to true the CSS will contain colored series. You can extend or change the color with the
// properties below
$ct-include-colored-series: $ct-include-classes !default;
// If set to true this will include all responsive container variations using the scales defined at the top of the script
$ct-include-alternative-responsive-containers: $ct-include-classes !default;
// Series names and colors. This can be extended or customized as desired. Just add more series and colors.
$ct-series-names: (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) !default;
$ct-series-colors: (
#d70206,
#f05b4f,
#f4c63d,
#d17905,
#453d3f,
#59922b,
#0544d3,
#6b0392,
#f05b4f,
#dda458,
#eacf7d,
#86797d,
#b2c326,
#6188e2,
#a748ca
) !default;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

@ -1,146 +0,0 @@
body, .default {
font-size:14px;
font-family:sans-serif;
font-weight:lighter;
padding:10px;
}
.jsgrid-grid-header{
background: #f9f9f9;
background-color: rgb(249, 249, 249);
background-image: none;
background-repeat: repeat;
background-attachment: scroll;
background-clip: border-box;
background-origin: padding-box;
background-position-x: 0%;
background-position-y: 0%;
background-size: auto auto;
max-height: 48px;
}
.jsgrid-grid-body {
overflow-x:hidden;
overflow-y:scroll;
-webkit-overflow-scrolling:touch
}
.small {
font-family:sans-serif;
font-size:12px;
font-weight:lighter;
}
.bold {font-weight:bold}
.left {float:left}
.right{float:right}
.caption {
font-size:22px;
margin:2px;
padding:2px;
height:30px;
font-family:sans-serif;
font-weight:lighter;
}
.button {
padding:8px;
margin:2px;
border-radius:4px;
-moz-border-radius:4px;
-webkit-border-radius:4px;
cursor:pointer;
}
.button:hover{
background-color:#4682B4 ;
color:#ffffff;
}
.no-border{ border:1px solid transparent}
.border { border:1px solid #CAD5E0}
.border-bottom{ border-bottom:1px solid #CAD5E0;}
.border-right { border-right:1px solid #CAD5E0;}
.border-left { border-left:1px solid #CAD5E0;}
.border-top { border-top:1px solid #CAD5E0;}
.grid {
font-family:sans-serif;
font-weight:lighter;
margin:4px;
padding:4px;
}
.grid-half {
height:195px;
margin:4px;
width:98%;
padding:4px;
}
.grid .fa-check {color:green}
.grid .fa-times {color:maroon; }
.menu {
margin:4px;
padding:4px;
}
.menu .fa-chevron-right {color:transparent; margin:4px; }
.menu .menu-item { border:1px solid transparent; cursor:pointer; padding-bottom:4px; margin:2px;}
.menu .menu-item:hover {
border-bottom-color:#4682B4;
}
.menu .menu-item:hover .fa-chevron-right { color:#4582b4}
input[type=text]{
padding:4px;
margin:4px;
outline:0px;
border:1px solid transparent;
background-color:#f3f3f3;
font-size:14px;
font-weight:lighter;
font-family:sans-serif;
}
input[type=text]:focus{
border-left-color:#4682B4;
}
.padding-2x{padding:4px;}
.margin-2x {margin:4px;}
.info {
margin:4px;
width:43%;
}
.height-quarter{height:24%;}
.height-half{height:47%}
.width-quarter {width:24%}
.width-half {width:47%; }
.width-75 {width:72%}
.bad { color:maroon}
.good{ color:green}
.fa-warning, .warning{color:orange}
.number {font-size:42px; font-weight:lighter; padding:2px; margin:2px;}
.action {cursor:pointer; padding:2px; margin:2px; border:1px solid transparent}
.action:hover { border-bottom-color:#4682B4}
.shadow{box-shadow: 7px 7px 5px #888888;}
.gradient {
background-image:
linear-gradient(
#4682b4, #ffffff,#ffffff
);
}
.simple-gradient {
background-image: -ms-linear-gradient(top, #CAD5E0 0%, #F3F3F3 40%);
background-image: -moz-linear-gradient(top, #CAD5E0 0%, #F3F3F3 40%);
background-image: -o-linear-gradient(top, #CAD5E0 0%, #F3F3F3 40%);
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #CAD5E0), color-stop(40, #F3F3F3));
background-image: -webkit-linear-gradient(top, #CAD5E0 0%, #F3F3F3 40%);
background-image: linear-gradient(to bottom, #CAD5E0 0%, #F3F3F3 40%);
}

@ -5,7 +5,7 @@
display: inline-block; display: inline-block;
font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration
font-size: inherit; // can't have font-size inherit on line above, so need to override font-size: inherit; // can't have font-size inherit on line above, so need to override
text-rendering: auto; // optimizelegibility throws things off #1094 text-rendering: auto; // optimize legibility throws things off #1094
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

Binary file not shown.

@ -0,0 +1,243 @@
<?xml version="1.0" encoding="UTF-8"?>
<XMI xmlns:UML="http://schema.omg.org/spec/UML/1.3" timestamp="2017-04-07T08:29:04" xmi.version="1.2" verified="false">
<XMI.header>
<XMI.documentation>
<XMI.exporter>umbrello uml modeller http://umbrello.kde.org</XMI.exporter>
<XMI.exporterVersion>1.6.9</XMI.exporterVersion>
<XMI.exporterEncoding>UnicodeUTF8</XMI.exporterEncoding>
</XMI.documentation>
<XMI.metamodel href="UML.xml" xmi.name="UML" xmi.version="1.3"/>
</XMI.header>
<XMI.content>
<UML:Model isRoot="false" isSpecification="false" name="UML Model" isAbstract="false" xmi.id="m1" isLeaf="false">
<UML:Namespace.ownedElement>
<UML:Stereotype isRoot="false" isSpecification="false" namespace="m1" name="folder" isAbstract="false" isLeaf="false" xmi.id="folder" visibility="public"/>
<UML:Stereotype isRoot="false" isSpecification="false" namespace="m1" name="datatype" isAbstract="false" isLeaf="false" xmi.id="datatype" visibility="public"/>
<UML:Stereotype isRoot="false" isSpecification="false" namespace="m1" name="agent" isAbstract="false" isLeaf="false" xmi.id="rSZCzDKpjhw5" visibility="public"/>
<UML:Stereotype isRoot="false" isSpecification="false" namespace="m1" name="interface" isAbstract="false" isLeaf="false" xmi.id="interface" visibility="public"/>
<UML:Model isRoot="false" isSpecification="false" namespace="m1" name="Logical View" isAbstract="false" isLeaf="false" xmi.id="Logical View" visibility="public">
<UML:Namespace.ownedElement>
<UML:Package isRoot="false" stereotype="folder" isSpecification="false" namespace="Logical View" name="Datatypes" isAbstract="false" isLeaf="false" xmi.id="Datatypes" visibility="public">
<UML:Namespace.ownedElement>
<UML:DataType isRoot="false" stereotype="datatype" isSpecification="false" namespace="Datatypes" name="int" isAbstract="false" isLeaf="false" xmi.id="fCoa6Ljfk80G" visibility="public"/>
<UML:DataType isRoot="false" stereotype="datatype" isSpecification="false" namespace="Datatypes" name="char" isAbstract="false" isLeaf="false" xmi.id="XVF672bO1S1I" visibility="public"/>
<UML:DataType isRoot="false" stereotype="datatype" isSpecification="false" namespace="Datatypes" name="bool" isAbstract="false" isLeaf="false" xmi.id="HU1uO6O1JAZP" visibility="public"/>
<UML:DataType isRoot="false" stereotype="datatype" isSpecification="false" namespace="Datatypes" name="float" isAbstract="false" isLeaf="false" xmi.id="UI3ER3SwXh1e" visibility="public"/>
<UML:DataType isRoot="false" stereotype="datatype" isSpecification="false" namespace="Datatypes" name="double" isAbstract="false" isLeaf="false" xmi.id="hc0i20yJS0Dp" visibility="public"/>
<UML:DataType isRoot="false" stereotype="datatype" isSpecification="false" namespace="Datatypes" name="short" isAbstract="false" isLeaf="false" xmi.id="6aqNkOnEgoR7" visibility="public"/>
<UML:DataType isRoot="false" stereotype="datatype" isSpecification="false" namespace="Datatypes" name="long" isAbstract="false" isLeaf="false" xmi.id="pt2Mb3yGdzxf" visibility="public"/>
<UML:DataType isRoot="false" stereotype="datatype" isSpecification="false" namespace="Datatypes" name="unsigned int" isAbstract="false" isLeaf="false" xmi.id="xvyPvAC0i1NS" visibility="public"/>
<UML:DataType isRoot="false" stereotype="datatype" isSpecification="false" namespace="Datatypes" name="unsigned short" isAbstract="false" isLeaf="false" xmi.id="P8f5w6BmxD8W" visibility="public"/>
<UML:DataType isRoot="false" stereotype="datatype" isSpecification="false" namespace="Datatypes" name="unsigned long" isAbstract="false" isLeaf="false" xmi.id="E7nr4kW1fSOb" visibility="public"/>
<UML:DataType isRoot="false" stereotype="datatype" isSpecification="false" namespace="Datatypes" name="string" isAbstract="false" isLeaf="false" xmi.id="abbIcwjz5O41" visibility="public"/>
</UML:Namespace.ownedElement>
</UML:Package>
<UML:Interface isRoot="false" stereotype="interface" isSpecification="false" namespace="Logical View" name="Agent" isAbstract="true" isLeaf="false" xmi.id="RXqBshUB41L5" visibility="public">
<UML:Classifier.feature>
<UML:Operation isRoot="false" isQuery="false" isSpecification="false" name="init" isAbstract="false" isLeaf="false" xmi.id="wViGJvmJF1zV" visibility="public"/>
<UML:Operation isRoot="false" isQuery="false" isSpecification="false" name="execute" isAbstract="false" isLeaf="false" xmi.id="7FOYGyKLJkjG" visibility="public"/>
<UML:Operation isRoot="false" isQuery="false" isSpecification="false" name="status" isAbstract="false" isLeaf="false" xmi.id="q8oPwCisiO61" visibility="public"/>
<UML:Operation isRoot="false" isQuery="false" isSpecification="false" name="instance" isAbstract="false" isLeaf="false" xmi.id="2fGeoj3czd3G" visibility="public" ownerScope="classifier"/>
</UML:Classifier.feature>
</UML:Interface>
<UML:Interface isRoot="false" stereotype="interface" isSpecification="false" namespace="Logical View" name="data-store" isAbstract="true" isLeaf="false" xmi.id="dqWyyHKwPkeW" visibility="public"/>
</UML:Namespace.ownedElement>
<XMI.extension xmi.extender="umbrello">
<diagrams>
<diagram usefillcolor="1" linewidth="0" showpubliconly="0" snapy="25" isopen="1" showatts="1" zoom="100" griddotcolor="#d3d3d3" name="class diagram" canvasheight="0" showpackage="1" canvaswidth="0" type="1" showops="1" xmi.id="J1rdJrVlcu5U" showgrid="0" showattsig="1" backgroundcolor="#ffffff" linecolor="#ff0000" snapcsgrid="0" fillcolor="#ffff00" showattribassocs="1" localid="-1" snapgrid="0" showscope="1" showopsig="1" snapx="25" showstereotype="1" textcolor="#000000" font="Sans Serif,9,-1,5,50,0,0,0,0,0" documentation="">
<widgets/>
<messages/>
<associations/>
</diagram>
</diagrams>
</XMI.extension>
</UML:Model>
<UML:Model isRoot="false" isSpecification="false" namespace="m1" name="Use Case View" isAbstract="false" isLeaf="false" xmi.id="Use Case View" visibility="public">
<UML:Namespace.ownedElement/>
</UML:Model>
<UML:Model isRoot="false" isSpecification="false" namespace="m1" name="Component View" isAbstract="false" isLeaf="false" xmi.id="Component View" visibility="public">
<UML:Namespace.ownedElement>
<UML:Component isRoot="false" isSpecification="false" namespace="Component View" name="data-collector" isAbstract="false" isLeaf="false" xmi.id="Tz06QOf0xEHX" visibility="public" executable="0"/>
<UML:Component isRoot="false" stereotype="rSZCzDKpjhw5" isSpecification="false" namespace="Component View" name="Learner" isAbstract="false" isLeaf="false" xmi.id="qVP8MjpaiUjw" visibility="public" executable="0"/>
<UML:Component isRoot="false" stereotype="rSZCzDKpjhw5" isSpecification="false" namespace="Component View" name="Kill" isAbstract="false" isLeaf="false" xmi.id="IsIXtH00UPZi" visibility="public" executable="0"/>
<UML:Abstraction isSpecification="false" namespace="Component View" name="" supplier="RXqBshUB41L5" xmi.id="rVfXulYAdqhX" visibility="public" client="IsIXtH00UPZi"/>
<UML:Component isRoot="false" stereotype="rSZCzDKpjhw5" isSpecification="false" namespace="Component View" name="Start" isAbstract="false" isLeaf="false" xmi.id="1TAcIp7NVdvX" visibility="public" executable="0"/>
<UML:Abstraction isSpecification="false" namespace="Component View" name="" supplier="RXqBshUB41L5" xmi.id="PvoWBjUADfkV" visibility="public" client="1TAcIp7NVdvX"/>
<UML:Component isRoot="false" stereotype="rSZCzDKpjhw5" isSpecification="false" namespace="Component View" name="Notify" isAbstract="false" isLeaf="false" xmi.id="HSy87jRVwqsY" visibility="public" executable="0"/>
<UML:Component isRoot="false" stereotype="rSZCzDKpjhw5" isSpecification="false" namespace="Component View" name="Mailer" isAbstract="false" isLeaf="false" xmi.id="2X1nlev04t8B" visibility="public" executable="0"/>
<UML:Abstraction isSpecification="false" namespace="Component View" name="" supplier="RXqBshUB41L5" xmi.id="HyCj3nQ3KPr5" visibility="public" client="2X1nlev04t8B"/>
<UML:Abstraction isSpecification="false" namespace="Component View" name="" supplier="RXqBshUB41L5" xmi.id="jpx2Co5CY9GC" visibility="public" client="HSy87jRVwqsY"/>
<UML:Association isSpecification="false" namespace="Component View" name="" xmi.id="xfmTo0d7U3Co" visibility="public">
<UML:Association.connection>
<UML:AssociationEnd isNavigable="false" aggregation="none" isSpecification="false" changeability="changeable" name="" type="Tz06QOf0xEHX" xmi.id="GLVKohqCd1VT" visibility="public"/>
<UML:AssociationEnd isNavigable="true" aggregation="none" isSpecification="false" changeability="changeable" name="" type="RXqBshUB41L5" xmi.id="cgz2pZckFNB1" visibility="public"/>
</UML:Association.connection>
</UML:Association>
<UML:Component isRoot="false" isSpecification="false" namespace="Component View" name="NoSQL" isAbstract="false" isLeaf="false" xmi.id="ZPS2o7GDkc5b" visibility="public" executable="0"/>
<UML:Component isRoot="false" isSpecification="false" namespace="Component View" name="Queue" isAbstract="false" isLeaf="false" xmi.id="yAQh9XwiuMkg" visibility="public" executable="0"/>
<UML:Abstraction isSpecification="false" namespace="Component View" name="" supplier="dqWyyHKwPkeW" xmi.id="roUjSuB43yq5" visibility="public" client="yAQh9XwiuMkg"/>
<UML:Abstraction isSpecification="false" namespace="Component View" name="" supplier="dqWyyHKwPkeW" xmi.id="up5vlwzBogrF" visibility="public" client="ZPS2o7GDkc5b"/>
<UML:Association isSpecification="false" namespace="Component View" name="" xmi.id="EZF1F7EEwgSu" visibility="public">
<UML:Association.connection>
<UML:AssociationEnd isNavigable="false" aggregation="none" isSpecification="false" changeability="changeable" name="" type="Tz06QOf0xEHX" xmi.id="WZqWR7Y3vUHh" visibility="public"/>
<UML:AssociationEnd isNavigable="true" aggregation="none" isSpecification="false" changeability="changeable" name="" type="dqWyyHKwPkeW" xmi.id="2WNNqxT3Uh2j" visibility="public"/>
</UML:Association.connection>
</UML:Association>
<UML:Component isRoot="false" isSpecification="false" namespace="Component View" name="Dashboard" isAbstract="false" isLeaf="false" xmi.id="mGviuNaRvQvK" visibility="public" executable="0"/>
<UML:Association isSpecification="false" namespace="Component View" name="" xmi.id="Mm0rT2YFGUvA" visibility="public">
<UML:Association.connection>
<UML:AssociationEnd isNavigable="false" aggregation="none" isSpecification="false" changeability="changeable" name="" type="mGviuNaRvQvK" xmi.id="pTZirT2NwOlu" visibility="public"/>
<UML:AssociationEnd isNavigable="true" aggregation="none" isSpecification="false" changeability="changeable" name="" type="dqWyyHKwPkeW" xmi.id="0rp9GA8cw6RN" visibility="public"/>
</UML:Association.connection>
</UML:Association>
<UML:Dependency isSpecification="false" namespace="Component View" name="" supplier="dqWyyHKwPkeW" xmi.id="80aOSVWFy4yp" visibility="public" client="qVP8MjpaiUjw"/>
</UML:Namespace.ownedElement>
<XMI.extension xmi.extender="umbrello">
<diagrams>
<diagram usefillcolor="0" linewidth="0" showpubliconly="0" snapy="25" isopen="1" showatts="1" zoom="100" griddotcolor="#d3d3d3" name="component diagram" canvasheight="614" showpackage="1" canvaswidth="1042" type="7" showops="1" xmi.id="SFlPQuwezjV1" showgrid="0" showattsig="1" backgroundcolor="#ffffff" linecolor="#000000" snapcsgrid="0" fillcolor="#ffff00" showattribassocs="1" localid="-1" snapgrid="0" showscope="1" showopsig="1" snapx="25" showstereotype="1" textcolor="#000000" font="Sans Serif,9,-1,5,50,0,0,0,0,0" documentation="">
<widgets>
<componentwidget usesdiagramfillcolor="0" fillcolor="#ffff00" font="Sans Serif,9,-1,5,50,0,0,0,0,0" y="-678" usefillcolor="0" isinstance="0" textcolor="#000000" usesdiagramusefillcolor="0" height="64" localid="v7rsoLtFIrMg" linewidth="0" linecolor="#000000" xmi.id="Tz06QOf0xEHX" x="-1736" width="159" showstereotype="1"/>
<componentwidget usesdiagramfillcolor="0" fillcolor="#ffff00" font="Sans Serif,9,-1,5,50,0,0,0,0,0" y="-412" usefillcolor="0" isinstance="0" textcolor="#000000" usesdiagramusefillcolor="0" height="64" localid="OPLKYyaGrclm" linewidth="0" linecolor="#000000" xmi.id="qVP8MjpaiUjw" x="-1550" width="146" showstereotype="1"/>
<interfacewidget usefillcolor="0" isinstance="0" linewidth="0" usesdiagramusefillcolor="0" showpubliconly="0" showoperations="1" height="102" y="-690.5" width="93" showattsigs="601" showpackage="0" xmi.id="RXqBshUB41L5" usesdiagramfillcolor="0" x="-1500.5" linecolor="#000000" fillcolor="#ffff00" localid="bSOrj87QKpFY" showscope="1" showattributes="0" showstereotype="1" textcolor="#000000" font="Sans Serif,9,-1,5,50,0,0,0,0,0" showopsigs="601" drawascircle="0"/>
<componentwidget usesdiagramfillcolor="0" fillcolor="#ffff00" font="Sans Serif,9,-1,5,50,0,0,0,0,0" y="-810" usefillcolor="0" isinstance="0" textcolor="#000000" usesdiagramusefillcolor="0" height="64" localid="Lr1cZksQrfnn" linewidth="0" linecolor="#000000" xmi.id="IsIXtH00UPZi" x="-1276" width="118" showstereotype="1"/>
<componentwidget usesdiagramfillcolor="0" fillcolor="#ffff00" font="Sans Serif,9,-1,5,50,0,0,0,0,0" y="-687" usefillcolor="0" isinstance="0" textcolor="#000000" usesdiagramusefillcolor="0" height="64" localid="fCxXTyzSroIP" linewidth="0" linecolor="#000000" xmi.id="1TAcIp7NVdvX" x="-1114" width="118" showstereotype="1"/>
<componentwidget usesdiagramfillcolor="0" fillcolor="#ffff00" font="Sans Serif,9,-1,5,50,0,0,0,0,0" y="-579" usefillcolor="0" isinstance="0" textcolor="#000000" usesdiagramusefillcolor="0" height="65" localid="rbXRChMtT5dh" linewidth="0" linecolor="#000000" xmi.id="HSy87jRVwqsY" x="-1293" width="150" showstereotype="1"/>
<componentwidget usesdiagramfillcolor="0" fillcolor="#ffff00" font="Sans Serif,9,-1,5,50,0,0,0,0,0" y="-803" usefillcolor="0" isinstance="0" textcolor="#000000" usesdiagramusefillcolor="0" height="64" localid="cZfZNX5E6adI" linewidth="0" linecolor="#000000" xmi.id="2X1nlev04t8B" x="-1515" width="118" showstereotype="1"/>
<componentwidget usesdiagramfillcolor="0" fillcolor="#ffff00" font="Sans Serif,9,-1,5,50,0,0,0,0,0" y="-426" usefillcolor="0" isinstance="0" textcolor="#000000" usesdiagramusefillcolor="0" height="64" localid="nIBN2jAINAlN" linewidth="0" linecolor="#000000" xmi.id="ZPS2o7GDkc5b" x="-1891" width="145" showstereotype="1"/>
<componentwidget usesdiagramfillcolor="0" fillcolor="#ffff00" font="Sans Serif,9,-1,5,50,0,0,0,0,0" y="-319" usefillcolor="0" isinstance="0" textcolor="#000000" usesdiagramusefillcolor="0" height="64" localid="Rzr9ZxkMFuhF" linewidth="0" linecolor="#000000" xmi.id="yAQh9XwiuMkg" x="-1888" width="147" showstereotype="1"/>
<interfacewidget usefillcolor="0" isinstance="0" linewidth="0" usesdiagramusefillcolor="0" showpubliconly="0" showoperations="1" height="40" y="-410" width="40" showattsigs="601" showpackage="0" xmi.id="dqWyyHKwPkeW" usesdiagramfillcolor="0" x="-1674" linecolor="#000000" fillcolor="#ffff00" localid="GYF8sxpJueQR" showscope="1" showattributes="0" showstereotype="1" textcolor="#000000" font="Sans Serif,9,-1,5,50,0,0,0,0,0" showopsigs="601" drawascircle="1">
<floatingtext usefillcolor="1" isinstance="0" linewidth="0" pretext="" usesdiagramusefillcolor="1" height="21" y="66" posttext="" width="78" xmi.id="pwDCepiuLv1D" usesdiagramfillcolor="1" x="-22" text="data-store" linecolor="#000000" fillcolor="none" localid="b8no2T4fJacH" showstereotype="1" textcolor="none" font="Ubuntu,11,-1,5,50,0,0,0,0,0" role="700"/>
</interfacewidget>
<componentwidget usesdiagramfillcolor="0" fillcolor="#ffff00" font="Sans Serif,9,-1,5,50,0,0,0,0,0" y="-312" usefillcolor="0" isinstance="0" textcolor="#000000" usesdiagramusefillcolor="0" height="64" localid="VTNOxe5xARKz" linewidth="0" linecolor="#000000" xmi.id="mGviuNaRvQvK" x="-1546" width="152" showstereotype="1"/>
<boxwidget usesdiagramfillcolor="0" fillcolor="#ffff00" font="Sans Serif,9,-1,5,50,0,0,0,0,0" y="-817" usefillcolor="0" isinstance="0" textcolor="#000000" usesdiagramusefillcolor="0" height="338" localid="deiZieMDdXfx" linewidth="0" linecolor="#000000" xmi.id="TyIE7mFOMqb2" x="-1945" width="998" showstereotype="1"/>
<boxwidget usesdiagramfillcolor="0" fillcolor="#ffff00" font="Sans Serif,9,-1,5,50,0,0,0,0,0" y="-462" usefillcolor="0" isinstance="0" textcolor="#000000" usesdiagramusefillcolor="0" height="259" localid="r9osJyLub2TH" linewidth="0" linecolor="#0000ff" xmi.id="gqVHN8Fq6V2C" x="-1945" width="1000" showstereotype="1"/>
<floatingtext usefillcolor="0" isinstance="0" linewidth="0" pretext="" usesdiagramusefillcolor="0" height="32" y="-537" posttext="" width="154" xmi.id="M7Vv9zCpnf7A" usesdiagramfillcolor="0" x="-1933" text=" DETECTION" linecolor="#000000" fillcolor="#ffff00" localid="GFaa3AbvJPnb" showstereotype="1" textcolor="#000000" font="Sans Serif,18,-1,5,50,0,0,0,0,0" role="700"/>
<floatingtext usefillcolor="0" isinstance="0" linewidth="0" pretext="" usesdiagramusefillcolor="0" height="32" y="-248" posttext="" width="163" xmi.id="mD94avfu28pB" usesdiagramfillcolor="0" x="-1116" text="PREDICTION " linecolor="#000000" fillcolor="#ffff00" localid="nKysny43DccE" showstereotype="1" textcolor="#000000" font="Sans Serif,18,-1,5,50,0,0,0,0,0" role="700"/>
</widgets>
<messages/>
<associations>
<assocwidget usesdiagramfillcolor="0" fillcolor="#ffff00" indexa="1" font="Sans Serif,9,-1,5,50,0,0,0,0,0" usefillcolor="1" indexb="1" textcolor="none" usesdiagramusefillcolor="0" type="511" totalcountb="2" linewidth="0" widgetbid="RXqBshUB41L5" linecolor="#000000" xmi.id="rVfXulYAdqhX" widgetaid="IsIXtH00UPZi" seqnum="" totalcounta="2">
<linepath layout="Polyline">
<startpoint starty="-746" startx="-1223"/>
<endpoint endx="-1407.5" endy="-649"/>
<point y="-649" x="-1223"/>
</linepath>
</assocwidget>
<assocwidget usesdiagramfillcolor="0" fillcolor="#ffff00" indexa="1" font="Sans Serif,9,-1,5,50,0,0,0,0,0" usefillcolor="1" indexb="1" textcolor="none" usesdiagramusefillcolor="0" type="511" totalcountb="2" linewidth="0" widgetbid="RXqBshUB41L5" linecolor="#000000" xmi.id="PvoWBjUADfkV" widgetaid="1TAcIp7NVdvX" seqnum="" totalcounta="2">
<linepath layout="Polyline">
<startpoint starty="-650" startx="-1114"/>
<endpoint endx="-1407.5" endy="-650"/>
</linepath>
</assocwidget>
<assocwidget usesdiagramfillcolor="0" fillcolor="#ffff00" indexa="1" font="Sans Serif,9,-1,5,50,0,0,0,0,0" usefillcolor="1" indexb="1" textcolor="none" usesdiagramusefillcolor="0" type="511" totalcountb="2" linewidth="0" widgetbid="RXqBshUB41L5" linecolor="#000000" xmi.id="HyCj3nQ3KPr5" widgetaid="2X1nlev04t8B" seqnum="" totalcounta="2">
<linepath layout="Polyline">
<startpoint starty="-739" startx="-1467"/>
<endpoint endx="-1467" endy="-690.5"/>
</linepath>
</assocwidget>
<assocwidget usesdiagramfillcolor="0" fillcolor="#ffff00" indexa="1" font="Sans Serif,9,-1,5,50,0,0,0,0,0" usefillcolor="1" indexb="1" textcolor="none" usesdiagramusefillcolor="0" type="511" totalcountb="2" linewidth="0" widgetbid="RXqBshUB41L5" linecolor="#000000" xmi.id="jpx2Co5CY9GC" widgetaid="HSy87jRVwqsY" seqnum="" totalcounta="2">
<linepath layout="Polyline">
<startpoint starty="-579" startx="-1224"/>
<endpoint endx="-1407.5" endy="-649"/>
<point y="-649" x="-1224"/>
</linepath>
</assocwidget>
<assocwidget usesdiagramfillcolor="1" fillcolor="none" indexa="1" font="Sans Serif,9,-1,5,50,0,0,0,0,0" usefillcolor="1" indexb="1" textcolor="none" usesdiagramusefillcolor="1" type="512" totalcountb="2" linewidth="0" widgetbid="RXqBshUB41L5" linecolor="#000000" xmi.id="xfmTo0d7U3Co" widgetaid="Tz06QOf0xEHX" seqnum="" totalcounta="2">
<linepath layout="Polyline">
<startpoint starty="-651.5" startx="-1577"/>
<endpoint endx="-1500.5" endy="-651.5"/>
</linepath>
</assocwidget>
<assocwidget usesdiagramfillcolor="0" fillcolor="#ffff00" indexa="1" font="Sans Serif,9,-1,5,50,0,0,0,0,0" usefillcolor="1" indexb="1" textcolor="none" usesdiagramusefillcolor="1" type="511" totalcountb="2" linewidth="0" widgetbid="dqWyyHKwPkeW" linecolor="#000000" xmi.id="roUjSuB43yq5" widgetaid="yAQh9XwiuMkg" seqnum="" totalcounta="2">
<linepath layout="Polyline">
<startpoint starty="-319" startx="-1741"/>
<endpoint endx="-1674" endy="-370"/>
</linepath>
</assocwidget>
<assocwidget usesdiagramfillcolor="1" fillcolor="none" indexa="1" font="Sans Serif,9,-1,5,50,0,0,0,0,0" usefillcolor="1" indexb="1" textcolor="none" usesdiagramusefillcolor="1" type="511" totalcountb="2" linewidth="0" widgetbid="dqWyyHKwPkeW" linecolor="#000000" xmi.id="up5vlwzBogrF" widgetaid="ZPS2o7GDkc5b" seqnum="" totalcounta="2">
<linepath layout="Polyline">
<startpoint starty="-410" startx="-1746"/>
<endpoint endx="-1674" endy="-410"/>
</linepath>
</assocwidget>
<assocwidget usesdiagramfillcolor="0" fillcolor="#ffff00" indexa="1" font="Sans Serif,9,-1,5,50,0,0,0,0,0" usefillcolor="1" indexb="1" textcolor="none" usesdiagramusefillcolor="1" type="512" totalcountb="2" linewidth="0" widgetbid="dqWyyHKwPkeW" linecolor="#000000" xmi.id="EZF1F7EEwgSu" widgetaid="Tz06QOf0xEHX" seqnum="" totalcounta="2">
<linepath layout="Polyline">
<startpoint starty="-614" startx="-1652"/>
<endpoint endx="-1652" endy="-410"/>
</linepath>
</assocwidget>
<assocwidget usesdiagramfillcolor="1" fillcolor="none" indexa="1" font="Sans Serif,9,-1,5,50,0,0,0,0,0" usefillcolor="1" indexb="1" textcolor="none" usesdiagramusefillcolor="0" type="512" totalcountb="2" linewidth="0" widgetbid="dqWyyHKwPkeW" linecolor="#000000" xmi.id="Mm0rT2YFGUvA" widgetaid="mGviuNaRvQvK" seqnum="" totalcounta="2">
<linepath layout="Polyline">
<startpoint starty="-312" startx="-1546"/>
<endpoint endx="-1634" endy="-370"/>
</linepath>
</assocwidget>
<assocwidget usesdiagramfillcolor="0" fillcolor="#ffff00" indexa="1" font="Sans Serif,9,-1,5,50,0,0,0,0,0" usefillcolor="1" indexb="1" textcolor="none" usesdiagramusefillcolor="0" type="502" totalcountb="2" linewidth="0" widgetbid="dqWyyHKwPkeW" linecolor="#000000" xmi.id="80aOSVWFy4yp" widgetaid="qVP8MjpaiUjw" seqnum="" totalcounta="2">
<linepath layout="Polyline">
<startpoint starty="-410" startx="-1550"/>
<endpoint endx="-1634" endy="-410"/>
</linepath>
</assocwidget>
</associations>
</diagram>
</diagrams>
</XMI.extension>
</UML:Model>
<UML:Model isRoot="false" isSpecification="false" namespace="m1" name="Deployment View" isAbstract="false" isLeaf="false" xmi.id="Deployment View" visibility="public">
<UML:Namespace.ownedElement/>
</UML:Model>
<UML:Model isRoot="false" isSpecification="false" namespace="m1" name="Entity Relationship Model" isAbstract="false" isLeaf="false" xmi.id="Entity Relationship Model" visibility="public">
<UML:Namespace.ownedElement/>
</UML:Model>
</UML:Namespace.ownedElement>
</UML:Model>
</XMI.content>
<XMI.extensions xmi.extender="umbrello">
<docsettings uniqueid="wLA7xmMizVkY" viewid="SFlPQuwezjV1" documentation=""/>
<listview>
<listitem id="Views" open="1" type="800">
<listitem id="Component View" open="1" type="821">
<listitem id="SFlPQuwezjV1" label="component diagram" open="0" type="819"/>
<listitem id="mGviuNaRvQvK" open="1" type="822"/>
<listitem id="Tz06QOf0xEHX" open="1" type="822"/>
<listitem id="IsIXtH00UPZi" open="1" type="822"/>
<listitem id="qVP8MjpaiUjw" open="1" type="822"/>
<listitem id="2X1nlev04t8B" open="1" type="822"/>
<listitem id="ZPS2o7GDkc5b" open="1" type="822"/>
<listitem id="HSy87jRVwqsY" open="1" type="822"/>
<listitem id="yAQh9XwiuMkg" open="1" type="822"/>
<listitem id="1TAcIp7NVdvX" open="1" type="822"/>
</listitem>
<listitem id="Deployment View" open="1" type="827"/>
<listitem id="Entity Relationship Model" open="1" type="836"/>
<listitem id="Logical View" open="1" type="801">
<listitem id="RXqBshUB41L5" open="1" type="817">
<listitem id="7FOYGyKLJkjG" open="0" type="815"/>
<listitem id="wViGJvmJF1zV" open="0" type="815"/>
<listitem id="2fGeoj3czd3G" open="0" type="815"/>
<listitem id="q8oPwCisiO61" open="0" type="815"/>
</listitem>
<listitem id="J1rdJrVlcu5U" label="class diagram" open="0" type="807"/>
<listitem id="dqWyyHKwPkeW" open="1" type="817"/>
<listitem id="Datatypes" open="0" type="830">
<listitem id="HU1uO6O1JAZP" open="1" type="829"/>
<listitem id="XVF672bO1S1I" open="1" type="829"/>
<listitem id="hc0i20yJS0Dp" open="1" type="829"/>
<listitem id="UI3ER3SwXh1e" open="1" type="829"/>
<listitem id="fCoa6Ljfk80G" open="1" type="829"/>
<listitem id="pt2Mb3yGdzxf" open="1" type="829"/>
<listitem id="6aqNkOnEgoR7" open="1" type="829"/>
<listitem id="abbIcwjz5O41" open="1" type="829"/>
<listitem id="xvyPvAC0i1NS" open="1" type="829"/>
<listitem id="E7nr4kW1fSOb" open="1" type="829"/>
<listitem id="P8f5w6BmxD8W" open="1" type="829"/>
</listitem>
</listitem>
<listitem id="Use Case View" open="1" type="802"/>
</listitem>
</listview>
<codegeneration>
<codegenerator language="C++"/>
</codegeneration>
</XMI.extensions>
</XMI>

@ -1,12 +0,0 @@
<link type="text/css" rel="stylesheet" href="{{ context }}/js/jsgrid/jsgrid.min.css" />
<link type="text/css" rel="stylesheet" href="{{ context }}/js/jsgrid/jsgrid-theme.min.css" />
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
<script src="{{ context }}/static/js/jsgrid.js"></script>
<script src="{{ context }}/static/js/jquery/jquery.min.js"></script>
<title></title>
<body>
<div class="caption">
<div class="left">Process Monitoring</div>
</div>
</body>

@ -0,0 +1,248 @@
!function ($) {
/* CHECKBOX PUBLIC CLASS DEFINITION
* ============================== */
var Checkbox = function (element, options) {
this.init(element, options);
}
Checkbox.prototype = {
constructor: Checkbox
, init: function (element, options) {
var $el = this.$element = $(element)
this.options = $.extend({}, $.fn.checkbox.defaults, options);
$el.before(this.options.template);
this.setState();
}
, setState: function () {
var $el = this.$element
, $parent = $el.closest('.checkbox');
$el.prop('disabled') && $parent.addClass('disabled');
$el.prop('checked') && $parent.addClass('checked');
}
, toggle: function () {
var ch = 'checked'
, $el = this.$element
, $parent = $el.closest('.checkbox')
, checked = $el.prop(ch)
, e = $.Event('toggle')
if ($el.prop('disabled') == false) {
$parent.toggleClass(ch) && checked ? $el.removeAttr(ch) : $el.prop(ch, ch);
$el.trigger(e).trigger('change');
}
}
, setCheck: function (option) {
var d = 'disabled'
, ch = 'checked'
, $el = this.$element
, $parent = $el.closest('.checkbox')
, checkAction = option == 'check' ? true : false
, e = $.Event(option)
$parent[checkAction ? 'addClass' : 'removeClass' ](ch) && checkAction ? $el.prop(ch, ch) : $el.removeAttr(ch);
$el.trigger(e).trigger('change');
}
}
/* CHECKBOX PLUGIN DEFINITION
* ======================== */
var old = $.fn.checkbox
$.fn.checkbox = function (option) {
return this.each(function () {
var $this = $(this)
, data = $this.data('checkbox')
, options = $.extend({}, $.fn.checkbox.defaults, $this.data(), typeof option == 'object' && option);
if (!data) $this.data('checkbox', (data = new Checkbox(this, options)));
if (option == 'toggle') data.toggle()
if (option == 'check' || option == 'uncheck') data.setCheck(option)
else if (option) data.setState();
});
}
$.fn.checkbox.defaults = {
template: '<span class="icons"><span class="first-icon fa fa-square fa-base"></span><span class="second-icon fa fa-check-square fa-base"></span></span>'
}
/* CHECKBOX NO CONFLICT
* ================== */
$.fn.checkbox.noConflict = function () {
$.fn.checkbox = old;
return this;
}
/* CHECKBOX DATA-API
* =============== */
$(document).on('click.checkbox.data-api', '[data-toggle^=checkbox], .checkbox', function (e) {
var $checkbox = $(e.target);
if (e.target.tagName != "A") {
e && e.preventDefault() && e.stopPropagation();
if (!$checkbox.hasClass('checkbox')) $checkbox = $checkbox.closest('.checkbox');
$checkbox.find(':checkbox').checkbox('toggle');
}
});
$(function () {
$('input[type="checkbox"]').each(function () {
var $checkbox = $(this);
$checkbox.checkbox();
});
});
}(window.jQuery);
/* =============================================================
* flatui-radio v0.0.3
* ============================================================ */
!function ($) {
/* RADIO PUBLIC CLASS DEFINITION
* ============================== */
var Radio = function (element, options) {
this.init(element, options);
}
Radio.prototype = {
constructor: Radio
, init: function (element, options) {
var $el = this.$element = $(element)
this.options = $.extend({}, $.fn.radio.defaults, options);
$el.before(this.options.template);
this.setState();
}
, setState: function () {
var $el = this.$element
, $parent = $el.closest('.radio');
$el.prop('disabled') && $parent.addClass('disabled');
$el.prop('checked') && $parent.addClass('checked');
}
, toggle: function () {
var d = 'disabled'
, ch = 'checked'
, $el = this.$element
, checked = $el.prop(ch)
, $parent = $el.closest('.radio')
, $parentWrap = $el.closest('form').length ? $el.closest('form') : $el.closest('body')
, $elemGroup = $parentWrap.find(':radio[name="' + $el.attr('name') + '"]')
, e = $.Event('toggle')
if ($el.prop(d) == false) {
$elemGroup.not($el).each(function () {
var $el = $(this)
, $parent = $(this).closest('.radio');
if ($el.prop(d) == false) {
$parent.removeClass(ch) && $el.removeAttr(ch).trigger('change');
}
});
if (checked == false) $parent.addClass(ch) && $el.prop(ch, true);
$el.trigger(e);
if (checked !== $el.prop(ch)) {
$el.trigger('change');
}
}
}
, setCheck: function (option) {
var ch = 'checked'
, $el = this.$element
, $parent = $el.closest('.radio')
, checkAction = option == 'check' ? true : false
, checked = $el.prop(ch)
, $parentWrap = $el.closest('form').length ? $el.closest('form') : $el.closest('body')
, $elemGroup = $parentWrap.find(':radio[name="' + $el['attr']('name') + '"]')
, e = $.Event(option)
$elemGroup.not($el).each(function () {
var $el = $(this)
, $parent = $(this).closest('.radio');
$parent.removeClass(ch) && $el.removeAttr(ch);
});
$parent[checkAction ? 'addClass' : 'removeClass'](ch) && checkAction ? $el.prop(ch, ch) : $el.removeAttr(ch);
$el.trigger(e);
if (checked !== $el.prop(ch)) {
$el.trigger('change');
}
}
}
/* RADIO PLUGIN DEFINITION
* ======================== */
var old = $.fn.radio
$.fn.radio = function (option) {
return this.each(function () {
var $this = $(this)
, data = $this.data('radio')
, options = $.extend({}, $.fn.radio.defaults, $this.data(), typeof option == 'object' && option);
if (!data) $this.data('radio', (data = new Radio(this, options)));
if (option == 'toggle') data.toggle()
if (option == 'check' || option == 'uncheck') data.setCheck(option)
else if (option) data.setState();
});
}
$.fn.radio.defaults = {
template: '<span class="icons"><span class="first-icon fa fa-circle-o fa-base"></span><span class="second-icon fa fa-dot-circle-o fa-base"></span></span>'
}
/* RADIO NO CONFLICT
* ================== */
$.fn.radio.noConflict = function () {
$.fn.radio = old;
return this;
}
/* RADIO DATA-API
* =============== */
$(document).on('click.radio.data-api', '[data-toggle^=radio], .radio', function (e) {
var $radio = $(e.target);
e && e.preventDefault() && e.stopPropagation();
if (!$radio.hasClass('radio')) $radio = $radio.closest('.radio');
$radio.find(':radio').radio('toggle');
});
$(function () {
$('input[type="radio"]').each(function () {
var $radio = $(this);
$radio.radio();
});
});
}(window.jQuery);

@ -0,0 +1,404 @@
/*
Creative Tim Modifications
Lines: 239, 240 was changed from top: 5px to top: 50% and we added margin-top: -13px. In this way the close button will be aligned vertically
Line:242 - modified when the icon is set, we add the class "alert-with-icon", so there will be enough space for the icon.
*/
/*
* Project: Bootstrap Notify = v3.1.5
* Description: Turns standard Bootstrap alerts into "Growl-like" notifications.
* Author: Mouse0270 aka Robert McIntosh
* License: MIT License
* Website: https://github.com/mouse0270/bootstrap-growl
*/
/* global define:false, require: false, jQuery:false */
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node/CommonJS
factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
// Create the defaults once
var defaults = {
element: 'body',
position: null,
type: "info",
allow_dismiss: true,
allow_duplicates: true,
newest_on_top: false,
showProgressbar: false,
placement: {
from: "top",
align: "right"
},
offset: 20,
spacing: 10,
z_index: 1031,
delay: 5000,
timer: 1000,
url_target: '_blank',
mouse_over: null,
animate: {
enter: 'animated fadeInDown',
exit: 'animated fadeOutUp'
},
onShow: null,
onShown: null,
onClose: null,
onClosed: null,
icon_type: 'class',
template: '<div data-notify="container" class="col-xs-11 col-sm-4 alert alert-{0}" role="alert"><button type="button" aria-hidden="true" class="close" data-notify="dismiss">&times;</button><span data-notify="icon"></span> <span data-notify="title">{1}</span> <span data-notify="message">{2}</span><div class="progress" data-notify="progressbar"><div class="progress-bar progress-bar-{0}" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;"></div></div><a href="{3}" target="{4}" data-notify="url"></a></div>'
};
String.format = function () {
var str = arguments[0];
for (var i = 1; i < arguments.length; i++) {
str = str.replace(RegExp("\\{" + (i - 1) + "\\}", "gm"), arguments[i]);
}
return str;
};
function isDuplicateNotification(notification) {
var isDupe = false;
$('[data-notify="container"]').each(function (i, el) {
var $el = $(el);
var title = $el.find('[data-notify="title"]').text().trim();
var message = $el.find('[data-notify="message"]').html().trim();
// The input string might be different than the actual parsed HTML string!
// (<br> vs <br /> for example)
// So we have to force-parse this as HTML here!
var isSameTitle = title === $("<div>" + notification.settings.content.title + "</div>").html().trim();
var isSameMsg = message === $("<div>" + notification.settings.content.message + "</div>").html().trim();
var isSameType = $el.hasClass('alert-' + notification.settings.type);
if (isSameTitle && isSameMsg && isSameType) {
//we found the dupe. Set the var and stop checking.
isDupe = true;
}
return !isDupe;
});
return isDupe;
}
function Notify(element, content, options) {
// Setup Content of Notify
var contentObj = {
content: {
message: typeof content === 'object' ? content.message : content,
title: content.title ? content.title : '',
icon: content.icon ? content.icon : '',
url: content.url ? content.url : '#',
target: content.target ? content.target : '-'
}
};
options = $.extend(true, {}, contentObj, options);
this.settings = $.extend(true, {}, defaults, options);
this._defaults = defaults;
if (this.settings.content.target === "-") {
this.settings.content.target = this.settings.url_target;
}
this.animations = {
start: 'webkitAnimationStart oanimationstart MSAnimationStart animationstart',
end: 'webkitAnimationEnd oanimationend MSAnimationEnd animationend'
};
if (typeof this.settings.offset === 'number') {
this.settings.offset = {
x: this.settings.offset,
y: this.settings.offset
};
}
//if duplicate messages are not allowed, then only continue if this new message is not a duplicate of one that it already showing
if (this.settings.allow_duplicates || (!this.settings.allow_duplicates && !isDuplicateNotification(this))) {
this.init();
}
}
$.extend(Notify.prototype, {
init: function () {
var self = this;
this.buildNotify();
if (this.settings.content.icon) {
this.setIcon();
}
if (this.settings.content.url != "#") {
this.styleURL();
}
this.styleDismiss();
this.placement();
this.bind();
this.notify = {
$ele: this.$ele,
update: function (command, update) {
var commands = {};
if (typeof command === "string") {
commands[command] = update;
} else {
commands = command;
}
for (var cmd in commands) {
switch (cmd) {
case "type":
this.$ele.removeClass('alert-' + self.settings.type);
this.$ele.find('[data-notify="progressbar"] > .progress-bar').removeClass('progress-bar-' + self.settings.type);
self.settings.type = commands[cmd];
this.$ele.addClass('alert-' + commands[cmd]).find('[data-notify="progressbar"] > .progress-bar').addClass('progress-bar-' + commands[cmd]);
break;
case "icon":
var $icon = this.$ele.find('[data-notify="icon"]');
if (self.settings.icon_type.toLowerCase() === 'class') {
$icon.removeClass(self.settings.content.icon).addClass(commands[cmd]);
} else {
if (!$icon.is('img')) {
$icon.find('img');
}
$icon.attr('src', commands[cmd]);
}
break;
case "progress":
var newDelay = self.settings.delay - (self.settings.delay * (commands[cmd] / 100));
this.$ele.data('notify-delay', newDelay);
this.$ele.find('[data-notify="progressbar"] > div').attr('aria-valuenow', commands[cmd]).css('width', commands[cmd] + '%');
break;
case "url":
this.$ele.find('[data-notify="url"]').attr('href', commands[cmd]);
break;
case "target":
this.$ele.find('[data-notify="url"]').attr('target', commands[cmd]);
break;
default:
this.$ele.find('[data-notify="' + cmd + '"]').html(commands[cmd]);
}
}
var posX = this.$ele.outerHeight() + parseInt(self.settings.spacing) + parseInt(self.settings.offset.y);
self.reposition(posX);
},
close: function () {
self.close();
}
};
},
buildNotify: function () {
var content = this.settings.content;
this.$ele = $(String.format(this.settings.template, this.settings.type, content.title, content.message, content.url, content.target));
this.$ele.attr('data-notify-position', this.settings.placement.from + '-' + this.settings.placement.align);
if (!this.settings.allow_dismiss) {
this.$ele.find('[data-notify="dismiss"]').css('display', 'none');
}
if ((this.settings.delay <= 0 && !this.settings.showProgressbar) || !this.settings.showProgressbar) {
this.$ele.find('[data-notify="progressbar"]').remove();
}
},
setIcon: function () {
this.$ele.addClass('alert-with-icon');
if (this.settings.icon_type.toLowerCase() === 'class') {
this.$ele.find('[data-notify="icon"]').addClass(this.settings.content.icon);
} else {
if (this.$ele.find('[data-notify="icon"]').is('img')) {
this.$ele.find('[data-notify="icon"]').attr('src', this.settings.content.icon);
} else {
this.$ele.find('[data-notify="icon"]').append('<img src="' + this.settings.content.icon + '" alt="Notify Icon" />');
}
}
},
styleDismiss: function () {
this.$ele.find('[data-notify="dismiss"]').css({
position: 'absolute',
right: '10px',
top: '50%',
marginTop: '-13px',
zIndex: this.settings.z_index + 2
});
},
styleURL: function () {
this.$ele.find('[data-notify="url"]').css({
backgroundImage: 'url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)',
height: '100%',
left: 0,
position: 'absolute',
top: 0,
width: '100%',
zIndex: this.settings.z_index + 1
});
},
placement: function () {
var self = this,
offsetAmt = this.settings.offset.y,
css = {
display: 'inline-block',
margin: '0px auto',
position: this.settings.position ? this.settings.position : (this.settings.element === 'body' ? 'fixed' : 'absolute'),
transition: 'all .5s ease-in-out',
zIndex: this.settings.z_index
},
hasAnimation = false,
settings = this.settings;
$('[data-notify-position="' + this.settings.placement.from + '-' + this.settings.placement.align + '"]:not([data-closing="true"])').each(function () {
offsetAmt = Math.max(offsetAmt, parseInt($(this).css(settings.placement.from)) + parseInt($(this).outerHeight()) + parseInt(settings.spacing));
});
if (this.settings.newest_on_top === true) {
offsetAmt = this.settings.offset.y;
}
css[this.settings.placement.from] = offsetAmt + 'px';
switch (this.settings.placement.align) {
case "left":
case "right":
css[this.settings.placement.align] = this.settings.offset.x + 'px';
break;
case "center":
css.left = 0;
css.right = 0;
break;
}
this.$ele.css(css).addClass(this.settings.animate.enter);
$.each(Array('webkit-', 'moz-', 'o-', 'ms-', ''), function (index, prefix) {
self.$ele[0].style[prefix + 'AnimationIterationCount'] = 1;
});
$(this.settings.element).append(this.$ele);
if (this.settings.newest_on_top === true) {
offsetAmt = (parseInt(offsetAmt) + parseInt(this.settings.spacing)) + this.$ele.outerHeight();
this.reposition(offsetAmt);
}
if ($.isFunction(self.settings.onShow)) {
self.settings.onShow.call(this.$ele);
}
this.$ele.one(this.animations.start, function () {
hasAnimation = true;
}).one(this.animations.end, function () {
if ($.isFunction(self.settings.onShown)) {
self.settings.onShown.call(this);
}
});
setTimeout(function () {
if (!hasAnimation) {
if ($.isFunction(self.settings.onShown)) {
self.settings.onShown.call(this);
}
}
}, 600);
},
bind: function () {
var self = this;
this.$ele.find('[data-notify="dismiss"]').on('click', function () {
self.close();
});
this.$ele.mouseover(function () {
$(this).data('data-hover', "true");
}).mouseout(function () {
$(this).data('data-hover', "false");
});
this.$ele.data('data-hover', "false");
if (this.settings.delay > 0) {
self.$ele.data('notify-delay', self.settings.delay);
var timer = setInterval(function () {
var delay = parseInt(self.$ele.data('notify-delay')) - self.settings.timer;
if ((self.$ele.data('data-hover') === 'false' && self.settings.mouse_over === "pause") || self.settings.mouse_over != "pause") {
var percent = ((self.settings.delay - delay) / self.settings.delay) * 100;
self.$ele.data('notify-delay', delay);
self.$ele.find('[data-notify="progressbar"] > div').attr('aria-valuenow', percent).css('width', percent + '%');
}
if (delay <= -(self.settings.timer)) {
clearInterval(timer);
self.close();
}
}, self.settings.timer);
}
},
close: function () {
var self = this,
posX = parseInt(this.$ele.css(this.settings.placement.from)),
hasAnimation = false;
this.$ele.data('closing', 'true').addClass(this.settings.animate.exit);
self.reposition(posX);
if ($.isFunction(self.settings.onClose)) {
self.settings.onClose.call(this.$ele);
}
this.$ele.one(this.animations.start, function () {
hasAnimation = true;
}).one(this.animations.end, function () {
$(this).remove();
if ($.isFunction(self.settings.onClosed)) {
self.settings.onClosed.call(this);
}
});
setTimeout(function () {
if (!hasAnimation) {
self.$ele.remove();
if (self.settings.onClosed) {
self.settings.onClosed(self.$ele);
}
}
}, 600);
},
reposition: function (posX) {
var self = this,
notifies = '[data-notify-position="' + this.settings.placement.from + '-' + this.settings.placement.align + '"]:not([data-closing="true"])',
$elements = this.$ele.nextAll(notifies);
if (this.settings.newest_on_top === true) {
$elements = this.$ele.prevAll(notifies);
}
$elements.each(function () {
$(this).css(self.settings.placement.from, posX);
posX = (parseInt(posX) + parseInt(self.settings.spacing)) + $(this).outerHeight();
});
}
});
$.notify = function (content, options) {
var plugin = new Notify(this, content, options);
return plugin.notify;
};
$.notifyDefaults = function (options) {
defaults = $.extend(true, {}, defaults, options);
return defaults;
};
$.notifyClose = function (command) {
if (typeof command === "undefined" || command === "all") {
$('[data-notify]').find('[data-notify="dismiss"]').trigger('click');
} else {
$('[data-notify-position="' + command + '"]').find('[data-notify="dismiss"]').trigger('click');
}
};
}));

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,216 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta content="origin" name="referrer" />
<link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/frameworks-d48d0c441ed0ab66aa7d582c5aaf762f4a1eef9a915871a36ddb07e71b01ffb2.css" media="all" rel="stylesheet" />
<link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/github-eceee2011dedd755b4dda5f1d5d1e21b21898ea894ef433b5ac3113bbae89a6e.css" media="all" rel="stylesheet" />
<link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/site-7f1a41ba2b363d8328a1603010c1c34aa7da36bd92ed8693a262fc5b703f2b10.css" media="all" rel="stylesheet" />
<meta name="viewport" content="width=device-width">
<title>Sign in to GitHub · GitHub</title>
<link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub">
<link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub">
<meta property="fb:app_id" content="1401488693436528">
<meta property="og:url" content="https://github.com">
<meta property="og:site_name" content="GitHub">
<meta property="og:title" content="Build software better, together">
<meta property="og:description" content="GitHub is where people build software. More than 22 million people use GitHub to discover, fork, and contribute to over 60 million projects.">
<meta property="og:image" content="https://assets-cdn.github.com/images/modules/open_graph/github-logo.png">
<meta property="og:image:type" content="image/png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="1200">
<meta property="og:image" content="https://assets-cdn.github.com/images/modules/open_graph/github-mark.png">
<meta property="og:image:type" content="image/png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="620">
<meta property="og:image" content="https://assets-cdn.github.com/images/modules/open_graph/github-octocat.png">
<meta property="og:image:type" content="image/png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="620">
<link rel="assets" href="https://assets-cdn.github.com/">
<meta name="pjax-timeout" content="1000">
<meta name="request-id" content="F4D1:0758:104FC4A:1870ADF:5939D212" data-pjax-transient>
<meta name="selected-link" value="/login" data-pjax-transient>
<meta name="google-site-verification" content="KT5gs8h0wvaagLKAVWq8bbeNwnZZK1r1XQysX3xurLU">
<meta name="google-site-verification" content="ZzhVyEFwb7w3e0-uOTltm8Jsck2F5StVihD0exw2fsA">
<meta name="google-analytics" content="UA-3769691-2">
<meta content="collector.githubapp.com" name="octolytics-host" /><meta content="github" name="octolytics-app-id" /><meta content="https://collector.githubapp.com/github-external/browser_event" name="octolytics-event-url" /><meta content="F4D1:0758:104FC4A:1870ADF:5939D212" name="octolytics-dimension-request_id" /><meta content="iad" name="octolytics-dimension-region_edge" /><meta content="iad" name="octolytics-dimension-region_render" />
<meta content="true" data-pjax-transient="true" name="analytics-location-query-strip" />
<meta class="js-ga-set" name="dimension1" content="Logged Out">
<meta name="hostname" content="github.com">
<meta name="user-login" content="">
<meta name="expected-hostname" content="github.com">
<meta name="js-proxy-site-detection-payload" content="YzUxN2E0MzU5NThkYzJjMzJhNmI3MTRlYzg4M2NmNzMxOGNlYmY4OWRmZGExNjAwZWQwYjVhZTQ4OGZhZTgxY3x7InJlbW90ZV9hZGRyZXNzIjoiNzUuMTQ5LjEwMC4yNTIiLCJyZXF1ZXN0X2lkIjoiRjREMTowNzU4OjEwNEZDNEE6MTg3MEFERjo1OTM5RDIxMiIsInRpbWVzdGFtcCI6MTQ5Njk2MTU1NCwiaG9zdCI6ImdpdGh1Yi5jb20ifQ==">
<meta name="html-safe-nonce" content="f53b182df68775bfd599d2db2b3644f6f57f3d6c">
<meta http-equiv="x-pjax-version" content="4b86b6b789ca74deb1b3578459c44709">
<meta name="description" content="GitHub is where people build software. More than 22 million people use GitHub to discover, fork, and contribute to over 60 million projects.">
<link rel="canonical" href="https://github.com/login" data-pjax-transient>
<meta name="browser-stats-url" content="https://api.github.com/_private/browser/stats">
<meta name="browser-errors-url" content="https://api.github.com/_private/browser/errors">
<link rel="mask-icon" href="https://assets-cdn.github.com/pinned-octocat.svg" color="#000000">
<link rel="icon" type="image/x-icon" href="https://assets-cdn.github.com/favicon.ico">
<meta name="theme-color" content="#1e2327">
</head>
<body class="logged-out env-production session-authentication page-responsive min-width-0">
<div class="position-relative js-header-wrapper ">
<a href="#start-of-content" tabindex="1" class="accessibility-aid js-skip-to-content">Skip to content</a>
<div id="js-pjax-loader-bar" class="pjax-loader-bar"><div class="progress"></div></div>
<div class="header header-logged-out width-full pt-5 pb-4" role="banner">
<div class="container clearfix width-full">
<a class="header-logo" href="https://github.com/" aria-label="Homepage" data-ga-click="(Logged out) Header, go to homepage, icon:logo-wordmark">
<svg aria-hidden="true" class="octicon octicon-mark-github" height="48" version="1.1" viewBox="0 0 16 16" width="48"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"/></svg>
</a>
</div>
</div>
</div>
<div id="start-of-content" class="accessibility-aid"></div>
<div role="main">
<div id="js-pjax-container" data-pjax-container>
<div class="auth-form px-3" id="login">
<!-- '"` --><!-- </textarea></xmp> --></option></form><form accept-charset="UTF-8" action="/session" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /><input name="authenticity_token" type="hidden" value="7XZSonP0W9pDyZpVrbdXWHCiRNfnCXldeVF5M83at4CARFuqW64xs69pW4t4+L8Uumbz21TkBxVMPfv/xF3/aw==" /></div> <div class="auth-form-header p-0">
<h1>Sign in to GitHub</h1>
</div>
<div id="js-flash-container">
</div>
<div class="auth-form-body mt-3">
<label for="login_field">
Username or email address
</label>
<input autocapitalize="off" autocorrect="off" autofocus="autofocus" class="form-control input-block" id="login_field" name="login" tabindex="1" type="text" />
<label for="password">
Password <a href="/password_reset" class="label-link">Forgot password?</a>
</label>
<input class="form-control form-control input-block" id="password" name="password" tabindex="2" type="password" />
<input class="btn btn-primary btn-block" data-disable-with="Signing in…" name="commit" tabindex="3" type="submit" value="Sign in" />
</div>
</form>
<p class="create-account-callout mt-3">
New to GitHub?
<a href="/join?return_to=https%3A%2F%2Fgithub.com%2Fgionkunz%2Fchartist-js%2Fedit%2Fdevelop%2Fdist%2Fchartist.min.js.map&amp;source=login" data-ga-click="Sign in, switch to sign up">Create an account</a>.
</p>
</div>
</div>
<div class="modal-backdrop js-touch-events"></div>
</div>
<div class="site-footer" role="contentinfo">
<ul class="site-footer-links">
<li><a href="https://github.com/site/terms" data-ga-click="Footer, go to terms, text:terms">Terms</a></li>
<li><a href="https://github.com/site/privacy" data-ga-click="Footer, go to privacy, text:privacy">Privacy</a></li>
<li><a href="https://github.com/security" data-ga-click="Footer, go to security, text:security">Security</a></li>
<li><a href="https://github.com/contact" data-ga-click="Footer, go to contact, text:contact">Contact GitHub</a></li>
</ul>
</div>
<div id="ajax-error-message" class="ajax-error-message flash flash-error">
<svg aria-hidden="true" class="octicon octicon-alert" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M8.865 1.52c-.18-.31-.51-.5-.87-.5s-.69.19-.87.5L.275 13.5c-.18.31-.18.69 0 1 .19.31.52.5.87.5h13.7c.36 0 .69-.19.86-.5.17-.31.18-.69.01-1L8.865 1.52zM8.995 13h-2v-2h2v2zm0-3h-2V6h2v4z"/></svg>
<button type="button" class="flash-close js-flash-close js-ajax-error-dismiss" aria-label="Dismiss error">
<svg aria-hidden="true" class="octicon octicon-x" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path fill-rule="evenodd" d="M7.48 8l3.75 3.75-1.48 1.48L6 9.48l-3.75 3.75-1.48-1.48L4.52 8 .77 4.25l1.48-1.48L6 6.52l3.75-3.75 1.48 1.48z"/></svg>
</button>
You can't perform that action at this time.
</div>
<script crossorigin="anonymous" src="https://assets-cdn.github.com/assets/compat-8a4318ffea09a0cdb8214b76cf2926b9f6a0ced318a317bed419db19214c690d.js"></script>
<script crossorigin="anonymous" src="https://assets-cdn.github.com/assets/frameworks-73720f027bb317fceb118c259275da4be5efa344c246a12341a68c3168ceeaa7.js"></script>
<script async="async" crossorigin="anonymous" src="https://assets-cdn.github.com/assets/github-3ad5579f0af51ee1adcb93de64d25ce6771132f49f8044580b60743ec58d520c.js"></script>
<div class="js-stale-session-flash stale-session-flash flash flash-warn flash-banner d-none">
<svg aria-hidden="true" class="octicon octicon-alert" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M8.865 1.52c-.18-.31-.51-.5-.87-.5s-.69.19-.87.5L.275 13.5c-.18.31-.18.69 0 1 .19.31.52.5.87.5h13.7c.36 0 .69-.19.86-.5.17-.31.18-.69.01-1L8.865 1.52zM8.995 13h-2v-2h2v2zm0-3h-2V6h2v4z"/></svg>
<span class="signed-in-tab-flash">You signed in with another tab or window. <a href="">Reload</a> to refresh your session.</span>
<span class="signed-out-tab-flash">You signed out in another tab or window. <a href="">Reload</a> to refresh your session.</span>
</div>
<div class="facebox" id="facebox" style="display:none;">
<div class="facebox-popup">
<div class="facebox-content" role="dialog" aria-labelledby="facebox-header" aria-describedby="facebox-description">
</div>
<button type="button" class="facebox-close js-facebox-close" aria-label="Close modal">
<svg aria-hidden="true" class="octicon octicon-x" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path fill-rule="evenodd" d="M7.48 8l3.75 3.75-1.48 1.48L6 9.48l-3.75 3.75-1.48-1.48L4.52 8 .77 4.25l1.48-1.48L6 6.52l3.75-3.75 1.48 1.48z"/></svg>
</button>
</div>
</div>
</body>
</html>

File diff suppressed because one or more lines are too long

@ -1,573 +1,192 @@
type = ['','info','success','warning','danger'];
dashboard = {
initPickColor: function(){
$('.pick-class-label').click(function(){
var new_class = $(this).attr('new-class');
var old_class = $('#display-buttons').attr('data-class');
var display_div = $('#display-buttons');
if(display_div.length) {
var display_buttons = display_div.find('.btn');
display_buttons.removeClass(old_class);
display_buttons.addClass(new_class);
display_div.attr('data-class', new_class);
}
});
},
initChartist: function(){
var getData = $.get('/1/app/usage/trend');
getData.done(function(results) {
var data = JSON.parse(results)
var node = data['apps@michaels-MBP'];
var app = node['chrome'];
var cpu = app['cpu'];
var memory_used = app['memory_used'];
console.log('data...',data)
console.log('node...',node)
console.log('app...',app)
console.log('cpu...',cpu)
console.log('memory_used...', memory_used)
// monitoring apps chart
var dataChart = {
labels: ['24','23','22','21','20','19','18','17','16','15','14','13','12','11','10','9','8','7','6','5','4','3','2','1' ],
series: [cpu, memory_used, [1,2,3,5], ] // TODO: Check the order, the graph is by index not name.
};
dataChartArray = dataChart.series
var maxlist = dataChartArray.map(dataChartArray => Math.max.apply(null, dataChartArray));
maxNum = Math.max.apply(null, maxlist)
var optionsChart = {
lineSmooth: false,
low: 0,
high: maxNum + 1,
showArea: true,
height: "245px",
axisX: {
showGrid: false,
},
lineSmooth: Chartist.Interpolation.simple({
divisor: 1
}),
showLine: true,
showPoint: false,
};
var responsiveChart = [
['screen and (max-width: 640px)', {
axisX: {
labelInterpolationFnc: function (value) {
return value[0];
}
}
}]
];
Chartist.Line('#chartHours', dataChart, optionsChart, responsiveChart);
// cpu and memory --------------------------
var data = {
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
series: [cpu, memory_used]
};
var options = {
seriesBarDistance: 10,
axisX: {
showGrid: false
},
height: "245px"
};
var responsiveOptions = [
['screen and (max-width: 640px)', {
seriesBarDistance: 5,
axisX: {
labelInterpolationFnc: function (value) {
return value[0];
}
}
}]
];
Chartist.Line('#chartActivity', data, options, responsiveOptions);
var getStatus = $.get('1/get/summary/app_status');
getStatus.done(function(results) {
var data = JSON.parse(results)
let getStatusList = []
getStatusList.push(data.idle)
getStatusList.push(data.crash)
getStatusList.push(data.running)
Chartist.Pie('#chartPreferences', {
labels: getStatusList,
series: getStatusList
},{donut:true});
}) /// end getStatus
})
},
// End chartist function
initGoogleMaps: function(){
var myLatlng = new google.maps.LatLng(40.748817, -73.985428);
var mapOptions = {
zoom: 13,
center: myLatlng,
scrollwheel: false, //we disable de scroll over the map, it is a really annoing when you scroll through page
styles: [{"featureType":"water","stylers":[{"saturation":43},{"lightness":-11},{"hue":"#0088ff"}]},{"featureType":"road","elementType":"geometry.fill","stylers":[{"hue":"#ff0000"},{"saturation":-100},{"lightness":99}]},{"featureType":"road","elementType":"geometry.stroke","stylers":[{"color":"#808080"},{"lightness":54}]},{"featureType":"landscape.man_made","elementType":"geometry.fill","stylers":[{"color":"#ece2d9"}]},{"featureType":"poi.park","elementType":"geometry.fill","stylers":[{"color":"#ccdca1"}]},{"featureType":"road","elementType":"labels.text.fill","stylers":[{"color":"#767676"}]},{"featureType":"road","elementType":"labels.text.stroke","stylers":[{"color":"#ffffff"}]},{"featureType":"poi","stylers":[{"visibility":"off"}]},{"featureType":"landscape.natural","elementType":"geometry.fill","stylers":[{"visibility":"on"},{"color":"#b8cb93"}]},{"featureType":"poi.park","stylers":[{"visibility":"on"}]},{"featureType":"poi.sports_complex","stylers":[{"visibility":"on"}]},{"featureType":"poi.medical","stylers":[{"visibility":"on"}]},{"featureType":"poi.business","stylers":[{"visibility":"simplified"}]}]
}
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
var marker = new google.maps.Marker({
position: myLatlng,
title:"Hello World!"
});
// To add the marker to the map, call setMap();
marker.setMap(map);
},
showNotification: function(from, align){
color = Math.floor((Math.random() * 4) + 1);
$.notify({
icon: "ti-comment",
message: "Message."
},{
type: type[color],
timer: 4000,
placement: {
from: from,
align: align
}
});
},
var monitor = {}
monitor.processes = {}
monitor.processes.fetch = function(){
var httpclient = HttpClient.instance()
httpclient.get(HTTP_CONTEXT+'/get/processes',monitor.processes.init);
} }
monitor.processes.init = function (x) {
var r = JSON.parse(x.responseText)
monitor.processes.summary.init(r)
var keys = jx.utils.keys(r)
jx.dom.set.value('menu','')
jx.utils.patterns.visitor(keys,function(label){
var div = jx.dom.get.instance('DIV')
var frame= jx.dom.get.instance('DIV')
var i = jx.dom.get.instance('I')
i.className = 'fa fa-chevron-right left'
div.innerHTML = label
frame.data = r[label]
frame.label = label
frame.appendChild(i)
frame.appendChild(div)
frame.className = 'menu-item'
frame.onclick = function () {
monitor.processes.render(this.label, this.data);
jx.dom.set.value('trends_chart','')
//monitor.processes.trend.init(this.label)
}
jx.dom.append('menu',frame)
})
//
// Auto start the first item in the menu
// This is designed not to let the user wander or wonder what is going on
//
var nodes = jx.dom.get.children('menu')
if (nodes.length > 0) {
nodes[0].click()
} else {
//
// We should hide the panes for this
//
jx.dom.hide('apps')
}
setTimeout(monitor.sandbox.init,3000)
}
/** /**
* This function renders the grid of processes being monitored, * Global information about the dashboard
* @param label label the list of processes belongs to * @TODO: Add socket handling ... it would make non-blocking updating information
* @param data dataset of a selected set of processes (works a bit like top) */
*/
monitor.processes.render = function(label,data) {
data = jx.utils.patterns.visitor(data,function(row){
var status = {"idle":'<i class="fa fa-ellipsis-h" title="IDLE"></i>',"running":'<i class="fa fa-check" title="RUNNING"></i>',"crash":'<i class="fa fa-times" title="CRASHED"></i>'}
if (!row.status.match(/class/)) {
row.status_id = row.status
row.status = status[row.status]
}
return row
})
jx.dom.set.value('latest_processes','') ;
jx.dom.set.value('latest_processes_label',label)
var options = {
width: $('#latest_processes').width(), height:'auto'
}
options.paging = true
options.pageSize = 4
options.pageIndex = 1
options.pageButtonCount = 4
options.pagerContainer = '#latest_process_pager'
options.pagerFormat= "{prev} Page {pageIndex} of {pageCount} {next}"
options.pagePrevText= '<i class="fa fa-chevron-left"></i>'
options.pageNextText= "<i class='fa fa-chevron-right small' title='Next'> </i>"
options.data = data
options.rowClass = function (item, index,evt) {
return 'small'
}
options.rowClick = function(args){
var item = args.item
var id = jx.dom.get.value('latest_processes_label')
var app = item.label
monitor.processes.trend.init(id, app)
if (item.anomaly == true) {
jx.dom.show('has_anomaly')
} else {
jx.dom.hide('has_anomaly')
}
}
options.autoload = true
options.fields = [
{ name: 'label', type: 'text', title: "Process", headercss: "small bold", css: "small"},
{ name: "cpu_usage", type: "number", title: "CPU", headercss: "small bold" , width:'64px'},
{ name: "memory_usage", type: "text", title: "Mem. Used", type: "number", headercss: "small bold" },
{ name: "proc_count", type: "number", title: "Proc Count", headercss: "small bold" },
{name:"status",type:"text",title:"Status",headercss:"small bold",align:"center", width:'64px'}
]
var grid = $('#latest_processes').jsGrid(options) ;
//
// We need to auto click the first row
$('#latest_processes').find('.jsgrid-row')[0].click()
}
monitor.processes.trend = {}
monitor.processes.trend.init = function (label,app) {
var httpclient = HttpClient.instance()
var uri = HTTP_CONTEXT+'/trends?id='+label+'&app='+encodeURIComponent(app)
httpclient.get(uri, function (x) {
var logs = JSON.parse(x.responseText)
var dom = jx.dom.get.instance('trend_info');
dom.logs = logs
jx.dom.set.value('trend_info',app)
// jx.dom.set.attribute(label,'logs',logs)
monitor.processes.trend.render(logs,null,app)
})
}
monitor.processes.trend.render = function (logs, key,label) {
// if (key == null) {
// key = 'memory_usage'
// }
// if (logs == null || label == null){
// logs = jx.dom.get.instance('trend_info').logs
// label= jx.dom.get.value('trend_info') ;
// }
var frame = $('#trends_chart')
jx.dom.set.value('trends_chart','')
var context = jx.dom.get.instance('CANVAS')
context.width = $(frame).width()
context.height= $(frame).height()
var conf = { type: 'line',responsive:true }
conf.data = {}
conf.options = { legend: { position: 'bottom' } }
conf.options.scales = {}
conf.options.scales.yAxes = [
{id:'0',scaleLabel:{display:true,labelString:'CPU & MEMORY USAGE'},ticks:{min:0,beginAtZero:true},gridLines: {display:false}},
{id:'1',position:'right',scaleLabel:{display:true,labelString:'PROCESS COUNT'},ticks:{min:0,stepSize:1,beginAtZero:true},gridLines: {display:false}}
]
conf.options.scales.xAxes = [
{
gridLines: {display:false},
time: {
format:'DD-MMM HH:mm'
}
}
]
conf.data.datasets = [ ]
var x_axis = []
var _x = {}
// var _y = {}
var cpu = {yAxisID:'0', label: 'CPU Usage (%)', data: [] ,backgroundColor:'transparent',borderColor:COLORS[187],fill:false,borderWidth:1}
var mem = {yAxisID:'0',label : 'Memory Usage(%)',data:[],backgroundColor:'transparent',borderColor:COLORS[32],fill:false,borderWidth:1}
var proc= {yAxisID:'1',label : 'Proc Count',data:[],backgroundColor:'transparent',borderColor:COLORS[542],fill:false,borderWidth:1}
var months={1:"Jan",2:"Feb",3:"Mar",4:"Apr",5:"May",6:"Jun",7:"Jul",8:"Aug",9:"Sep",10:"Oct",11:"Nov",12:"Dec"}
jx.utils.patterns.visitor(logs,function(item){
//x = new Date(item.year,item.month-1,item.day,item.hour,item.minute)
day = item.day > 9? (['0',item.day]).join(''): item.day
month = months[item.month]
x = ([month,day,item.hour+':'+item.minute]).join(' ')
y = item[key]
if (_x[x] == null ){//||(_x[x] == null && _y[y] == null)) {
_x[x] = 1
// _y[y] = 1
x_axis.push(x)
cpu.data.push({ x: x, y: item.cpu_usage })
mem.data.push({x:x,y:item.memory_usage})
proc.data.push({x:x,y:item.proc_count})
// return {x:x,y:y}
}
})
conf.data.datasets = [cpu,mem,proc]
x_axis = jx.utils.unique(x_axis)
conf.data.labels = x_axis
// console.log(conf)
jx.dom.append('trends_chart',context)
var chart = new Chart(context,conf)
}
monitor.processes.summary = {}
monitor.processes.summary.init = function(logs){
var xr = 0, xc = 0, xi = 0
var series = {}
//var colors = [COLORS[11], COLORS[1], COLORS[2]]
colors = [COLORS[11], COLORS[2], COLORS[100]]
RUNNING_COLOR = COLORS[26]
IDLE_COLOR = COLORS[100]
CRASH_COLOR=COLORS[2]
var i = 0;
var date = null;
for( label in logs ){
var rows = logs[label]
series[label] = {data:[0,0,0],label:label}
jx.utils.patterns.visitor(rows,function(item){
if (date == null) {
date = new Date(item.year,item.month,item.day)
//date = [item.day,item.month,item.year]
}
if (item.status == 'running'){
xr += 1
}else if(item.status == 'idle'){
xi += 1
}else{
xc += 1
}
})
}
var data = {labels:['Running','Crash','Idle'],datasets:[{data:[xr,xc,xi],backgroundColor:[RUNNING_COLOR,CRASH_COLOR,IDLE_COLOR/**COLORS[11],COLORS[2],COLORS[100]*/]}]}
var context = jx.dom.get.instance('CANVAS')
jx.dom.set.value('total-running', xr)
jx.dom.set.value('total-crash', xc)
jx.dom.set.value('total-idle', xi)
jx.dom.set.value('total-apps', xr + xi + xc)
jx.dom.set.value('app-summary-date', date)
jx.dom.set.value('summary_chart','')
jx.dom.append('summary_chart',context)
var conf = {}//width:50,height:40}
conf.type = 'doughnut'
conf.responsive = true
conf.data = data
conf.options = {legend:{ position:'right'},repsonsive:true}
var chart = new Chart(context,conf)
jx.dom.set.value('summary_ranking','')
context = jx.dom.get.instance('CANVAS')
jx.dom.append('summary_ranking',context)
conf = { type: 'bar', responsive: true }
conf.options={scales:{xAxes:[{gridLines: {display:false}}],yAxes:[{gridLines: {display:false},scaleLabel:{display:true,labelString:'PROCESS COUNTS'} }] }}
conf.options.legend ={position:'right'}
/*
conf.data = {labels:['Running','Idle','Crash']}
var labels = jx.utils.keys(series)
var i = 0
conf.data.datasets = jx.utils.patterns.visitor(labels,function(id){
series[id].backgroundColor = COLORS[i++]
return series[id]})
chart = new Chart(context,conf);
*/
var labels = jx.utils.keys(logs)
conf.data = { labels: labels, backgroundColor:colors }
var xr = [], xi = [], xc = [],xr_bg = [],xc_bg = [],xi_bg = []
jx.utils.patterns.visitor(labels, function (id) {
var rows = logs[id]
var index = xr.length
xr_bg[index] = RUNNING_COLOR
xi_bg[index] = IDLE_COLOR
xc_bg[index] = CRASH_COLOR
if (xr[index] == null) {
xr[index] = 0
xc[index] = 0
xi[index] = 0
}
jx.utils.patterns.visitor(logs[id], function (row) {
if (row.status.match(/running/i)) {
xr[index] += 1
} else if (row.status.match(/idle/i)) {
xi[index] += 1
} else {
xc[index] += 1
}
})
})
conf.data.datasets = [{ label: 'Running', data:xr,backgroundColor:xr_bg},{label:'Crash',data:xc,backgroundColor:xc_bg},{label:'Idle',data:xi,backgroundColor:xi_bg} ]
chart = new Chart(context, conf)
}
monitor.sandbox = {}
monitor.sandbox.init = function () {
jx.dom.hide('inspect_sandbox')
var httpclient = HttpClient.instance()
httpclient.get(HTTP_CONTEXT+'/sandbox', function (x) {
var r = JSON.parse(x.responseText)
if (r.length > 0) {
jx.dom.show('sandbox')
monitor.sandbox.render(r);
} else {
jx.dom.hide('sandbox')
}
})
}
monitor.sandbox.render = function (logs) {
months = { 1: 'Jan', 2: 'Feb', 3: 'Mar', 4: 'Apr', 5: 'May', 6: 'Jun', 7: 'Jul', 8: 'Aug', 9: 'Sep', 10: 'Oct', 11: 'Nov', 12: 'Dec' }
var d = ([logs[0].day, '-', months[logs[0].month], '-', logs[0].year, ' ', logs[0].hour, ':', logs[0].minute]).join('')
jx.dom.set.value('sandbox_date', d)
var options = { width: $('#sandbox_status').width(), height: 'auto' }
options.data = jx.utils.patterns.visitor(logs, function (item) {
if (item.value == 100) {
item.status = '<i class="fa fa-check" style="color:green"></i>'
} else {
item.status = '<i class="fa fa-download" style="color:black"></i>'
}
return item
})
options.paging = true
options.pageSize = 4
options.pageIndex = 1
options.pageButtonCount = 4
options.pagerContainer = '#folders_pager'
options.pagerFormat = "{prev} Page {pageIndex} of {pageCount} {next}"
options.pagePrevText = '<i class="fa fa-chevron-left"></i>'
options.pageNextText = "<i class='fa fa-chevron-right small' title='Next'> </i>";
options.rowClass = function (item) {
if (item.value < 70) {
return 'bad'
} else if (item.value < 100) {
return 'warning'
} else {
return 'good'
}
}
options.rowClick = function (args) {
var item = args.item;
if (item.missing.length > 0) {
var form = jx.dom.get.instance('FORM')
var dom = jx.dom.get.instance('INPUT')
dom.type = 'hidden'
dom.name = 'missing'
dom.value = JSON.stringify(item.missing)
form.action = HTTP_CONTEXT+'/download'
form.method = 'POST'
form.appendChild(dom)
form.submit()
}
}
options.fields = [
{name:"status",title:"",width:20},
{ name: 'label',title:'Virtual Environment Label',type:'text',css:'small',headercss:'small bold' },
{ name: 'value', title:'Completeness %',type: 'number', css: 'small', headercss: 'small bold' }
]
var grid = $('#sandbox_status').jsGrid(options)
jx.dom.show('inspect_sandbox')
}
monitor.folders = {}
monitor.folders.init = function () {
var httpclient = HttpClient.instance()
httpclient.get(HTTP_CONTEXT+'/folders', function (x) {
var r = JSON.parse(x.responseText)
var data = []
for (var id in r) {
var item = r[id]
// item.id = id
data = data.concat(item)
}
monitor.folders.render.init(data)
})
}
monitor.folders.search = {}
monitor.folders.search.reset = function () {
jx.dom.set.value('folder_search', '')
var data = jx.dom.get.attribute('folder_search', 'data')
monitor.folders.render.summary(data)
}
monitor.folders.search.init = function(){
var term = jx.dom.get.value('folder_search')
var data = jx.dom.get.attribute('folder_search', 'data')
term = term.replace(/\x32/g,'')
if (term.length == 0) {
monitor.folders.render.summary(data)
} else if (term.length > 0) {
data = jx.utils.patterns.visitor(data, function (row) {
if (row.id.match(term)) {
return row
}
})
monitor.folders.render.summary(data)
}
}
monitor.folders.render = {}
monitor.folders.render.init = function (data) {
jx.dom.set.attribute('folder_search','data',data)
monitor.folders.render.summary(data)
}
monitor.folders.show = {}
monitor.folders.show.plan = function () {
$('#folder_summary').slideUp(function () {
$('#folder_plan').slideDown()
})
} var g = {}
monitor.folders.show.grid = function () { g.summary = {}
$('#folder_plan').slideUp(function () { /**
$('#folder_summary').slideDown() * Initializing the top section of the dashboard (apps and folders)
})
}
/***
* This function is designed to establish a folder clean up strategy i.e :
* - We will look for anomalies given age,file size
* - We will also look for where most of the data is distributed (mode)
*/ */
monitor.folders.render.details = function (folder,data) { g.summary.factory = function (url,pointer) {
// var object = {}
// We need to normalize the data at this point so as to be able to show it all in the same chart object.url = url
// jx.math.scale x: counts, y: measure ment var observer = null
// var TIME_ELLAPSED = 2000 ;
var r = [data.age, data.size] object.callback = function (r) {
var plans = [] r = JSON.parse(r.responseText)
for (var i in r) { pointer(r)
var xy = r[i]
var mode = jx.math.mode(jx.utils.vector('x', xy))
var yvalues = jx.utils.patterns.visitor(xy, function (row) {
if (row.x == mode) {
return row.y
}
})
var sd = jx.math.sd(yvalues)
if (i == 0) {
prefix = 'age'
var mean = jx.math.mean(yvalues)
var max = (mean + (1.5 * sd))
if (mean > 30 && mean < 365) {
divide_by = 30
units = 'MONTHS'
} else if (mean > 365) {
divide_by=365
units = 'YEARS'
} else {
divide_by = 1
units = 'DAYS'
}
} else {
prefix = 'size'
var mean = jx.math.sum(yvalues)
var max = 0// (mean + (1.5 * sd))
if (mean > 1000) {
divide_by = 1000
units = 'GB'
} else {
divide_by = 1
units = 'MB'
}
} //observer.notify()
if (isNaN(mean)) {
mean = 0
}
//
// We need to assess the outliars i.e too old, too large
//
y = jx.utils.vector('y', xy)
var _mean = jx.math.mean(y)
var _sd = jx.math.sd(y)
var outlier = _mean < mean || max > (_mean + (1.5 * _sd))
plans.push({ 'label': prefix, 'max': max, 'sd': sd, 'mean': mean, 'count': yvalues.length, 'outlier': outlier }) }
jx.dom.set.value(prefix + '_count', yvalues.length) object.init = function (observer) {
jx.dom.set.value(prefix + '_value', (mean/divide_by).toFixed(2)) observer = observer
jx.dom.set.value(prefix+'_units',units)
monitor.folders.show.plan()
} var httpclient = HttpClient.instance()
//httpclient.setAsync(false)
jx.dom.set.value('folder_name', folder) httpclient.get(this.url, this.callback)
setTimeout(function(){
observer.notify()
},TIME_ELLAPSED) ;
} //observer.notify()
monitor.folders.render.summary = function (data) { }
return object
jx.dom.set.value('gridfolders', '')
var options = {
width: $('#gridfolders').width(), height:'auto'
}
options.paging = true
options.pageSize = 4
options.pageIndex = 2
options.pageButtonCount = 4
options.pagerContainer = '#folderspager'
options.pagerFormat= "{prev} Page {pageIndex} of {pageCount} {next}"
options.pagePrevText= '<i class="fa fa-chevron-left"></i>'
options.pageNextText= "<i class='fa fa-chevron-right small' title='Next'> </i>"
options.data = data
options.rowClass = function (item, index,evt) {
return 'small'
}
options.rowClick = function(args){
// var item = args.item
// age = jx.utils.patterns.visitor(item.details.age, function (row) {
// return {y:row[0],x:row[1]}
// })
// size = jx.utils.patterns.visitor(item.details.size, function (row) {
// return {y:row[0],x:row[1]}
// })
// monitor.folders.render.details(item.name,{age:age,size:size})
}
//
// @TODO Add the units in days just in case
options.autoload = true
options.fields = [
{ name: 'id', type: 'text', title: "Host", headercss: "small bold", css: "small"},
{ name: 'name', type: 'text', title: "Folder Name", headercss: "small bold", css: "small"},
{ name: "size", type: "number", title: "Folder Size", type: "number", headercss: "small bold" },
{ name: "count", type: "number", title: "File Count", type: "number", headercss: "small bold" }
]
var grid = $('#gridfolders').jsGrid(options) ;
}
monitor.menu = {}
monitor.menu.event = {}
monitor.menu.event.toggle = function () {
var dom = jx.dom.get.instance('menuframe')
var value = dom.style.marginLeft.trim()
if (value==0 || value == "0px" || value == "") {
var width = -$(dom).width() - 10
$('#menuframe').animate({marginLeft:"-12%"})
} else {
$('#menuframe').animate({marginLeft:"0"})
}
} }
/**
* Socket handler, check for learning status
*/

@ -0,0 +1,140 @@
var fixedTop = false;
var transparent = true;
var navbar_initialized = false;
$(document).ready(function(){
window_width = $(window).width();
// Init navigation toggle for small screens
if(window_width <= 991){
pd.initRightMenu();
}
// Activate the tooltips
$('[rel="tooltip"]').tooltip();
});
// activate collapse right menu when the windows is resized
$(window).resize(function(){
if($(window).width() <= 991){
pd.initRightMenu();
}
});
pd = {
misc:{
navbar_menu_visible: 0
},
checkScrollForTransparentNavbar: debounce(function() {
if($(document).scrollTop() > 381 ) {
if(transparent) {
transparent = false;
$('.navbar-color-on-scroll').removeClass('navbar-transparent');
$('.navbar-title').removeClass('hidden');
}
} else {
if( !transparent ) {
transparent = true;
$('.navbar-color-on-scroll').addClass('navbar-transparent');
$('.navbar-title').addClass('hidden');
}
}
}),
initRightMenu: function(){
if(!navbar_initialized){
$off_canvas_sidebar = $('nav').find('.navbar-collapse').first().clone(true);
$sidebar = $('.sidebar');
sidebar_bg_color = $sidebar.data('background-color');
sidebar_active_color = $sidebar.data('active-color');
$logo = $sidebar.find('.logo').first();
logo_content = $logo[0].outerHTML;
ul_content = '';
// set the bg color and active color from the default sidebar to the off canvas sidebar;
$off_canvas_sidebar.attr('data-background-color',sidebar_bg_color);
$off_canvas_sidebar.attr('data-active-color',sidebar_active_color);
$off_canvas_sidebar.addClass('off-canvas-sidebar');
//add the content from the regular header to the right menu
$off_canvas_sidebar.children('ul').each(function(){
content_buff = $(this).html();
ul_content = ul_content + content_buff;
});
// add the content from the sidebar to the right menu
content_buff = $sidebar.find('.nav').html();
ul_content = ul_content + '<li class="divider"></li>'+ content_buff;
ul_content = '<ul class="nav navbar-nav">' + ul_content + '</ul>';
navbar_content = logo_content + ul_content;
navbar_content = '<div class="sidebar-wrapper">' + navbar_content + '</div>';
$off_canvas_sidebar.html(navbar_content);
$('body').append($off_canvas_sidebar);
$toggle = $('.navbar-toggle');
$off_canvas_sidebar.find('a').removeClass('btn btn-round btn-default');
$off_canvas_sidebar.find('button').removeClass('btn-round btn-fill btn-info btn-primary btn-success btn-danger btn-warning btn-neutral');
$off_canvas_sidebar.find('button').addClass('btn-simple btn-block');
$toggle.click(function (){
if(pd.misc.navbar_menu_visible == 1) {
$('html').removeClass('nav-open');
pd.misc.navbar_menu_visible = 0;
$('#bodyClick').remove();
setTimeout(function(){
$toggle.removeClass('toggled');
}, 400);
} else {
setTimeout(function(){
$toggle.addClass('toggled');
}, 430);
div = '<div id="bodyClick"></div>';
$(div).appendTo("body").click(function() {
$('html').removeClass('nav-open');
pd.misc.navbar_menu_visible = 0;
$('#bodyClick').remove();
setTimeout(function(){
$toggle.removeClass('toggled');
}, 400);
});
$('html').addClass('nav-open');
pd.misc.navbar_menu_visible = 1;
}
});
navbar_initialized = true;
}
}
}
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function() {
timeout = null;
if (!immediate) func.apply(context, args);
}, wait);
if (immediate && !timeout) func.apply(context, args);
};
};

File diff suppressed because it is too large Load Diff

@ -1,172 +1,402 @@
<meta charset="UTF-8"> <!doctype html>
<meta http-equiv="cache-control" content="no-cache"> <html lang="en">
<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1"> <head>
<link type="text/css" rel="stylesheet" href="{{ context }}/static/js/jsgrid/jsgrid.min.css" > <meta charset="utf-8" />
<link type="text/css" rel="stylesheet" href="{{ context }}/static/js/jsgrid/jsgrid-theme.min.css" > <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<link href="{{context}}/static/css/default.css" rel="stylesheet" type="text/css">
<link href="{{context}}/static/css/fa/css/font-awesome.min.css" rel="stylesheet" type="text/css"> <title>Monitor</title>
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport' />
<script src="{{ context }}/static/js/jquery/jquery.min.js"></script> <meta name="viewport" content="width=device-width" />
<script src="{{context}}/static/js/chart.js/chart.bundle.js"></script>
<script src="{{context}}/static/js/jx/rpc.js"></script> <!-- Bootstrap core CSS -->
<script src="{{context}}/static/js/jx/dom.js"></script> <link href="{{context}}/static/css/bootstrap.min.css" rel="stylesheet" />
<script src="{{context}}/static/js/jx/utils.js"></script>
<script src="{{context}}/static/js/jx/ext/math.js"></script> <!-- Animation library for notifications -->
<script src="{{ context }}/static/js/jsgrid/jsgrid.js"></script> <link href="{{context}}/static/css/animate.min.css" rel="stylesheet"/>
<script src="{{context}}/static/js/colors.js"></script>
<script src="{{context}}/static/js/dashboard.js"></script> <!-- Dashboard core CSS -->
<title>iMonitor</title> <link href="{{context}}/static/css/dashboard.css" rel="stylesheet"/>
<script>
var HTTP_CONTEXT="{{context}}" <!-- Fonts and icons -->
$(document).ready(function(){ <link href="http://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css" rel="stylesheet">
monitor.folders.init() <!--
monitor.processes.fetch() <link href='https://fonts.googleapis.com/css?family=Muli:400,300' rel='stylesheet' type='text/css'>
-->
}) <link href="{{context}}/static/css/themify-icons.css" rel="stylesheet">
</script> <!-- Core JS Files -->
<body class=""> <script src="{{context}}/static/js/jquery-1.10.2.js" type="text/javascript"></script>
<div class="border-bottom caption" style="height:42px"> <script src="{{context}}/static/js/bootstrap.min.js" type="text/javascript"></script>
<div class="">{{title}}</div>
<div class="small" style="margin:4px">The Phi Technology LLC</div> <!-- Checkbox, Radio & Switch Plugins -->
</div> <script src="{{context}}/static/js/bootstrap-checkbox-radio.js"></script>
<i class="fa fa-reorder default left action" onclick="monitor.menu.event.toggle()"></i>
<div id="menuframe" class="left small " style="width:10%; height:90%"> <!-- Charts Plugin -->
<div id="menu" class="menu"></div> <script src="{{context}}/static/js/chartist.min.js"></script>
</div>
<!-- Notifications Plugin -->
<div class="left info"> <script src="{{context}}/static/js/bootstrap-notify.js"></script>
<div class="" style="height:28px; "> <!-- Google Maps Plugin
<div class="left bold">Monitoring <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js"></script>
<span id="latest_processes_label" class="default bold"></span> -->
</div> <!-- Dashboard Core javascript and methods for Demo purpose -->
<script src="{{context}}/static/js/default.js"></script>
</div>
<!-- Dashboard DEMO methods, don't include it in your project! -->
<div class = "shadow border-right" style="padding:2px; margin:4px; height:170px"> <script src="{{context}}/static/js/dashboard.js"></script>
<div id="latest_processes" class="grid" ></div> <script src="{{context}}/static/js/jx/dom.js"></script>
</div> <script src="{{context}}/static/js/jx/rpc.js"></script>
<div style="height:22px; padding:2px" class="small"> <script src="{{context}}/static/js/jx/utils.js"></script>
<div id="latest_process_pager" align="center"></div> <script type="text/javascript">
</div> var URI_CONTEXT="{{context}}"
<div id="process_summary" class=" grid border-right" style="margin:4px"> $(document).ready(function(){
<div style="margin:4px; padding:2px; margin-bottom:4px; height:28px">
<div class="bold" >Application Summary By Status</div> var lobservers = [
<div id="app-summary-date" class="small"></div> g.summary.factory('/1/get/summary/app_resources',function(r){
</div>
//r = JSON.parse(r.responseText)
<div class="simple-gradient shadow" style="padding:2px; height:150px; margin:4px; margin-top:10px"> jx.dom.set.value('total_cpu',r.cpu_usage)
<div class="left small width-half" style="margin-top:10px"> jx.dom.set.value('total_mem',r.memory_usage)
<div class="border-right" style="padding:4px" title="Running"><span id="total-running" class="default">0</span> <i class="fa fa-check right" style="margin:4px"></i></div> jx.dom.set.value('mem_units',r.units)
<div class="border-right" title="Crash" style="padding:4px; margin-top:2px"><span id="total-crash" class="default">0</span> <i class="fa fa-times right" style="margin:4px"></i></div>
<div class="border-right" title="Idle" style="padding:4px; margin-top:2px"><span id="total-idle" class="default">0</span> <i class="fa fa-ellipsis-h right" style="margin:4px"></i></div> }),
<div class="border-top" style="padding:4px; margin-top:2px"> <span id="total-apps" class="default">0</span> <span class="right">Applications</span></div> g.summary.factory('/1/get/summary/folder_size',function(r){
</div> //console.log(r.responseText)
//r = JSON.parse(r.responseText)
<div id="summary_chart" class="width-half right"></div> if (r.length == 0){
</div> r.size = "0.0"
<div id="summary_details" class="right"></div> r.units = 'MB'
</div> }
jx.dom.set.value('total_folder_size',r.size)
<div class="grid border-right" style="margin:4px; margin-top:10px;"> jx.dom.set.value('folder_units',r.units)
<div style="height:28px"> }),
<div class="bold" style="margin:4px; padding:4px">Application Summary By Groups</div> g.summary.factory('/1/get/summary/app_status',function(r){
</div>
<div class="shadow simple-gradient width" id="summary_ranking" style="margin:4px; padding:2px; text-transform:capitalize"></div> jx.dom.set.value('total_app_crashes',r.crash)
</div> })
</div> ]
<div class="left info">
<div class="" style="height:28px"> jx.utils.patterns.observer(lobservers,"init")
<div class="small bold">CPU & Memory Usage Trend for <span id="trend_info" class="default bold"></span></div> dashboard.initChartist();
<div class="smal" style="float:none"><div id="has_anomaly" class="small"><i class="fa fa-warning" ></i> Anomaly Detected</div></div>
});
</div> </script>
</head>
<div class="shadow simple-gradient" style="height:270px; margin-top:4px">
<div id="trends_chart" class="small grid" style="height:250px"></div>
</div>
<div id="sandbox" class="border-top" style="padding:4px; margin-top:10px"> <body>
<div style="height:28px">
<div id="inspect_sandbox" class="right button border" style="display:none" onclick="monitor.sandbox.init()">Inspect</div> <div class="wrapper">
<div class="bold">Python Virtual Environment Analysis</div> <div class="sidebar" data-background-color="white" data-active-color="danger">
<div class="small">Last Lookup <span id="sandbox_date"></span></div> <!--
</div> Tip 1: you can change the color of the sidebar's background using: data-background-color="white | black"
Tip 2: you can change the color of the active button using the data-active-color="primary | info | success | warning | danger"
<div class="shadow " style="margin-top:10px; height:135px"> -->
<div id="sandbox_status" class="">
</div> <div class="sidebar-wrapper">
<div id="sandbox_pager"></div> <div class="logo">
</div> <a href="#" class="simple-text">
</div> Monitor
<div style="margin-top:10px"> </a>
<div id="folder_summary"> </div>
<div style="height:28px">
<ul class="nav">
<div class="bold">Folder Analysis/Monitoring</div> <li class="active">
<div class="small">Powered By Machine Learning</div> <a href="dashboard.html">
</div> <i class="ti-panel"></i>
<div class="shadow"> <p>Dashboard</p>
<div class=" border-top" style="margin-top:4px; padding:2px; height:34px"> </a>
<i class="fa fa-search left" style="margin:4px; padding:4px; ; color:gray;"></i> </li>
<input id="folder_search" type="text" class="small left" placeholder="hostname" style="width:87%; padding-left:4px;" onkeyup="monitor.folders.search.init()"/> <li>
<i class="fa fa-trash right action right" style="margin:4px; padding:4px; color:maroon" onclick="monitor.folders.search.reset()"></i> <a href= "/user">
</div> <i class="ti-user"></i>
<div style="margin-top:10px; height:170px"> <p>User Profile</p>
<div id="gridfolders"></div> </a>
<div id="folderspager" class="small" style="height:22px"></div> </li>
</div> <li class="active-pro">
</div> <a href="/upgrade">
</div> <i class="ti-export"></i>
<p>Upgrade to PRO</p>
<div id="folder_plan" style="display:none"> </a>
<div class="border-bottom" style="height:32px"> </li>
<div class="bold">Deletion/Archiving Plan </ul>
<i class="fa fa-quote-left"></i> <span id="folder_name"></span> <i class="fa fa-quote-right"></i> </div>
<i class="fa fa-angle-up action right bold" style="font-size:16px; margin:4px;" onclick="monitor.folders.show.grid()"></i> </div>
</div> <!-- End Side Bar -->
<div class="small left">Powered By Machine Learning</div> <div class="main-panel">
<nav class="navbar navbar-default">
</div> <div class="container-fluid">
<div class="navbar-header">
<div id="delete_age" class="left width-half border-right" style="margin:2px; padding:2px;"> <button type="button" class="navbar-toggle">
<div class="small" align="left">By Age</div> <span class="sr-only">Toggle navigation</span>
<div class="number" style="height:42px"> <span class="icon-bar bar1"></span>
<span class="icon-bar bar2"></span>
<div id="age_count" align="right" class="left width-75" style="margin-right:4px">00</div> <span class="icon-bar bar3"></span>
<div class="small" class="left" style="height:100%; padding-top:15px">Files</div> </button>
<a class="navbar-brand" href="#">Dashboard</a>
</div>
</div> <div class="collapse navbar-collapse">
<div class="small border-top" align="center" style="padding-top:4px"> <ul class="nav navbar-nav navbar-right">
Approximately <span id="age_value">00</span> <span id="age_units"></span> <li>
</div> <a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="ti-panel"></i>
</div> <p>Stats</p>
<div id="delete_size" class="right width-half" class="number" style="margin:2px; padding:2px"> </a>
<div class="small" align="left">By Size</div> </li>
<li class="dropdown">
<div class=" number" style="height:42px"> <a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="ti-server"></i>
<div id="size_count" align="right" class="left width-75" style="margin-right:4px">00</div> <!-- <p class="notification">5</p> -->
<div class="small" class="left" style="height:100%; padding-top:15px">Files</div> <p>Servers</p>
</div> <b class="caret"></b>
<div class="small border-top"align="center" style="padding-top:4px"> </a>
Approximately <span id="size_value">00</span> <span id="size_units"></span> <ul class="dropdown-menu">
</div> {% for name in app_names %}
<div class="action" data-name="{{name}}" id="app_names"><i class="fa fa-angle-right"></i><a href='#'>{{name|safe}}</a>
<script type="text/javascript">onclick=function(){
</div> console.log('name...', "{{ name }}") //this works, but returns same variable......
</div>
<div id="chartfolder" ></div> var appName = $('#app_names').data("name");
</div> console.log('name...', appName )
}</script>
</div>
</div>
{% endfor %}
</ul>
</li>
<li>
<a href="#">
<i class="ti-settings"></i>
<p>Settings</p>
</a>
</li>
</ul>
</div>
</div>
</nav>
<!-- End Menu Bar -->
<div class="content">
<div class="container-fluid">
<div class="row">
<div class="col-lg-3 col-sm-6">
<div class="card">
<div class="content">
<div class="row">
<div class="col-xs-5">
<div class="icon-big icon-warning text-center">
<i class="ti-dashboard"></i>
<div class="small">Total CPU</div>
</div>
</div>
<div class="col-xs-7">
<div class="numbers">
<div id="total_cpu" align="center">00</div>
<div class="small" align="right">Percent</div>
</div>
</div>
</div>
<div class="footer">
<hr />
<div class="stats">
<i class="ti-reload"></i> Updated now
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-3 col-sm-6">
<div class="card">
<div class="content">
<div class="row">
<div class="col-xs-5">
<div class="icon-big icon-success text-center">
<i class="fa fa-microchip"></i>
<div class="small">Mem. Used</div>
</div>
</div>
<div class="col-xs-7">
<div class="numbers">
<div id="total_mem"></div>
<div class="small" id="mem_units" align="right"></div>
</div>
</div>
</div>
<div class="footer">
<hr />
<div class="stats">
<i class="ti-calendar"></i> Last day
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-3 col-sm-6">
<div class="card">
<div class="content">
<div class="row">
<div class="col-xs-5">
<div class="icon-big icon-danger text-center">
<i class="fa fa-warning"></i>
<div class="small" align="center">Crashes</div>
</div>
</div>
<div class="col-xs-7">
<div class="numbers">
<div id="total_app_crashes"></div>
<!-- show errors API. Crashed? -->
</div>
</div>
</div>
<div class="footer">
<hr />
<div class="stats">
<i class="ti-timer"></i> In the last hour
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-3 col-sm-6">
<div class="card">
<div class="content">
<div class="row">
<div class="col-xs-5">
<div class="icon-big icon-info text-center">
<i class="ti-folder"></i>
<div class="small">Folders</div>
</div>
</div>
<div class="col-xs-7">
<div class="numbers">
<div id="total_folder_size" align="center"></div>
<div class="small" align="center" id="folder_units"></div>
<!-- Folder Analysis API here. -->
</div>
</div>
</div>
<div class="footer">
<hr />
<div class="stats">
<i class="ti-reload"></i> Updated now
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="card">
<div class="header">
<h4 class="title">Monitoring Apps</h4>
<p class="category">performance</p>
</div>
<div class="content">
<div id="chartHours" class="ct-chart"></div>
<div class="footer">
<div class="chart-legend">
<i class="fa fa-circle text-info"></i> cpu usage
<i class="fa fa-circle text-warning"></i> memory used
<i class="fa fa-circle text-danger"></i> available line
</div>
<hr>
<div class="stats">
<i class="ti-reload"></i> Updated 3 minutes ago
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="card">
<div class="header">
<h4 class="title">Summary</h4>
<p class="category">Running|Idle|Crash</p>
</div>
<div class="content">
<div id="chartPreferences" class="ct-chart ct-perfect-fourth"></div>
<div class="footer">
<div class="chart-legend">
<i class="fa fa-circle text-info"></i> Running
<i class="fa fa-circle text-danger"></i> Crashed
<i class="fa fa-circle text-warning"></i> Idle
</div>
<hr>
<div class="stats">
<i class="ti-timer"></i> Some footer
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card ">
<div class="header">
<h4 class="title">CPU and Memory</h4>
<p class="category">Usage Trends</p>
</div>
<div class="content">
<div id="chartActivity" class="ct-chart"></div>
<div class="footer">
<div class="chart-legend">
<i class="fa fa-circle text-info"></i> CPU
<i class="fa fa-circle text-warning"></i> Memory
</div>
<hr>
<div class="stats">
<i class="ti-check"></i> Data information certified
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<footer class="footer">
<div class="container-fluid">
<nav class="pull-left">
<ul>
<li>
<a href="#">
Monitor
</a>
</li>
<li>
<a href="#">
Invy
</a>
</li>
</ul>
</nav>
</div>
</footer>
</div>
</div>
</body> </body>
</html>

@ -0,0 +1 @@
<H1>Upgrade</Hi>

@ -30,6 +30,9 @@ class Analysis:
return {"month":d.month,"year":d.year, "day":d.day,"hour":d.hour,"minute":d.minute} return {"month":d.month,"year":d.year, "day":d.day,"hour":d.hour,"minute":d.minute}
def getName(self): def getName(self):
return self.__class__.__name__ return self.__class__.__name__
def cleanup(self,text):
return re.sub('[^a-zA-Z0-9\s:]',' ',str(text)).strip()
""" """
This class is designed to analyze environment variables. Environment variables can either be folders, files or simple values This class is designed to analyze environment variables. Environment variables can either be folders, files or simple values
@ -214,7 +217,7 @@ class DetailProcess(Analysis):
else: else:
return "crash" return "crash"
def format(self,row): def format(self,row):
r= {"memory_usage":row[0],"cpu_usage":row[1],"memory_available":row[2]/1000,"proc_count":row[3],"label":row[4]} r= {"memory_usage":row[0],"cpu_usage":row[1],"memory_available":row[2]/1000,"proc_count":row[3],"label":self.cleanup(row[4])}
status = self.status(r) status = self.status(r)
r['status'] = status r['status'] = status
return r return r

@ -0,0 +1,303 @@
"""
This class is designed to be an actor class i.e it will undertake certain actions given an event detected
The platform has 2 main sections (detection & analysis).
Action Types (Actors):
- Alert : Sends an email or Webhook
- Apps : Kill, Start
- Folder: Archive, Delete (all, age, size)
By design we are to understand that a message is structured as follows:
{to,from,content} with content either being an arbitrary stream (or JSON)
@TODO:
- upgrade to python 3.x
"""
import json
from threading import Thread
import os
import shutil
import subprocess
from monitor import ProcessCounter
from utils.transport import QueueListener, QueueWriter, QueueReader
from utils.params import PARAMS
from ngram import NGram as ng
class Actor(Thread):
def __init__(self):
Thread.__init__(self)
pass
def getIdentifier(self):
return self.__class__.__name__.lower()
"""
Initializing the class with configuration. The configuration will be specific to each subclass
"""
def init(self,config,item=None):
self.config = config
self.item = item
def process(self,item):
pass
def isValid(self,item):
return False
def execute(self,cmd):
stream = None
try:
subprocess.call (cmd,shell=False)
#stream = handler.communicate()[0]
except Exception,e:
pass
def run(self):
if self.item is not None:
self.process(self.item)
"""
Sending a message to a queue with parameters to,from,content
"""
def post(self,**args):
pass
"""
This is designed to handle folders i.e cleaning/archiving the folders
"""
class Folders(Actor):
def init(self,config,item):
Actor.init(self,config,item)
self.lfolders = config['folders']
self.config = config['actions']['folders']
self.threshold = self.get_size(self.config['threshold'])
self.item = item
def archive(self,item):
"""
This function will archive all files in a given folder
@pre : isValid
"""
folder = item['label']
signature='-'.join([str(item['date']),str(item['count']),'-files'])
tarball=os.sep([folder,signature])
shutil.make_archive(tarball,'tar',folder)
self.clean(item)
#
# @TODO: The archive can be uploaded to the cloud or else where
# - This allows the submission of data to a processing engine if there ever were one
#
pass
def clean(self,item):
"""
This function consists in deleting files from a given folder
"""
rpath = item['label']
lists = os.listdir(item['label'])
for name in list() :
path = os.sep([item['label'],name])
if os.path.isdir(path) :
shutil.rmtree(path)
else:
os.remove(path)
#
#
def get_size(self,value):
units = {'MB':1000,'GB':1000000,'TB':1000000000} # converting to kb
key = set(unites) & set(re.split('(\d+)',value.upper()))
if len(key) == 0:
return -1
key = key.pop()
return float(value.upper().replace('MB','').strip()) * units[key]
def isvalid(self,item):
"""
This function returns whether the following :
p : folder exists
q : has_reached threashold
"""
p = os.path.exists(item['label']) and item['label'] in self.lfolders
q = self.get_size(item['size']) >= self.threshold
return p and q
def process(self,item):
if self.isValid(item) :
name = self.config['action']
stream = "".join([name,'(',json.dumps(item),')'])
eval(stream)
class Kill(Actor):
def isValid(self,item):
return (item is not None) and (item in self.config)
def process(self,item):
args = "".join(["-eo pid,command|grep ",item,'|grep -E "^ {0,1}[0-9]+" -o|xargs kill -9'])
self.execute(["ps",args])
#
# We need to make sure we can get assess the process on this server
#
class Start(Actor):
def __init__(self):
Actor.__init__(self)
self.ng = None
def init(self,config,item):
Actor.init(self,config,item)
self.config = config['apps']
self.ng = ng(self.config.keys())
def isValid(self,name):
items = self.ng.search(name)
if len(items) == 0 :
return False
else:
return items[0][1] > 0.1
def process(self,row):
name = row['label']
items = self.ng.search(name)[0]
app = items[0]
args = self.config[app]
cmd = " ".join([app,args])
self.execute([app,args])
"""
This class is designed to handle applications i.e start/stopping applications
@TODO: Assess if a reboot is required, by looking at the variance/anomaly detection
"""
class Apps(Actor):
def __init__(self):
Actor.__init__(self)
self.crashes = []
self.running = []
def isValid(self,rows):
status = [row['status'] for row in rows]
return 'crash' in status
def classify(self,rows):
self.crashes = []
self.running = []
for row in rows:
if row['status'] == 'crash' :
self.crashes.append(row)
else:
self.running.append(row)
def reboot(self):
for row_run in self.running:
pass
def start(self):
for row_crash in self.crashes:
thread = Start()
thread.init(self.config,row_crash)
thread.daemon = True
thread.start()
def process(self,rows):
self.classify(rows)
if self.crashes :
self.start()
if self.running:
self.reboot()
class Event(Thread):
def __init__(self,config):
pass
def run(self):
"""
The orchestrator class is designed to aggregate actions and communicate back to the caller
Mesage passing is structured as follows {from,to,content} The content is designed to be understood by the actor
The orchestrator is implemented using a simple iterator design-pattern
@TODO: action specifications should be provided remotely
"""
class Orchestrator(Actor):
def __init__(self,config=None):
Actor.__init__(self)
if config is None:
f = open(PARAMS['path'])
config = json.loads(f.read())
f.close()
self.config = config
Actor.__init__(self)
self.actors = {"apps":Apps(),"folders":Folders()}
self.is_master_node = False
self.items = []
#
# If the configuration only has id,key then this is NOT the maestro
#
host = config['api']
qid = config['id']
print "Initialized ***** ",self.getIdentifier(), " as ",config['id']
#
# This object will have to request for the configuration
#
#for id in config['actions'] :
#conf = config['actions'][id]
#item = eval("".join([id,"(",json.dumps(conf),")"]))
#self.actors[id.lower()] = item
"""
This function is designed to provide the orchestrator a configuration
@pre
"""
def init(self,config):
for id in config:
setup_info = config[id]
item = eval("".join([id,"(",json.dumps(setup_info),")"]))
self.actors[id.lower()] = item
def callback(self,channel,method,header,stream):
message = json.loads(stream)
if 'content' in message :
content = message['content']
print self.actors
to = message['to']
if isinstance(content,basestring) and content.lower() in ['quit'] or to=='quit':
if content.lower() == 'quit' or to == 'quit':
print '**** closing ',self.getIdentifier()
channel.close()
else:
id = to.lower()
actor = self.actors[id]
if actor is not None and actor.isValid(content) :
actor.init(self.config['actions'])
actor.process(content)
else:
content = {"status":"invalid","content":content}
#self.post(to=sender,content=content)
def run(self):
info = {}
host = self.config['api']
uid = self.config['key']
qid = self.config['id']
qlistener = QueueListener(qid=qid,uid=uid,host=host)
qlistener.callback = self.callback
qlistener.read()
r = [self.process(item) for item in self.items]
"""
This class is designed to send a message to a given AMQP enpoint
The AMQP endpoint is implemented by QueueWriter class
"""
# class Alert(Actor):
# def process(self,item):
# pass
if __name__ == '__main__':
thread = Orchestrator()
thread.start()

@ -27,6 +27,8 @@ class ICollector(Thread) :
self.factory = DataSourceFactory() self.factory = DataSourceFactory()
self.init() self.init()
self.name = 'data-collector@'+self.id self.name = 'data-collector@'+self.id
def init(self): def init(self):
@ -51,7 +53,9 @@ class ICollector(Thread) :
self.quit = False self.quit = False
#self.DELAY = PARAMS['delay']*60 #self.DELAY = PARAMS['delay']*60
self.DELAY = self.config['delay'] self.DELAY = self.config['delay']
#
# we need to instanciate the actor orchestrator
#
""" """
This function returns an instance of a data collector class : This function returns an instance of a data collector class :
ProcessDetails, FileWatch, ... provided the class name ProcessDetails, FileWatch, ... provided the class name
@ -70,6 +74,7 @@ class ICollector(Thread) :
write_class = self.config['store']['class']['write'] write_class = self.config['store']['class']['write']
read_args = self.config['store']['args'] read_args = self.config['store']['args']
DELAY = self.config['delay'] * 60 DELAY = self.config['delay'] * 60
while self.quit == False: while self.quit == False:
for thread in self.pool : for thread in self.pool :
@ -84,10 +89,25 @@ class ICollector(Thread) :
else: else:
label = id label = id
row = data row = data
#
# At this point we should check for the status and if it prompts an action
# @TODO Use a design pattern for this ... (Aggregation?)
# - submit the row to Event for analysis
# - The event orchestrator will handle things from this point on
#
message = {}
message['to'] = thread.getName()
message['content'] = row
qwriter = QueueWriter(host=self.config['api'],uid=self.config['key'],qid=self.id)
qwriter.write(label=self.id,row = message)
qwriter.close()
self.lock.acquire() self.lock.acquire()
store = self.factory.instance(type=write_class,args=read_args) store = self.factory.instance(type=write_class,args=read_args)
store.flush(size=200) store.flush(size=200)
store.write(label=label,row=row) store.write(label=label,row=row)
self.lock.release() self.lock.release()
if 'MONITOR_CONFIG_PATH' in os.environ : if 'MONITOR_CONFIG_PATH' in os.environ :
@ -104,4 +124,4 @@ class ICollector(Thread) :
if __name__ == '__main__': if __name__ == '__main__':
thread = ICollector() thread = ICollector()
# thread.daemon = True # thread.daemon = True
thread.start() thread.start()

@ -261,6 +261,7 @@ class MessageQueue:
self.close() self.close()
return resp return resp
def close(self): def close(self):
if self.connection.is_closed == False :
self.channel.close() self.channel.close()
self.connection.close() self.connection.close()
""" """
@ -345,9 +346,12 @@ class QueueReader(MessageQueue,Reader):
#self.uid = params['uid'] #self.uid = params['uid']
#self.qid = params['qid'] #self.qid = params['qid']
MessageQueue.__init__(self,**params); MessageQueue.__init__(self,**params);
if 'durable' in params :
self.durable = True
else:
self.durable = False
self.size = -1 self.size = -1
self.data = {} self.data = {}
def init(self,qid): def init(self,qid):
properties = pika.ConnectionParameters(host=self.host) properties = pika.ConnectionParameters(host=self.host)
@ -364,6 +368,7 @@ class QueueReader(MessageQueue,Reader):
""" """
def callback(self,channel,method,header,stream): def callback(self,channel,method,header,stream):
r = [] r = []
if re.match("^\{|\[",stream) is not None: if re.match("^\{|\[",stream) is not None:
r = json.loads(stream) r = json.loads(stream)
@ -395,9 +400,12 @@ class QueueReader(MessageQueue,Reader):
# We enabled the reader to be able to read from several queues (sequentially for now) # We enabled the reader to be able to read from several queues (sequentially for now)
# The qid parameter will be an array of queues the reader will be reading from # The qid parameter will be an array of queues the reader will be reading from
# #
if isinstance(self.qid,basestring) :
self.qid = [self.qid]
for qid in self.qid: for qid in self.qid:
self.init(qid) self.init(qid)
# r[qid] = [] # r[qid] = []
if self.info.method.message_count > 0: if self.info.method.message_count > 0:
self.channel.basic_consume(self.callback,queue=qid,no_ack=False); self.channel.basic_consume(self.callback,queue=qid,no_ack=False);
@ -406,11 +414,26 @@ class QueueReader(MessageQueue,Reader):
pass pass
#self.close() #self.close()
# r[qid].append( self.data) # r[qid].append( self.data)
return self.data return self.data
class QueueListener(QueueReader):
def init(self,qid):
properties = pika.ConnectionParameters(host=self.host)
self.connection = pika.BlockingConnection(properties)
self.channel = self.connection.channel()
self.channel.exchange_declare(exchange=self.uid,type='direct',durable=True )
self.info = self.channel.queue_declare(passive=True,exclusive=True,queue=qid)
self.channel.queue_bind(exchange=self.uid,queue=self.info.method.queue,routing_key=qid)
#self.callback = callback
def read(self):
self.init(self.qid)
self.channel.basic_consume(self.callback,queue=self.qid,no_ack=True);
self.channel.start_consuming()
""" """
This class is designed to write output as sql insert statements This class is designed to write output as sql insert statements
The class will inherit from DiskWriter with minor adjustments The class will inherit from DiskWriter with minor adjustments
@ -465,7 +488,11 @@ class Couchdb:
if q == False: if q == False:
return False return False
return True return True
def view(self,id,**args):
r =self.dbase.view(id,**args)
r = r.all()
return r[0]['value'] if len(r) > 0 else []
""" """
This function will read an attachment from couchdb and return it to calling code. The attachment must have been placed before hand (otherwise oops) This function will read an attachment from couchdb and return it to calling code. The attachment must have been placed before hand (otherwise oops)
@T: Account for security & access control @T: Account for security & access control
@ -564,7 +591,7 @@ class CouchdbWriter(Couchdb,Writer):
self.dbase.save_doc(document) self.dbase.save_doc(document)
def flush(self,**params) : def flush(self,**params) :
size = params['size'] size = params['size'] if 'size' in params else 0
has_changed = False has_changed = False
document = self.dbase.get(self.uid) document = self.dbase.get(self.uid)
for key in document: for key in document:
@ -572,7 +599,7 @@ class CouchdbWriter(Couchdb,Writer):
content = document[key] content = document[key]
else: else:
continue continue
if isinstance(content,list): if isinstance(content,list) and size > 0:
index = len(content) - size index = len(content) - size
content = content[index:] content = content[index:]
document[key] = content document[key] = content
@ -580,8 +607,8 @@ class CouchdbWriter(Couchdb,Writer):
else: else:
document[key] = {} document[key] = {}
has_changed = True has_changed = True
if has_changed:
self.dbase.save_doc(document) self.dbase.save_doc(document)
def archive(self,params=None): def archive(self,params=None):
document = self.dbase.get(self.uid) document = self.dbase.get(self.uid)

@ -0,0 +1,8 @@
#!/bin/bash
#script_dir=`dirname $0`
#cd $script_dir
#/bin/bash -c ". activate sandbox; exec /bin/bash -i"
`source activate sandbox`
export PYTHONPATH=$PWD/src
python src/utils/agents/data-collector.py --path /Users/michaelmead/Documents/Programming/monitor/config.json --title "Seekers Dashboard"
Loading…
Cancel
Save