Index: trunk/src/tmcsim/cadsimulator/Coordinator.java
===================================================================
--- trunk/src/tmcsim/cadsimulator/Coordinator.java	(revision 435)
+++ trunk/src/tmcsim/cadsimulator/Coordinator.java	(revision 440)
@@ -758,5 +758,5 @@
                 if (initials.length() > 0)
                 {//CAD Log Entry, Incident #187, Sharon: REQUEST EXTRA ANCHOVIES
-                    output.append("CAD log entry, ");
+                    output.append("CAD log, ");
                     output.append("Incident #" + incident.logNum + ", ");
                     output.append(initials + ": ");
Index: trunk/src/tmcsim/application.properties
===================================================================
--- trunk/src/tmcsim/application.properties	(revision 435)
+++ trunk/src/tmcsim/application.properties	(revision 440)
@@ -1,5 +1,5 @@
-#Wed, 10 Jul 2019 15:20:20 -0700
+#Thu, 11 Jul 2019 17:51:05 -0700
 
-Application.revision=434
+Application.revision=439
 
 Application.buildnumber=146
Index: trunk/src/python/unifiedlogger/cad_watcher.py
===================================================================
--- trunk/src/python/unifiedlogger/cad_watcher.py	(revision 439)
+++ trunk/src/python/unifiedlogger/cad_watcher.py	(revision 439)
@@ -0,0 +1,59 @@
+import json, time
+from copy import deepcopy
+
+# CAD comment log Watcher
+# Look for changes in the CAD comment log.
+# The CADserver will append new comments to the log as they arrive 
+# from clients.  We only need to keep track of the log length in order to
+# determine if a new comment has been added.  We will output the 
+# new messages that arrived during the last wait interval. 
+# jdalbey  7/6/2019
+
+lastLineNum = 0
+
+# Utility functions
+def isEmpty(cmsitem):
+    return cmsitem == ",,,,,"
+def isFull(cmsitem):
+    return not isEmpty(cmsitem)
+
+# Read the cad comments log 
+def readFile():
+    lines = []
+    try:
+        text_file = open("CADcomments.log", "r")
+    except IOError:
+        print "Error: missing CADcomments.log file."
+    else:
+        lines = text_file.read().split('\n')
+        text_file.close()    
+    return lines
+    
+def setup():
+    # nothing needed for setup
+    return
+
+# Retrieve new messages from CAD comment log 
+def getLogEntries():
+    global lastLineNum
+    msgList = readFile()
+    currList = []
+    currList = msgList[lastLineNum:]    # new items since last file read
+    lastLineNum = len(msgList)-1
+    return currList
+
+# Local main for unit testing
+def main():
+    setup()
+    # Loop Forever, checking every five seconds
+    while True:
+        # Look for new messages
+        answer = getLogEntries()
+        # Output results
+        for item in answer:
+            print item
+        # wait 
+        time.sleep(5)
+
+if __name__ == "__main__":
+    main()
Index: trunk/src/python/unifiedlogger/logging_service.py
===================================================================
--- trunk/src/python/unifiedlogger/logging_service.py	(revision 439)
+++ trunk/src/python/unifiedlogger/logging_service.py	(revision 439)
@@ -0,0 +1,74 @@
+import cms_watcher, cad_watcher, time, json, ConfigParser
+# Unified Logging Service
+# jdalbey 7/6/2019
+
+outputFilename = "unifiedlog.csv"
+
+# Load the sim time file and extract the seconds */
+def getSimTime():
+    with open ("webapps/dynamicdata/sim_elapsedtime.json", 'r') as myfile:
+        jsonData=myfile.read()
+         
+    seconds = json.loads(jsonData)['elapsedtime']
+    # convert seconds to H:MM:SS
+    m, s = divmod(int(seconds), 60)
+    h, m = divmod(m, 60)
+    return  "%d:%02d:%02d" % (h, m, s)    
+
+def startup():
+    # get path to output file from configuration
+    config = ConfigParser.ConfigParser()
+    config.read('config/logging_service.cfg')
+    logfilepath  = config.get('Paths', 'UnifiedLogPath')
+    
+    # Delete any previously existing output file
+    f = open(logfilepath + outputFilename, "w")
+    f.close()            
+    # List of the available plugin modules 
+    plugins = ["cms_watcher","cad_watcher"]
+    #FOR each plugin LOOP
+    for plugin in plugins:
+        # dynamically load the setup function for this plugin
+        plugmodule = globals()[plugin]
+        setupfunc = getattr(plugmodule, 'setup')
+        #Call setup
+        setupfunc()
+    #END LOOP
+    
+    #DO Forever
+    while True:
+    #    Get simulation time
+        timeStamp = getSimTime()
+    #    Reset Output Buffer
+        output = ""
+        results = []
+    #    FOR each plugin LOOP
+        for plugin in plugins:
+            # dynamically load the setup function for this plugin
+            plugmodule = globals()[plugin]
+            getfunc = getattr(plugmodule, 'getLogEntries')
+            
+    #        Run the plugin process returning new log entries
+            results = getfunc()     
+            #    Append simulation time and the log entries to the Output Buffer
+            for item in results:
+                trimmed_item = item.strip()
+                if len(trimmed_item) > 0:
+                    output += timeStamp + ", " + trimmed_item + "\n"
+    #    END LOOP
+    #    IF the Output Buffer has any contents THEN
+        if len(output) > 0:
+    #       Write (append) Output Buffer to unified log file as CSV
+    #       Assumes fields don't contain commas 
+            print output,
+            f = open(logfilepath + outputFilename, "a")
+            f.write(output)
+            f.close()            
+    #    END IF
+    #    Wait five seconds
+        time.sleep(5)
+
+#END DO
+
+if __name__ == '__main__':
+    startup()
Index: trunk/src/python/unifiedlogger/wing_project.wpr
===================================================================
--- trunk/src/python/unifiedlogger/wing_project.wpr	(revision 440)
+++ trunk/src/python/unifiedlogger/wing_project.wpr	(revision 440)
@@ -0,0 +1,545 @@
+#!wing
+#!version=7.0
+##################################################################
+# Wing project file                                              #
+##################################################################
+[project attributes]
+debug.launch-configs = (2,
+                        {'launch-Dap54cn2qAN7AXZm': ({},
+        {'buildcmd': ('project',
+                      None),
+         'env': ('project',
+                 [u'']),
+         'name': 'launchme',
+         'pyexec': ('project',
+                    u''),
+         'pypath': ('project',
+                    []),
+         'pyrunargs': ('project',
+                       '-u'),
+         'runargs': u'',
+         'rundir': ('custom',
+                    u'/home/jdalbey/Dropbox/TMCrepo/trunk')})})
+proj.directory-list = [{'dirloc': loc('.'),
+                        'excludes': (),
+                        'filter': u'*',
+                        'include_hidden': False,
+                        'recursive': True,
+                        'watch_for_changes': True}]
+proj.file-type = 'normal'
+proj.home-dir = loc('../..')
+proj.launch-config = {loc('__main__.py'): ('custom',
+        (u'',
+         'launch-Dap54cn2qAN7AXZm'))}
+proj.main-file = loc('__main__.py')
+[user attributes]
+debug.show-args-dialog = {loc('__main__.py'): False}
+guimgr.overall-gui-state = {'windowing-policy': 'combined-window',
+                            'windows': [{'name': '0BtsNVOAornvyNAPNOxHAmuDFR'\
+        'v7Dw8l',
+        'size-state': 'maximized',
+        'type': 'dock',
+        'view': {'area': 'tall',
+                 'constraint': None,
+                 'current_pages': [4],
+                 'full-screen': False,
+                 'notebook_display': 'normal',
+                 'notebook_percent': 0.3850187265917603,
+                 'override_title': None,
+                 'pagelist': [('source-assistant',
+                               'tall',
+                               2,
+                               {}),
+                              ('debug-stack',
+                               'tall',
+                               1,
+                               {}),
+                              ('browser',
+                               'tall',
+                               0,
+                               {}),
+                              ('indent',
+                               'tall',
+                               2,
+                               {}),
+                              ('debug-io',
+                               'tall',
+                               0,
+                               {}),
+                              ('project',
+                               'tall',
+                               0,
+                               {'tree-state': {'file-sort-method': 'by name',
+        'list-files-first': False,
+        'tree-states': {'deep': {'expanded-nodes': [(0,),
+        (0,
+         0)],
+                                 'selected-nodes': [(0,
+        0,
+        0)],
+                                 'top-node': (0,)}},
+        'tree-style': 'deep'}})],
+                 'primary_view_state': {'area': 'wide',
+        'constraint': None,
+        'current_pages': [3,
+                          1],
+        'notebook_display': 'hidden',
+        'notebook_percent': 0.0,
+        'override_title': None,
+        'pagelist': [('batch-search',
+                      'wide',
+                      0,
+                      {'fScope': {'fFileSetName': 'All Source Files',
+                                  'fLocation': None,
+                                  'fRecursive': True,
+                                  'fType': 'documentation'},
+                       'fSearchSpec': {'fEndPos': None,
+                                       'fIncludeLinenos': True,
+                                       'fInterpretBackslashes': False,
+                                       'fMatchCase': False,
+                                       'fOmitBinary': True,
+                                       'fRegexFlags': 42,
+                                       'fReplaceText': '',
+                                       'fReverse': False,
+                                       'fSearchText': u'default directory policy',
+                                       'fStartPos': 0,
+                                       'fStyle': 'text',
+                                       'fWholeWords': False,
+                                       'fWrap': True},
+                       'fUIOptions': {'fAutoBackground': True,
+                                      'fFilePrefix': 'short-file',
+                                      'fFindAfterReplace': True,
+                                      'fInSelection': False,
+                                      'fIncremental': True,
+                                      'fReplaceOnDisk': False,
+                                      'fShowFirstMatch': False,
+                                      'fShowLineno': True,
+                                      'fShowReplaceWidgets': False},
+                       'replace-entry-expanded': False,
+                       'search-entry-expanded': False}),
+                     ('interactive-search',
+                      'wide',
+                      0,
+                      {'fScope': {'fFileSetName': 'All Source Files',
+                                  'fLocation': None,
+                                  'fRecursive': True,
+                                  'fType': 'project-files'},
+                       'fSearchSpec': {'fEndPos': None,
+                                       'fIncludeLinenos': True,
+                                       'fInterpretBackslashes': False,
+                                       'fMatchCase': False,
+                                       'fOmitBinary': True,
+                                       'fRegexFlags': 42,
+                                       'fReplaceText': u'lastLineNum',
+                                       'fReverse': False,
+                                       'fSearchText': u'fileLength',
+                                       'fStartPos': 0,
+                                       'fStyle': 'text',
+                                       'fWholeWords': False,
+                                       'fWrap': True},
+                       'fUIOptions': {'fAutoBackground': True,
+                                      'fFilePrefix': 'short-file',
+                                      'fFindAfterReplace': True,
+                                      'fInSelection': False,
+                                      'fIncremental': True,
+                                      'fReplaceOnDisk': False,
+                                      'fShowFirstMatch': False,
+                                      'fShowLineno': True,
+                                      'fShowReplaceWidgets': True}}),
+                     ('debug-data',
+                      'wide',
+                      0,
+                      {}),
+                     ('debug-exceptions',
+                      'wide',
+                      0,
+                      {}),
+                     ('python-shell',
+                      'wide',
+                      2,
+                      {'active-range': (None,
+        -1,
+        -1),
+                       'attrib-starts': [],
+                       'code-line': '',
+                       'first-line': 0L,
+                       'folded-linenos': [],
+                       'history': {},
+                       'launch-id': None,
+                       'sel-line': 3L,
+                       'sel-line-start': 132L,
+                       'selection_end': 132L,
+                       'selection_start': 132L,
+                       'zoom': 0L}),
+                     ('messages',
+                      'wide',
+                      2,
+                      {'current-domain': 0}),
+                     ('os-command',
+                      'wide',
+                      1,
+                      {'last-percent': 0.8,
+                       'toolbox-percent': 1.0,
+                       'toolbox-tree-sel': ''})],
+        'primary_view_state': {'editor_states': ({'bookmarks': ([[loc('cms_watcher.py'),
+        {'attrib-starts': [('main|0|',
+                            85)],
+         'code-line': 'def main():\n',
+         'first-line': 60L,
+         'folded-linenos': [],
+         'sel-line': 85L,
+         'sel-line-start': 3074L,
+         'selection_end': 3085L,
+         'selection_start': 3085L,
+         'zoom': 0L},
+        1562878428.05693],
+        [loc('cad_watcher.py'),
+         {'attrib-starts': [],
+          'code-line': '\n',
+          'first-line': 0L,
+          'folded-linenos': [],
+          'sel-line': 10L,
+          'sel-line-start': 402L,
+          'selection_end': 402L,
+          'selection_start': 402L,
+          'zoom': 0L},
+         1562878905.96885],
+        [loc('__main__.py'),
+         {'attrib-starts': [('main|0|',
+                             2)],
+          'code-line': '    print "Unified Logging Service starting from ",o'\
+                       's.getcwd()\n',
+          'first-line': 0L,
+          'folded-linenos': [],
+          'sel-line': 3L,
+          'sel-line-start': 132L,
+          'selection_end': 183L,
+          'selection_start': 183L,
+          'zoom': 0L},
+         1562878936.888077],
+        [loc('../../../../../../../usr/lib/python2.7/ConfigParser.py'),
+         {'attrib-starts': [('ConfigParser|0|',
+                             85),
+                            ('ConfigParser|0|.get|0|',
+                             589)],
+          'code-line': '                raise NoSectionError(section)\n',
+          'first-line': 597L,
+          'folded-linenos': [],
+          'sel-line': 606L,
+          'sel-line-start': 22028L,
+          'selection_end': 22028L,
+          'selection_start': 22028L,
+          'zoom': 0L},
+         1562879070.061342],
+        [loc('../../../../../../../usr/lib/wing-personal7/doc/TOC'),
+         {'displayed-index': 102,
+          'viewer-state': {'history': [-1,
+                                       60,
+                                       -1,
+                                       6,
+                                       1,
+                                       -1,
+                                       102,
+                                       234],
+                           'history-pos': 6,
+                           'index': 102,
+                           'top': 0,
+                           'top-left-pos': 5971}},
+         1562879090.358421],
+        [loc('../../../../../../../usr/lib/wing-personal7/doc/TOC'),
+         {'displayed-index': 234,
+          'viewer-state': {'history': [-1,
+                                       60,
+                                       -1,
+                                       6,
+                                       1,
+                                       -1,
+                                       102,
+                                       234],
+                           'history-pos': 7,
+                           'index': 234,
+                           'top': 0,
+                           'top-left-pos': 20113}},
+         1562879176.767588],
+        [loc('../../../../../../../usr/lib/python2.7/ConfigParser.py'),
+         {'attrib-starts': [('ConfigParser|0|',
+                             85),
+                            ('ConfigParser|0|.get|0|',
+                             589)],
+          'code-line': '                raise NoSectionError(section)\n',
+          'first-line': 597L,
+          'folded-linenos': [],
+          'sel-line': 606L,
+          'sel-line-start': 22028L,
+          'selection_end': 22028L,
+          'selection_start': 22028L,
+          'zoom': 0L},
+         1562879399.049104],
+        [loc('../../../../../../../usr/lib/wing-personal7/doc/TOC'),
+         {'displayed-index': 234,
+          'viewer-state': {'history': [-1,
+                                       60,
+                                       -1,
+                                       6,
+                                       1,
+                                       -1,
+                                       102,
+                                       234],
+                           'history-pos': 7,
+                           'index': 234,
+                           'top': 0,
+                           'top-left-pos': 101}},
+         1562879632.459482],
+        [loc('../../../../../../../usr/lib/python2.7/ConfigParser.py'),
+         {'attrib-starts': [('ConfigParser|0|',
+                             85),
+                            ('ConfigParser|0|.get|0|',
+                             589)],
+          'code-line': '                raise NoSectionError(section)\n',
+          'first-line': 597L,
+          'folded-linenos': [],
+          'sel-line': 606L,
+          'sel-line-start': 22028L,
+          'selection_end': 22028L,
+          'selection_start': 22028L,
+          'zoom': 0L},
+         1562879640.602333],
+        [loc('logging_service.py'),
+         {'attrib-starts': [('startup|0|',
+                             16)],
+          'code-line': '        timeStamp = getSimTime()\n',
+          'first-line': 18L,
+          'folded-linenos': [],
+          'sel-line': 41L,
+          'sel-line-start': 1347L,
+          'selection_end': 1378L,
+          'selection_start': 1378L,
+          'zoom': 0L},
+         1562879647.165641],
+        [loc('__main__.py'),
+         {'attrib-starts': [('main|0|',
+                             2)],
+          'code-line': '    print "Unified Logging Service starting from ",o'\
+                       's.getcwd()\n',
+          'first-line': 0L,
+          'folded-linenos': [],
+          'sel-line': 3L,
+          'sel-line-start': 132L,
+          'selection_end': 183L,
+          'selection_start': 183L,
+          'zoom': 0L},
+         1562879668.696399],
+        [loc('logging_service.py'),
+         {'attrib-starts': [('startup|0|',
+                             16)],
+          'code-line': '        timeStamp = getSimTime()\n',
+          'first-line': 18L,
+          'folded-linenos': [],
+          'sel-line': 41L,
+          'sel-line-start': 1347L,
+          'selection_end': 1378L,
+          'selection_start': 1378L,
+          'zoom': 0L},
+         1562880191.70851],
+        [loc('cms_watcher.py'),
+         {'attrib-starts': [('extractMessages|0|',
+                             45)],
+          'code-line': '\n',
+          'first-line': 45L,
+          'folded-linenos': [],
+          'sel-line': 56L,
+          'sel-line-start': 1978L,
+          'selection_end': 1978L,
+          'selection_start': 1978L,
+          'zoom': 0L},
+         1562880439.712792],
+        [loc('logging_service.py'),
+         {'attrib-starts': [('startup|0|',
+                             16)],
+          'code-line': '        timeStamp = getSimTime()\n',
+          'first-line': 0L,
+          'folded-linenos': [],
+          'sel-line': 41L,
+          'sel-line-start': 1347L,
+          'selection_end': 1378L,
+          'selection_start': 1378L,
+          'zoom': 0L},
+         1562880463.667528],
+        [loc('cms_watcher.py'),
+         {'attrib-starts': [('getLogEntries|0|',
+                             61)],
+          'code-line': "               results.append(\"CMS Updated., \" + l"\
+                       "ocationMap[idList[idx]] + \", '\" + currList[idx] +"\
+                       "\"'\")\n",
+          'first-line': 57L,
+          'folded-linenos': [],
+          'sel-line': 78L,
+          'sel-line-start': 2846L,
+          'selection_end': 2924L,
+          'selection_start': 2924L,
+          'zoom': 0L},
+         1562880625.962149],
+        [loc('cad_watcher.py'),
+         {'attrib-starts': [('setup|0|',
+                             31)],
+          'code-line': '    return\n',
+          'first-line': 24L,
+          'folded-linenos': [],
+          'sel-line': 33L,
+          'sel-line-start': 888L,
+          'selection_end': 898L,
+          'selection_start': 898L,
+          'zoom': 0L},
+         1562882880.377423],
+        [loc('cms_watcher.py'),
+         {'attrib-starts': [('extractMessages|0|',
+                             45)],
+          'code-line': "                    msgList[idx]['cms']['message']['"\
+                       "phase2']['Line2'] + ':' +\n",
+          'first-line': 39L,
+          'folded-linenos': [],
+          'sel-line': 54L,
+          'sel-line-start': 1829L,
+          'selection_end': 1903L,
+          'selection_start': 1903L,
+          'zoom': 0L},
+         1562883842.916941],
+        [loc('logging_service.py'),
+         {'attrib-starts': [('startup|0|',
+                             17)],
+          'code-line': '            f = open(logfilepath + outputFilename, "'\
+                       'a")\n',
+          'first-line': 0L,
+          'folded-linenos': [],
+          'sel-line': 63L,
+          'sel-line-start': 2214L,
+          'selection_end': 2263L,
+          'selection_start': 2263L,
+          'zoom': 0L},
+         1562887416.91585],
+        [loc('__main__.py'),
+         {'attrib-starts': [('main|0|',
+                             2)],
+          'code-line': '    print "Unified Logging Service starting from ",o'\
+                       's.getcwd()\n',
+          'first-line': 0L,
+          'folded-linenos': [],
+          'sel-line': 3L,
+          'sel-line-start': 132L,
+          'selection_end': 183L,
+          'selection_start': 183L,
+          'zoom': 0L},
+         1562892803.750792],
+        [loc('cms_watcher.py'),
+         {'attrib-starts': [('isEmpty|0|',
+                             12)],
+          'code-line': '     return cmsitem == ":::::"\n',
+          'first-line': 0L,
+          'folded-linenos': [],
+          'sel-line': 13L,
+          'sel-line-start': 324L,
+          'selection_end': 353L,
+          'selection_start': 353L,
+          'zoom': 0L},
+         1562893146.713132]],
+        20),
+        'current-loc': loc('__main__.py'),
+        'editor-state-list': [(loc('cad_watcher.py'),
+                               {'attrib-starts': [('setup|0|',
+        31)],
+                                'code-line': '    return\n',
+                                'first-line': 24L,
+                                'folded-linenos': [],
+                                'sel-line': 33L,
+                                'sel-line-start': 888L,
+                                'selection_end': 898L,
+                                'selection_start': 898L,
+                                'zoom': 0L}),
+                              (loc('cms_watcher.py'),
+                               {'attrib-starts': [('isEmpty|0|',
+        12)],
+                                'code-line': '     return cmsitem == ":::::"'\
+        '\n',
+                                'first-line': 0L,
+                                'folded-linenos': [],
+                                'sel-line': 13L,
+                                'sel-line-start': 324L,
+                                'selection_end': 353L,
+                                'selection_start': 353L,
+                                'zoom': 0L}),
+                              (loc('logging_service.py'),
+                               {'attrib-starts': [('startup|0|',
+        17)],
+                                'code-line': '            f = open(logfilepa'\
+        'th + outputFilename, "a")\n',
+                                'first-line': 0L,
+                                'folded-linenos': [],
+                                'sel-line': 63L,
+                                'sel-line-start': 2214L,
+                                'selection_end': 2263L,
+                                'selection_start': 2263L,
+                                'zoom': 0L}),
+                              (loc('__main__.py'),
+                               {'attrib-starts': [('main|0|',
+        2)],
+                                'code-line': '    print "Unified Logging Ser'\
+        'vice starting from ",os.getcwd()\n',
+                                'first-line': 0L,
+                                'folded-linenos': [],
+                                'sel-line': 3L,
+                                'sel-line-start': 132L,
+                                'selection_end': 183L,
+                                'selection_start': 183L,
+                                'zoom': 0L})],
+        'has-focus': True,
+        'locked': False},
+        [loc('cad_watcher.py'),
+         loc('cms_watcher.py'),
+         loc('logging_service.py'),
+         loc('__main__.py')]),
+                               'open_files': [u'cad_watcher.py',
+        u'logging_service.py',
+        u'cms_watcher.py',
+        u'__main__.py']},
+        'saved_notebook_display': None,
+        'split_percents': {0: 0.5},
+        'splits': 2,
+        'tab_location': 'top',
+        'traversal_pos': ((0,
+                           3),
+                          1562879301.119771),
+        'user_data': {}},
+                 'saved_notebook_display': None,
+                 'split_percents': {},
+                 'splits': 1,
+                 'tab_location': 'left',
+                 'traversal_pos': ((0,
+                                    4),
+                                   1562892833.554952),
+                 'user_data': {}},
+        'window-alloc': (29,
+                         0,
+                         1197,
+                         722)}]}
+guimgr.recent-documents = [loc('__main__.py'),
+                           loc('cms_watcher.py'),
+                           loc('logging_service.py'),
+                           loc('cad_watcher.py')]
+guimgr.visual-state = {loc('../../../../../../../usr/lib/python2.7/ConfigParser.py'): {'a'\
+        'ttrib-starts': [('ConfigParser|0|',
+                          85),
+                         ('ConfigParser|0|.get|0|',
+                          589)],
+        'code-line': '                raise NoSectionError(section)\n',
+        'first-line': 597L,
+        'folded-linenos': [],
+        'sel-line': 606L,
+        'sel-line-start': 22028L,
+        'selection_end': 22028L,
+        'selection_start': 22028L,
+        'zoom': 0L}}
+proj.build-cmd = {None: ('default',
+                         None)}
+proj.env-vars = {None: ('default',
+                        [u''])}
+search.search-history = [u'default directory policy']
Index: trunk/src/python/unifiedlogger/cms_watcher.py
===================================================================
--- trunk/src/python/unifiedlogger/cms_watcher.py	(revision 440)
+++ trunk/src/python/unifiedlogger/cms_watcher.py	(revision 440)
@@ -0,0 +1,103 @@
+import json, time
+from copy import deepcopy
+
+# CMS Message Watcher
+# Look for changes in the CMS message file
+# jdalbey  7/6/2019
+idList = []    # list of CMS ID's
+prevList = []  # previous messages
+currList = []  # current messages
+locationMap = {} # map of CMS ID's to locations
+
+# Utility functions
+def isEmpty(cmsitem):
+     return cmsitem == ":::::"
+def isFull(cmsitem):
+     return not isEmpty(cmsitem)
+
+# Read the cms message file
+def readFile():     
+     with open ("webapps/dynamicdata/cms_messages.json",'r') as myfile:
+          jsonData=myfile.read()
+ 
+     return json.loads(jsonData)['data']
+
+# Read the static file of cms locations and create a lookup map
+def loadLocations():
+     with open ("webapps/cptms/data_layers/cms_locations_D12.gjson",'r') as myfile:
+          jsonData=myfile.read()
+ 
+     list = json.loads(jsonData)['features']
+     # add each item to a lookup map
+     for item in list:
+          locationMap [item['id']] = item['properties']['location'] + " " + item['properties']['street']
+     
+# Setup the ID list and initialize the previous messages to empty
+def initialize():
+     loadLocations()
+     msgList = readFile()
+     global prevList, idList
+     for idx in range(0,len(msgList)):
+          idList.append(msgList[idx]['cms']['index'])
+          prevList.append(":::::")
+     return msgList
+
+# Extract the current messages into a list
+def extractMessages(msgList):
+     global currList
+     currList = []
+     for idx in range(0,len(msgList)):
+          currList.append(
+                    msgList[idx]['cms']['message']['phase1']['Line1'] + ':' + 
+                    msgList[idx]['cms']['message']['phase1']['Line2'] + ':' +
+                    msgList[idx]['cms']['message']['phase1']['Line3'] + ':' +
+                    msgList[idx]['cms']['message']['phase2']['Line1'] + ':' +
+                    msgList[idx]['cms']['message']['phase2']['Line2'] + ':' +
+                    msgList[idx]['cms']['message']['phase2']['Line3'])
+
+def setup():
+     extractMessages(initialize())
+
+# compare previous messages to current messages to look for changes
+def getLogEntries():
+     global prevList, currList
+     msgList = readFile()
+     extractMessages(msgList)
+     size = len(currList)
+     
+     results = []
+     # Consider each CMS message
+     for idx in range(0,size):
+          # Is a new message activated?
+          if isEmpty(prevList[idx]) and isFull(currList[idx]):
+               results.append("CMS Activated.," + locationMap[idList[idx]] + ", '" + currList[idx] +"'")
+          # Is an existing message turned off?
+          if isEmpty(currList[idx]) and isFull(prevList[idx]):
+               results.append("CMS Deactivated., " + locationMap[idList[idx]])
+          # Did a message change?
+          if isFull(currList[idx]) and isFull(prevList[idx]) and currList[idx] != prevList[idx]:
+               results.append("CMS Updated., " + locationMap[idList[idx]] + ", '" + currList[idx] +"'")
+
+     # Save the current list as previous
+     prevList = deepcopy(currList)
+     return results
+
+# Local main for unit testing
+def main():
+     global currList
+     setup()
+     # Loop Forever
+     while True:
+          # Look for changed messages
+          answer = getLogEntries()
+          # Output results
+          for item in answer:
+               print item
+          # wait 
+          time.sleep(5)
+          # Get the current messages
+          extractMessages(readFile())
+
+if __name__ == "__main__":
+     main()
+     
Index: trunk/src/python/unifiedlogger/__main__.py
===================================================================
--- trunk/src/python/unifiedlogger/__main__.py	(revision 439)
+++ trunk/src/python/unifiedlogger/__main__.py	(revision 439)
@@ -0,0 +1,8 @@
+import logging_service, os
+# This main module is provided so the application can be conveniently bundled for deployment
+def main():
+    print "Unified Logging Service starting from ",os.getcwd()
+    logging_service.startup()
+
+if __name__ == '__main__':
+    main()
Index: trunk/src/python/demo/config/logging_service.cfg
===================================================================
--- trunk/src/python/demo/config/logging_service.cfg	(revision 440)
+++ trunk/src/python/demo/config/logging_service.cfg	(revision 440)
@@ -0,0 +1,2 @@
+[Paths]
+UnifiedLogPath = ../dynamicdata/
Index: trunk/src/python/demo/__main__.py
===================================================================
--- trunk/src/python/demo/__main__.py	(revision 440)
+++ trunk/src/python/demo/__main__.py	(revision 440)
@@ -0,0 +1,15 @@
+import os, ConfigParser
+
+# This main module is provided so the application can be conveniently bundled for deployment
+def main():
+    print os.getcwd()
+    print "Hello Demo World"
+
+    # get path to output file from configuration
+    config = ConfigParser.ConfigParser()
+    config.read('config/logging_service.cfg')
+    logfilepath  = config.get('Paths', 'UnifiedLogPath')
+    print "logfile path is: ",logfilepath
+
+if __name__ == '__main__':
+    main()
