diff --git a/src/python/pyrte.c b/src/python/pyrte.c
old mode 100755
new mode 100644
index 4faf67d9e880b4660203a492fd8d833d016ec074_c3JjL3B5dGhvbi9weXJ0ZS5j..bdd8cb18f7176c99a537d760568ae9717df424b3_c3JjL3B5dGhvbi9weXJ0ZS5j
--- a/src/python/pyrte.c
+++ b/src/python/pyrte.c
@@ -95,6 +95,13 @@
 
 Python functions provided by this module:
 
+  wasd.cgi_callout()
+
+    Initiate a CGI callout to the server.
+    The required parameter provides the callout request string.
+    If the request string begins with '!' or '#' the callout will return
+    Py_None, otherwise the response string.
+
   wasd.cgiplus_begin()
 
     This function is used to synchronise an explicitly CGIplus script
@@ -111,6 +118,10 @@
     function can be used to obtain the same data (and some variables
     that don't make it into os.environ (e.g. FORM_..).
 
+  wasd.read_cgiplusin()
+
+    Read a record from the CGIPLUSIN stream (caution!)
+
   wasd.reuse_interpreter()
 
     See discussion of 'latencies' above.  Takes one arugment; True to reuse
@@ -146,6 +157,10 @@
 
     Returns an integer representing the number of times this RTE has been used.
 
+  wasd.write()
+
+    Writes directly to <stdout> with a following fflush().
+
 
 WSGI INTERFACE
 --------------
@@ -183,7 +198,8 @@
 Python/C API Reference Manual, Release 2.4.3
 Extending and Embedding the Python Interpreter, Release 2.4.3
 Lots of Googling with many and varied query strings.
+http://python3porting.com/cextensions.html
 
 
 PYRTE COPYRIGHT
 ---------------
@@ -186,8 +202,8 @@
 
 
 PYRTE COPYRIGHT
 ---------------
-Copyright (C) 2007-2013 Mark G.Daniel
+Copyright (C) 2007-2020 Mark G.Daniel
 This package comes with ABSOLUTELY NO WARRANTY.
 This is free software, and you are welcome to redistribute it under the
 conditions of the GNU GENERAL PUBLIC LICENSE, version 3, or any later version.
@@ -272,7 +288,7 @@
 
 LOGICAL NAMES
 -------------
-PYRTE$DBUG         enables all if(Debug) output statements;
+PYRTE$DBUG         enables all if(dbug) output statements;
                      if some unique part of the script debugs just that script
                      if defined to something like 'c' or '/' or '-' debugs all
                      (this script-name check is CASE-SENSITIVE)
@@ -283,8 +299,10 @@
 PYRTE_CACHE_MAX    integer size of code cache (zero to compare uncached)
 PYRTE_METRICS      enable metric collection and report via "?$metrics$" query
 PYRTE_NOREUSE_INTERPRETER   do not reuse interpreter for each script instance
-PYRTE_USAGE_LIMIT   integer number of requests before voluntary exit
-PYRTE_WSGI_FORCE_BUFFERING  enable buffering with WASD, this break the WSGI
+PYRTE_ONESHOT      voluntary exit after a single use (see PYRTE_USAGE_LIMIT) 
+PYRTE_STAT_TIMER   incorporate basic stats in HTML comment
+PYRTE_USAGE_LIMIT  integer number of requests before voluntary exit
+PYRTE_WSGI_FORCE_BUFFERING  enable buffering with WASD, this breaks the WSGI
                             specification but may give a performance boost.
 
 BUILD DETAILS
@@ -296,6 +314,13 @@
 
 VERSION HISTORY (update SOFTWAREVN as well!)
 ---------------
+20-AUG-2020  MGD  v3.0.0,  Python 3 (via JFP Python 3.10.0a0)
+                  v2.0.0,  Python 2 equivalent
+                           Python 2.7.18 build kludge for
+                             VSI C V7.4-001 on OpenVMS IA64 V8.4-2L1
+22-JUL-2017  MGD  v1.1.12, wasd.cgi_callout and RtePyMethCgiCallout()
+                             provides callout environment regardless of WSGI
+                           bugfix; stderr = freopen(stderr);
 20-JUN-2013  MGD  v1.1.11, bugfix; ProcessCachingRte() it appears to be
                              necessary to destroy *EnvironDict along with
                              using Py_EndInterpreter()
@@ -323,8 +348,9 @@
 */
 /*****************************************************************************/
 
-#define SOFTWARECR "Copyright (C) 2007-2013 Mark G.Daniel"
-#define SOFTWAREVN "1.1.11"
+#define SOFTWARECR "Copyright (C) 2007-2020 Mark G.Daniel"
+#define SOFTWAREVN "x.0.0"  /* just the minor and tweak versions here! */
+/** ----------------^^^^^ and IDENTIFICATION=x.n.n in BUILD_PYRTE[n].COM **/
 #define SOFTWARENM "PYRTE"
 #ifdef __ALPHA
 #  define SOFTWAREID SOFTWARENM " AXP-" SOFTWAREVN
@@ -366,5 +392,16 @@
 */
 #include <unistd.h>
 
+/* 2.7.18 build kludge */
+#ifdef __ia64
+/** VSI C V7.4-001 on OpenVMS IA64 V8.4-2L1 **/
+#ifndef intmax_t
+typedef signed long long int intmax_t;
+typedef unsigned long long int uintmax_t;
+typedef signed long long int intptr_t;
+typedef unsigned long long int uintptr_t;
+#endif
+#endif
+
 /* Python-specific includes (must come first!) */
 
@@ -369,5 +406,8 @@
 /* Python-specific includes (must come first!) */
 
+/** INTERIM **/
+#define PY_SSIZE_T_CLEAN
+
 #include <python.h>
 
 /* standard C header files */
@@ -382,8 +422,9 @@
 #include <time.h>
 #include <unixlib.h>
 #include <unixio.h>
+#include <wchar.h>
 
 /* VMS-specific header files */
 
 #include <cvt$routines.h>
 #include <cvtdef.h>
@@ -385,8 +426,9 @@
 
 /* VMS-specific header files */
 
 #include <cvt$routines.h>
 #include <cvtdef.h>
+#include <fabdef.h>
 #include <jpidef.h>
 #include <lib$routines.h>
 #include <libdef.h>
@@ -399,6 +441,13 @@
 /* macros */
 /**********/
 
+/** INTERIM **/
+#if PY_MAJOR_VERSION >= 3
+#define PyArg_ParseTuple                _PyArg_ParseTuple_SizeT
+#define PyArg_ParseTupleAndKeywords     _PyArg_ParseTupleAndKeywords_SizeT
+#define Py_BuildValue                   _Py_BuildValue_SizeT
+#endif
+
 #ifndef BUILD_DATETIME
 #  define BUILD_DATETIME "(undefined)"
 #endif
@@ -406,7 +455,7 @@
 #define OBJREFCNT(pobj) ((pobj)->ob_refcnt)
 
 #define DEBUGPYOBJ(sobj,pobj) \
-   if (Debug) \
+   if (dbug) \
    { \
       fprintf (stdout, "\n***** %s ***** ", sobj); \
       PyObject_Print (pobj, stdout, 0); \
@@ -414,9 +463,9 @@
    }
 
 #define DEBUGREFCNT(sobj,pobj) \
-   if (Debug) \
+   if (dbug) \
       fprintf (stdout, "%s%s->ob_refcnt: %d\n", \
                sobj, (pobj) ? "" : "(null)", (pobj) ? pobj->ob_refcnt : 0);
 
 #define FI_LI __FILE__, __LINE__
 
@@ -418,9 +467,14 @@
       fprintf (stdout, "%s%s->ob_refcnt: %d\n", \
                sobj, (pobj) ? "" : "(null)", (pobj) ? pobj->ob_refcnt : 0);
 
 #define FI_LI __FILE__, __LINE__
 
+/* mainly to allow easy use of the __unaligned directive */
+#define ULONGPTR __unaligned unsigned long*
+#define USHORTPTR __unaligned unsigned short*
+#define INT64PTR __unaligned __int64*
+
 /******************/
 /* global storage */
 /******************/
 
@@ -423,7 +477,8 @@
 /******************/
 /* global storage */
 /******************/
 
-int  AppOutputCount,
+int  dbug,
+     AppOutputCount,
      CgiPlusPythonEnd,
      CodeMetricEnabled,
@@ -428,6 +483,5 @@
      CgiPlusPythonEnd,
      CodeMetricEnabled,
-     Debug,
      GlobalDebug,
      HeadCvtGet,
      IsCgiPlusMode,
@@ -466,6 +520,10 @@
       ErrorPython [] = "Error initialising Python environment.",
       ErrorWsgiEnv [] = "Error initialising WSGI environment.";
 
+char  SoftwareId [] = SOFTWAREID;
+
+FILE  *CgiPlusInFp;
+
 PyObject  *pBuiltins,
           *pError,
           *pEnvironDict,
@@ -527,4 +585,7 @@
    char *FileNamePtr,
         *FileNameByteCodePtr;
    PyThreadState  *pInterpState;
+#if PY_MAJOR_VERSION >= 3
+   PyObject  *pByteCode;
+#else
    PyCodeObject  *pByteCode;
@@ -530,4 +591,5 @@
    PyCodeObject  *pByteCode;
+#endif
    struct CodeMetricStruct  *CodeMetricPtr;
 }
 CodeCache [CACHE_MAX];
@@ -538,6 +600,14 @@
 /* python extension methods */
 /****************************/
 
+static PyObject* RtePyMethCgiCallout ();
+
+PyDoc_STRVAR (rte_cgi_callout__doc__,
+"Initiate a CGI callout to the server. \
+The required parameter provides the callout request string. \
+If the request string begins with '!' or '#' the callout will return \
+NULL otherwise the callout response string.");
+
 static PyObject* RtePyMethCgiPlusBegin (PyObject*, PyObject*);
 
 PyDoc_STRVAR (rte_cgiplus_begin__doc__,
@@ -560,6 +630,11 @@
 in the function argument. Generally CGI variables are accessed from \
 os.environ in the same manner as other environment variables.");
 
+static PyObject* RtePyMethReadCgiPlusIn ();
+
+PyDoc_STRVAR (rte_read_cgiplusin__doc__,
+"Retuns a string containing a record read from the CGIPLUSIN stream.");
+
 static PyObject* RtePyMethReuseInterpreter ();
 
 PyDoc_STRVAR (rte_reuse_interpreter__doc__,
@@ -619,7 +694,7 @@
 PyDoc_STRVAR (wsgi_write__doc__,
 "Write direct to <stdout>.");
 
-/* Jean-Fran�ois Pi�ronne's original '_wasd' module functions */ 
+/* Jean-Francois Pieronne's original '_wasd' module functions */ 
 
 static PyObject* wasd_cgi_init ();
 static PyObject* wasd_isCgiPlus ();
@@ -630,10 +705,11 @@
 static struct PyMethodDef RtePyMethods [] =
 {
    /* WASD PyRTE methods */
-
+   { "cgi_callout", (PyCFunction)RtePyMethCgiCallout, METH_VARARGS,
+                     rte_cgi_callout__doc__ },
    { "cgiplus_begin", (PyCFunction)RtePyMethCgiPlusBegin, METH_VARARGS,
                        rte_cgiplus_begin__doc__ },
    { "cgiplus_end", (PyCFunction)RtePyMethCgiPlusEnd, METH_VARARGS,
                      rte_cgiplus_end__doc__ },
    { "getvar", (PyCFunction)RtePyMethGetVar, METH_VARARGS,
                 rte_getvar__doc__ },
@@ -634,9 +710,11 @@
    { "cgiplus_begin", (PyCFunction)RtePyMethCgiPlusBegin, METH_VARARGS,
                        rte_cgiplus_begin__doc__ },
    { "cgiplus_end", (PyCFunction)RtePyMethCgiPlusEnd, METH_VARARGS,
                      rte_cgiplus_end__doc__ },
    { "getvar", (PyCFunction)RtePyMethGetVar, METH_VARARGS,
                 rte_getvar__doc__ },
+   { "read_cgiplusin", (PyCFunction)RtePyMethReadCgiPlusIn, METH_VARARGS,
+                rte_read_cgiplusin__doc__ },
    { "reuse_interpreter", (PyCFunction)RtePyMethReuseInterpreter, METH_VARARGS,
                            rte_reuse_interpreter__doc__ },
    { "rte_cache_entry", (PyCFunction)RtePyMethRteCacheEntry, METH_VARARGS,
@@ -663,5 +741,5 @@
 
    /* JFP's original '_wasd' module functions */ 
 
-   { "cgi_init", (PyCFunction)wasd_cgi_init, 0,
+   { "cgi_init", (PyCFunction)wasd_cgi_init, METH_NOARGS,
                  "initialise CGIplus environment" },
@@ -667,3 +745,3 @@
                  "initialise CGIplus environment" },
-   { "isCgiPlus", (PyCFunction)wasd_isCgiPlus, 0,
+   { "isCgiPlus", (PyCFunction)wasd_isCgiPlus, METH_NOARGS,
                   "is it activated in CGIplus mode?" },
@@ -669,5 +747,5 @@
                   "is it activated in CGIplus mode?" },
-   { "cgi_eof", (PyCFunction)wasd_cgi_eof, 0,
+   { "cgi_eof", (PyCFunction)wasd_cgi_eof, METH_NOARGS,
                 "concludes the current CGIplus request" },
    { "cgi_info", (PyCFunction)wasd_cgi_info, METH_VARARGS,
                  "return a CGI variable" },
@@ -677,6 +755,20 @@
    { NULL, NULL, 0, NULL }
 };
 
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef RtePyModuleDef = {
+   PyModuleDef_HEAD_INIT,
+   "wasd",               /* m_name */
+   "WASD pyRTE module\n",  /* m_doc */
+   -1,                   /* m_size */
+   RtePyMethods,         /* m_methods */
+   NULL,                 /* m_reload */
+   NULL,                 /* m_traverse */
+   NULL,                 /* m_clear */
+   NULL,                 /* m_free */
+};
+#endif
+
 /**************/
 /* prototypes */
 /**************/
@@ -687,6 +779,7 @@
 char* CgiVar (char*);
 char* CgiVarDclSymbol (char*);
 void CollectMetrics (struct CodeCacheStruct*, int);
+void DbugCheck ();
 int EmptyScriptName (char*, char*);
 void EnsureExit (unsigned long*);
 void FlushCacheEntry (struct CodeCacheStruct*);
@@ -701,5 +794,6 @@
 void ProcessBasicRte ();
 void ProcessCachingRte ();
 int ProctorDetect ();
+int ReadFileIntoMemory (char*, char**, int*);
 void ReportError (int, int, int, char*, ...);
 void RteScriptParam ();
@@ -704,5 +798,6 @@
 void ReportError (int, int, int, char*, ...);
 void RteScriptParam ();
+void SetProgramName (char*);
 int SetupOsEnvCgiVar (int);
 char* StatTimer (int);
 char* TrnLnm (char*, char*);
@@ -706,6 +801,7 @@
 int SetupOsEnvCgiVar (int);
 char* StatTimer (int);
 char* TrnLnm (char*, char*);
+int WasdModuleInit (void);
 int WsgiSendHeaders ();
 int WsgiSendResponse (PyObject*);
 int WsgiOsEnvVar ();
@@ -709,6 +805,14 @@
 int WsgiSendHeaders ();
 int WsgiSendResponse (PyObject*);
 int WsgiOsEnvVar ();
-
+#if PY_MAJOR_VERSION >= 3
+wchar_t** MungeArgv (int, char*[]);
+#else
+char** MungeArgv (int, char*[]);
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+PyAPI_FUNC(void) PyNode_Free (struct _mod*);
+#else
 /* not in an include file for some reason (adapted from node.h)*/
 PyAPI_FUNC(void) PyNode_Free (struct _node*);
@@ -713,5 +817,6 @@
 /* not in an include file for some reason (adapted from node.h)*/
 PyAPI_FUNC(void) PyNode_Free (struct _node*);
+#endif
 PyAPI_FUNC(PyObject*) PyMarshal_ReadObjectFromFile(FILE*);
 unsigned long PyMarshal_ReadLongFromFile(FILE*);
 
@@ -741,7 +846,16 @@
    /* begin */
    /*********/
 
+#if PY_MAJOR_VERSION >= 3
+    *strchr(SoftwareId,'x') = '3';
+#else
+    *strchr(SoftwareId,'x') = '2';
+#endif
+
+   /* set the global pointer used by some functions */
+   CodeCachePtr = &CodeCache[0];
+
    if (argc == 2)
    {
       if (!strncasecmp(argv[1], "/cli=", 5))
       {
@@ -744,10 +858,11 @@
    if (argc == 2)
    {
       if (!strncasecmp(argv[1], "/cli=", 5))
       {
+         DbugCheck();
          ProcessCLI (argv[1]+5);
          exit (SS$_NORMAL);
       }
       if (!strcasecmp(argv[1], "/version"))
       {
          fprintf (stdout, "%%PYRTE-I-VERSION, %s (%s)\n%s\n%s",
@@ -748,10 +863,10 @@
          ProcessCLI (argv[1]+5);
          exit (SS$_NORMAL);
       }
       if (!strcasecmp(argv[1], "/version"))
       {
          fprintf (stdout, "%%PYRTE-I-VERSION, %s (%s)\n%s\n%s",
-                  SOFTWAREID, BUILD_DATETIME, SOFTWARECR, SOFTWAREGPL);
+                  SoftwareId, BUILD_DATETIME, SOFTWARECR, SOFTWAREGPL);
          exit (SS$_NORMAL);
       }
    }
@@ -759,14 +874,7 @@
    status = sys$getjpiw (0, 0, 0, &JpiItems, 0, 0, 0);
    if (!(status & 1)) exit (status);
 
-   /* this is almost a 'bit too clever' :-) */
-   if ((cptr = TrnLnm ("PYRTE$DBUG", NULL)) != NULL)
-      if (strchr (cptr, '*'))
-         if (GlobalDebug = Debug = 1)
-         {
-            fputs ("Content-Type: text/plain\n\n", stdout);
-            fflush (stdout);
-         }
+   DbugCheck();
 
    WsgiForceBuffering = 
          (TrnLnm ("PYRTE_WSGI_FORCE_BUFFERING", NULL) != NULL);
@@ -774,7 +882,7 @@
    /* if it doesn't look like CGI environment then forget it */
    if (!TrnLnm ("HTTP$INPUT", NULL)) exit (SS$_ABORT);
 
-   if (!Debug)
+   if (!dbug)
    {
       /* binary mode to eliminate carriage-control */
       if (!(stdin = freopen ("HTTP$INPUT:", "r", stdin,
@@ -783,7 +891,7 @@
       if (!(stdout = freopen ("SYS$OUTPUT:", "w", stdout,
                               "ctx=bin", "ctx=xplct")))
          exit (vaxc$errno);
-      if (!(stdout = freopen ("SYS$ERROR:", "w", stderr,
+      if (!(stderr = freopen ("SYS$ERROR:", "w", stderr,
                               "ctx=bin", "ctx=xplct")))
          exit (vaxc$errno);
    }
@@ -791,6 +899,8 @@
    cptr = TrnLnm ("PYRTE_USAGE_LIMIT", NULL);
    if (cptr && isdigit(*cptr)) UsageLimit = atoi(cptr);
 
+   if (TrnLnm ("PYRTE_ONESHOT", NULL)) UsageLimit = 1;
+
    /* need differentiate between RTE/CGIplus and CGIplus script */
    IsCgiPlusMode = (TrnLnm ("CGIPLUSEOF", NULL) != NULL);
    CgiPlusEofPtr = TrnLnm ("CGIPLUSEOF", CgiPlusEof);
@@ -854,7 +964,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "EnsureExit() %%X%08.08X\n", ExitStatus);
+   if (dbug) fprintf (stdout, "EnsureExit() %%X%08.08X\n", ExitStatus);
 
    if (ExitStatus & 0x00000001) exit (ExitStatus);
 
@@ -878,6 +988,8 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "ProcessCLI()\n");
-
+   if (dbug) fprintf (stdout, "ProcessCLI()\n");
+
+   SetProgramName (ScriptName);
+   WasdModuleInit ();
    Py_Initialize();
@@ -883,8 +995,5 @@
    Py_Initialize();
-   pWasdModule = Py_InitModule ("wasd", RtePyMethods);
-
-   Py_SetProgramName (ScriptName);
 
    fp = fopen (ScriptName, "r");
    if (fp)
    {
@@ -887,7 +996,8 @@
 
    fp = fopen (ScriptName, "r");
    if (fp)
    {
+      if (dbug) fprintf (stdout, "fp:%u\n", fp);
       PyRun_AnyFileExFlags (fp, ScriptName, 0, NULL);
       fclose (fp);
    }
@@ -897,7 +1007,10 @@
       ReportError (__LINE__, status, 0, "Error opening !AZ", ScriptName);
    }
 
-   Py_Finalize();
+   Py_Finalize ();
+
+   if (dbug || TrnLnm ("PYRTE_STAT_TIMER",NULL))
+      fprintf (stdout, "<!-- %s -->\n", StatTimer(TRUE));
 }
 
 /*****************************************************************************/
@@ -920,16 +1033,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "ProcessCGI()\n");
-
-   Py_Initialize();
-   pWasdModule = Py_InitModule ("wasd", RtePyMethods);
-
-   sptr = CgiVar ("SCRIPT_NAME");
-   Py_SetProgramName (sptr);
-
-   /* NEEDS WORK!! */
-   PySys_SetArgv (argc, argv);
-
-   cptr = CgiVar ("SCRIPT_FILENAME");
+   if (dbug) fprintf (stdout, "ProcessCGI()\n");
+
+   cptr = sptr = CgiVar ("PATH_INFO");
    fp = fopen (cptr, "r");
@@ -935,3 +1039,8 @@
    fp = fopen (cptr, "r");
+   if (!fp)
+   {
+      sptr = CgiVar ("PATH_TRANSLATED");
+      fp = fopen (sptr, "r");
+   }
    if (fp)
    {
@@ -936,3 +1045,11 @@
    if (fp)
    {
+      StatTimer(FALSE);
+
+      SetProgramName (cptr);
+      WasdModuleInit ();
+      Py_Initialize();
+
+      PySys_SetArgv (argc, MungeArgv(argc,argv));
+
       PyRun_AnyFileExFlags (fp, cptr, 0, NULL);
@@ -938,4 +1055,10 @@
       PyRun_AnyFileExFlags (fp, cptr, 0, NULL);
+
+      if (dbug || TrnLnm ("PYRTE_STAT_TIMER",NULL))
+         fprintf (stdout, "<!-- %s -->\n", StatTimer(TRUE));
+
+      Py_Finalize();
+
       fclose (fp);
    }
    else
@@ -943,8 +1066,6 @@
       status = vaxc$errno;
       ReportError (__LINE__, status, 0, "Error opening !AZ", sptr);
    }
-
-   Py_Finalize();
 }
 
 /*****************************************************************************/
@@ -967,8 +1088,8 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "ProcessCGIplus() %d\n", argc);
+   if (dbug) fprintf (stdout, "ProcessCGIplus() %d\n", argc);
 
    /* code behaviours are different for an explicitly CGIplus script */
    IsCgiPlusScript = 1;
 
@@ -971,9 +1092,10 @@
 
    /* code behaviours are different for an explicitly CGIplus script */
    IsCgiPlusScript = 1;
 
+   SetProgramName (argv[1]);
    Py_Initialize();
 
    /* just use the first element of the code cache */
    ccptr = &CodeCache[0];
 
@@ -975,11 +1097,8 @@
    Py_Initialize();
 
    /* just use the first element of the code cache */
    ccptr = &CodeCache[0];
 
-   /* set the global pointer used by some functions */
-   CodeCachePtr = ccptr;
-
    /* it will have been used the once! */
    ccptr->InterpreterUsageCount++;
 
@@ -983,6 +1102,4 @@
    /* it will have been used the once! */
    ccptr->InterpreterUsageCount++;
 
-   Py_SetProgramName (argv[1]);
-
    /* first is RTE image, second CGIplus script, then optional parameters */
@@ -988,5 +1105,5 @@
    /* first is RTE image, second CGIplus script, then optional parameters */
-   PySys_SetArgv (argc-1, &argv[1]);
+   PySys_SetArgv (argc-1, MungeArgv(argc,&argv[1]));
 
    LoadByteCode (argv[1], argv[1], ccptr);
    if (!ccptr->pByteCode) return;
@@ -1019,13 +1136,8 @@
    }
    DEBUGPYOBJ("pOsDict",pOsDict)
 
-   pWasdModule = Py_InitModule ("wasd", RtePyMethods);
-   if (!pWasdModule)
-   {
-      ReportError (__LINE__, 0, 1, ErrorPython);
-      return;
-   }
+   if (!WasdModuleInit ()) return;
 
    /* get the first request (which is already available and won't block) */
    CgiVar ("");
 
@@ -1028,17 +1140,8 @@
 
    /* get the first request (which is already available and won't block) */
    CgiVar ("");
 
-   if (!(Debug = GlobalDebug))
-      if (cptr = TrnLnm ("PYRTE$DBUG", NULL))
-         if (sptr = CgiVar ("SCRIPT_NAME"))
-            if (strstr (sptr, cptr))
-               Debug = 1;
-   if (Debug)
-   {
-      fputs ("Content-Type: text/plain\n\n", stdout);
-      fflush (stdout);
-   }
+   DbugCheck();
 
    RteScriptParam ();
 
@@ -1061,6 +1164,6 @@
    fputs (CgiPlusEofPtr, stdout);
    fflush (stdout);
 
-   if (!GlobalDebug) Debug = 0;
+   if (!GlobalDebug) dbug = 0;
 
    Py_Finalize();
@@ -1065,5 +1168,8 @@
 
    Py_Finalize();
+
+   if (dbug || TrnLnm ("PYRTE_STAT_TIMER",NULL))
+      fprintf (stdout, "<!-- %s -->\n", StatTimer(TRUE));
 }
 
 /*****************************************************************************/
@@ -1085,7 +1191,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "ProcessBasicRte()\n");
+   if (dbug) fprintf (stdout, "ProcessBasicRte()\n");
 
    for (;;)
    {
@@ -1094,5 +1200,6 @@
       /* initialise this for special CGI-and-CGIplus script cases */
       RtePyMethCgiPlusBegin (NULL, NULL);
 
-      /* try to get some of the work out of the way before next request */
+      SetProgramName ("ProcessBasicRte()");
+      if (!WasdModuleInit()) break;
       Py_Initialize();
@@ -1098,12 +1205,6 @@
       Py_Initialize();
-      pWasdModule = Py_InitModule ("wasd", RtePyMethods);
-      if (!pWasdModule)
-      {
-         ReportError (__LINE__, 0, 1, ErrorPython);
-         return;
-      }
 
       /* block waiting for the first/next request */
       CgiVar ("");
       UsageCount++;
 
@@ -1105,20 +1206,18 @@
 
       /* block waiting for the first/next request */
       CgiVar ("");
       UsageCount++;
 
-      if (!(Debug = GlobalDebug))
-         if (cptr = TrnLnm ("PYRTE$DBUG", NULL))
-            if (sptr = CgiVar ("SCRIPT_NAME"))
-               if (strstr (sptr, cptr))
-                  Debug = 1;
-      if (Debug)
-      {
-         fputs ("Content-Type: text/plain\n\n", stdout);
-         fflush (stdout);
-      }
+      DbugCheck();
+
+      cptr = sptr = CgiVar ("SCRIPT_FILENAME");
+      SetProgramName (cptr);
+
+      /* fudge these */
+      argv[0] = cptr;
+      PySys_SetArgv (1, MungeArgv(1,argv));
 
       RteScriptParam ();
 
       if (!NoStreamMode) fprintf (stdout, "Script-Control: X-stream-mode\n");
 
@@ -1120,16 +1219,8 @@
 
       RteScriptParam ();
 
       if (!NoStreamMode) fprintf (stdout, "Script-Control: X-stream-mode\n");
 
-      cptr = CgiVar ("SCRIPT_FILENAME");
-
-      Py_SetProgramName (cptr);
-
-      /* fudge these */
-      argv[0] = cptr;
-      PySys_SetArgv (1, argv);
-
-      fp = fopen (cptr, "r", "shr=get");
+      fp = fopen (sptr, "r", "shr=get");
       if (fp)
       {
@@ -1134,6 +1225,6 @@
       if (fp)
       {
-         PyRun_AnyFileExFlags (fp, cptr, 0, NULL);
+         PyRun_AnyFileExFlags (fp, sptr, 0, NULL);
          fclose (fp);
       }
       else
@@ -1145,7 +1236,10 @@
 
       Py_Finalize();
 
+      if (dbug || TrnLnm ("PYRTE_STAT_TIMER",NULL))
+         fprintf (stdout, "<!-- %s -->\n", StatTimer(TRUE));
+
       fflush (stdout);
       fputs (CgiPlusEofPtr, stdout);
       fflush (stdout);
 
@@ -1148,8 +1242,8 @@
       fflush (stdout);
       fputs (CgiPlusEofPtr, stdout);
       fflush (stdout);
 
-      if (!GlobalDebug) Debug = 0;
+      if (!GlobalDebug) dbug = 0;
 
       if (UsageLimit && UsageCount >= UsageLimit) break;
    }
@@ -1161,9 +1255,7 @@
 (compiled) byte-code for a number of scripts (determined by compilation
 constant and logical name value).  The byte-code used is either loaded from
 pre-compiled file content (.PYO or .PYC) or compiled dynamically (and then
-cached) from a source file (.PY).  Also, and based on RTE or script
-configuration, maintain a cache of pre-initialized (and previously used) Python
-subinterpreters.
+cached) from a source file (.PY).
 */
 
 void ProcessCachingRte ()
@@ -1172,8 +1264,8 @@
    int  idx, tidx, retval, status;
    unsigned long  mtime,
                   CurrentTimeSecs;
-   char  *cptr, *sptr;
+   char  *cptr, *fnptr, *sptr, *snptr;
    char  *argv [2] = { NULL, NULL };
    struct CodeCacheStruct  *ccptr;
    PyObject  *pObject,
              *pResult;
@@ -1176,11 +1268,9 @@
    char  *argv [2] = { NULL, NULL };
    struct CodeCacheStruct  *ccptr;
    PyObject  *pObject,
              *pResult;
-   PyThreadState  *pStateBuffer,
-                  *pNewInterpState = NULL;
 
    /*********/
    /* begin */
    /*********/
 
@@ -1182,11 +1272,11 @@
 
    /*********/
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "ProcessCachingRte()\n");
+   if (dbug) fprintf (stdout, "ProcessCachingRte()\n");
 
    cptr = TrnLnm ("PYRTE_CACHE_MAX", NULL);
    if (cptr && isdigit(*cptr)) CodeCacheMax = atoi(cptr);
    if (CodeCacheMax > CACHE_MAX) CodeCacheMax = CACHE_MAX;
 
@@ -1188,14 +1278,11 @@
 
    cptr = TrnLnm ("PYRTE_CACHE_MAX", NULL);
    if (cptr && isdigit(*cptr)) CodeCacheMax = atoi(cptr);
    if (CodeCacheMax > CACHE_MAX) CodeCacheMax = CACHE_MAX;
 
-   Py_Initialize();
-   PyEval_InitThreads ();
-
    for (;;)
    {
       /********/
       /* wait */
       /********/
 
@@ -1196,25 +1283,9 @@
    for (;;)
    {
       /********/
       /* wait */
       /********/
 
-      if (!pNewInterpState)
-      {
-         /*
-            Create a new interpreter *before* checking for the next request.
-            This reduces response latency where requests are not back-to-back.
-         */
-         pStateBuffer = PyEval_SaveThread ();
-         pNewInterpState = Py_NewInterpreter ();
-         if (!pNewInterpState)
-         {
-            ReportError (__LINE__, 0, 0, "Error initialising interpreter.");
-            break;
-         }
-         PyThreadState_Swap (pStateBuffer);
-      }
-
       /* initialise this for special CGI-and-CGIplus script cases */
       RtePyMethCgiPlusBegin (NULL, NULL);
 
@@ -1218,5 +1289,9 @@
       /* initialise this for special CGI-and-CGIplus script cases */
       RtePyMethCgiPlusBegin (NULL, NULL);
 
+      SetProgramName ("ProcessBasicRte()");
+      if (!WasdModuleInit()) break;
+      Py_Initialize();
+
       /* block waiting for the first/next request */
       CgiVar ("");
@@ -1221,4 +1296,5 @@
       /* block waiting for the first/next request */
       CgiVar ("");
+
       sys$gettim (&CurrentBinTime);
       CurrentTimeSecs = decc$fix_time (&CurrentBinTime);
@@ -1223,16 +1299,6 @@
       sys$gettim (&CurrentBinTime);
       CurrentTimeSecs = decc$fix_time (&CurrentBinTime);
-
-      if (!(Debug = GlobalDebug))
-         if (cptr = TrnLnm ("PYRTE$DBUG", NULL))
-            if (sptr = CgiVar ("SCRIPT_NAME"))
-               if (strstr (sptr, cptr))
-                  Debug = 1;
-      if (Debug)
-      {
-         fputs ("Content-Type: text/plain\n\n", stdout);
-         fflush (stdout);
-      }
+      DbugCheck();
 
       if (TrnLnm ("PYRTE_METRICS", NULL))
          CodeMetricEnabled = 1;
@@ -1254,8 +1320,8 @@
       /* request */
       /***********/
 
-      cptr = CgiVar ("SCRIPT_FILENAME");
-      if (!cptr)
+      fnptr = CgiVar ("SCRIPT_FILENAME");
+      if (!fnptr)
       {
          ReportError (__LINE__, 0, 0, "Error getting SCRIPT_FILENAME.");
          break;
@@ -1273,8 +1339,10 @@
       /* byte-code cache */
       /*******************/
 
+      if (dbug) fprintf (stdout, "CodeCacheCount:%d\n", CodeCacheCount);
+
       /* look to see if we have the script byte-code cached */
       for (idx = 0; idx < CodeCacheCount; idx++)
       {
          ccptr = &CodeCache[idx];
          if (!ccptr->FileNamePtr) continue;
@@ -1276,8 +1344,8 @@
       /* look to see if we have the script byte-code cached */
       for (idx = 0; idx < CodeCacheCount; idx++)
       {
          ccptr = &CodeCache[idx];
          if (!ccptr->FileNamePtr) continue;
-         if (Debug) fprintf (stdout, "%d %d |%s|%s|\n",
+         if (dbug) fprintf (stdout, "%d %d |%s|%s|\n",
                              idx, ccptr->InterpreterUsageCount,
                              cptr, ccptr->FileNamePtr);
@@ -1282,7 +1350,7 @@
                              idx, ccptr->InterpreterUsageCount,
                              cptr, ccptr->FileNamePtr);
-         if (!strcasecmp (cptr, ccptr->FileNamePtr)) break;
-         ccptr++;
+         if (!strcasecmp (fnptr, ccptr->FileNamePtr)) break;
+         ccptr = NULL;
       }
 
       if (idx < CodeCacheCount)
@@ -1291,6 +1359,7 @@
          /* found cache */
          /***************/
 
+         if (dbug) fprintf (stdout, "hit:%d\n", idx);
          if (!ByteCodeUpToDate (ccptr))
          {
             /* apparently not */
@@ -1310,7 +1379,7 @@
          if (tidx < CodeCacheCount)
             ccptr = &CodeCache[tidx];
          else
-         if (idx < CodeCacheMax)
+         if (tidx < CodeCacheMax)
          {
             /* didn't find an unused entry */
             CodeCacheCount++;
@@ -1314,7 +1383,7 @@
          {
             /* didn't find an unused entry */
             CodeCacheCount++;
-            ccptr = &CodeCache[idx];
+            ccptr = &CodeCache[tidx];
          }
          else
          {
@@ -1325,6 +1394,7 @@
             ccptr = &CodeCache[tidx];
             FlushCacheEntry (ccptr);
          }
+         idx = tidx;
       }
       else
       {
@@ -1332,6 +1402,8 @@
          ccptr = &CodeCache[0];
          if (ccptr->FileNamePtr) FlushCacheEntry (ccptr);
       }
+      if (dbug) fprintf (stdout, "CodeCacheCount:%d idx:%d usage:%d\n",
+                         CodeCacheCount, idx, ccptr->CodeUsageCount);
 
       /* set the global pointer used by some functions */
       CodeCachePtr = ccptr;
@@ -1342,20 +1414,10 @@
          /* load script */
          /***************/
 
-         if (ccptr->pInterpState)
-         {
-            /* also lose any previously associated interpreter */
-            pStateBuffer = PyThreadState_Swap (ccptr->pInterpState);
-            Py_EndInterpreter (ccptr->pInterpState);
-            PyThreadState_Swap (pStateBuffer);
-            ccptr->pInterpState = NULL;
-            ccptr->InterpreterUsageCount = 0;
-         }
-
-         sptr = CgiVar ("SCRIPT_NAME");
-         if (!sptr)
+         snptr = CgiVar ("SCRIPT_NAME");
+         if (!snptr)
          {
             ReportError (__LINE__, 0, 0, "Error getting SCRIPT_NAME.");
             break;
          }
 
@@ -1357,9 +1419,9 @@
          {
             ReportError (__LINE__, 0, 0, "Error getting SCRIPT_NAME.");
             break;
          }
 
-         LoadByteCode (cptr, sptr, ccptr);
+         LoadByteCode (fnptr, snptr, ccptr);
 
          AddMetrics (ccptr);
       }
@@ -1375,23 +1437,6 @@
          ccptr->CodeUsageCount++;
          ccptr->LastUsedSecs = CurrentTimeSecs;
 
-         if (!ccptr->pInterpState)
-         {
-            /* associate an interpreter with the byte-code */
-            ccptr->pInterpState = pNewInterpState;
-            pNewInterpState = NULL;
-
-            /* fudge the arguments */
-            pStateBuffer = PyThreadState_Swap (ccptr->pInterpState);
-            Py_SetProgramName (cptr);
-            argv[0] = cptr;
-            PySys_SetArgv (1, argv);
-            PyThreadState_Swap (pStateBuffer);
-         }
-         ccptr->InterpreterUsageCount++;
-
-         pStateBuffer = PyThreadState_Swap (ccptr->pInterpState);
-
          /* borrowed reference */
          pMainModule = PyImport_AddModule ("__main__");
          if (!pMainModule)
@@ -1424,13 +1469,5 @@
          }
          DEBUGPYOBJ("pOsDict",pOsDict)
 
-         /* borrowed reference */
-         pWasdModule = Py_InitModule ("wasd", RtePyMethods);
-         if (!pWasdModule)
-         {
-            ReportError (__LINE__, 0, 1, ErrorPython);
-            return;
-         }
-
          if (!SetupOsEnvCgiVar (1)) return;
 
@@ -1435,4 +1472,6 @@
          if (!SetupOsEnvCgiVar (1)) return;
 
+         SetProgramName (snptr);
+
          PyErr_Clear ();
 
@@ -1437,6 +1476,5 @@
          PyErr_Clear ();
 
-         /* new reference */
          pResult = PyEval_EvalCode (ccptr->pByteCode, pMainDict, pMainDict);
          /* new reference */
          if (pError = PyErr_Occurred())
@@ -1450,10 +1488,6 @@
 
          /* new reference, can be NULL */
          Py_XDECREF (pResult);
-
-         DEBUGPYOBJ("pMainDict",pMainDict)
- 
-         PyThreadState_Swap (pStateBuffer);
       }
       else
       {
@@ -1461,7 +1495,9 @@
          FlushCacheEntry (ccptr);
       }
 
+      Py_Finalize();
+
       /******************/
       /* end of request */
       /******************/
 
@@ -1464,9 +1500,7 @@
       /******************/
       /* end of request */
       /******************/
 
-      fflush (stdout);
-
       /* after the flush to accumulate any outstanding BIO */
       CollectMetrics (ccptr, 1);
 
@@ -1470,6 +1504,10 @@
       /* after the flush to accumulate any outstanding BIO */
       CollectMetrics (ccptr, 1);
 
+      if (dbug || TrnLnm ("PYRTE_STAT_TIMER",NULL))
+         fprintf (stdout, "<!-- %s -->\n", StatTimer(TRUE));
+
+      fflush (stdout);
       fputs (CgiPlusEofPtr, stdout);
       fflush (stdout);
 
@@ -1473,23 +1511,7 @@
       fputs (CgiPlusEofPtr, stdout);
       fflush (stdout);
 
-      if (ccptr->pInterpState)
-      {
-         if (!ReuseInterpreter || !ccptr->FileNamePtr)
-         {
-            pStateBuffer = PyThreadState_Swap (ccptr->pInterpState);
-            Py_EndInterpreter (ccptr->pInterpState);
-            PyThreadState_Swap (pStateBuffer);
-            ccptr->pInterpState = NULL;
-            ccptr->InterpreterUsageCount = 0;
-            /* these seem to need to go after the interpreter */
-            Py_DECREF (pEnvironDict);
-            Py_DECREF (pOsEnvironDict);
-            pEnvironDict = pOsEnvironDict = NULL;
-         }
-      }
-
-      if (!GlobalDebug) Debug = 0;
+      if (!GlobalDebug) dbug = 0;
 
       if (UsageLimit && UsageCount >= UsageLimit) break;
    }
@@ -1493,8 +1515,6 @@
 
       if (UsageLimit && UsageCount >= UsageLimit) break;
    }
-
-   Py_Finalize();
 }
 
 /*****************************************************************************/
@@ -1510,7 +1530,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "FlushCacheEntry()\n");
+   if (dbug) fprintf (stdout, "FlushCacheEntry()\n");
 
    if (ccptr->FileNamePtr)
    {
@@ -1531,6 +1551,156 @@
 
 /*****************************************************************************/
 /*
+Initialise the internal WASD module.
+Declared before WasdModuleInit() to avoid protyping.
+*/
+
+#if PY_MAJOR_VERSION >= 3
+
+PyObject* WasdModuleInit2 (void)
+
+{
+   PyObject*  modptr;
+
+   /*********/
+   /* begin */
+   /*********/
+
+   modptr = PyModule_Create (&RtePyModuleDef);
+   if (!modptr) return (modptr);
+   PyModule_AddObject (modptr, "__path__", Py_BuildValue("()"));
+   return (modptr);
+}
+
+#else /* PY_MAJOR_VERSION < 3 */
+
+void WasdModuleInit2 (void)
+
+{
+   PyObject*  modptr;
+
+   /*********/
+   /* begin */
+   /*********/
+
+   modptr = Py_InitModule ("wasd", RtePyMethods);
+   if (!modptr) return;
+   PyModule_AddObject (modptr, "__path__", Py_BuildValue("()"));
+}
+
+#endif /* PY_MAJOR_VERSION >= 3 */
+
+/*****************************************************************************/
+/*
+Initialise the internal WASD module.
+*/
+
+int WasdModuleInit (void)
+
+{
+   /*********/
+   /* begin */
+   /*********/
+
+   if (dbug) fprintf (stdout, "WasdModuleInit()\n");
+
+   if (PyImport_AppendInittab ("wasd", &WasdModuleInit2) >= 0) return (1);
+   ReportError (__LINE__, 0, 1, ErrorPython);
+   return (0);
+}
+
+/*****************************************************************************/
+/*
+Set the programme name (doh).
+*/
+
+void SetProgramName (char* name)
+
+{
+   wchar_t  *wcptr;
+
+   /*********/
+   /* begin */
+   /*********/
+
+   if (dbug) fprintf (stdout, "SetProgramName() |%s|\n", name);
+
+   if (!name) return;
+#if PY_MAJOR_VERSION >= 3
+   wcptr = Py_DecodeLocale (name, NULL);
+   Py_SetProgramName (wcptr);
+   PyMem_RawFree (wcptr);
+#else
+   Py_SetProgramName (name);
+#endif
+}
+
+/*****************************************************************************/
+/*
+For Python 3 covert an array of pointers to char to an array of pointers to
+wide char.  For Python 2 just return the original array of pointers to char.
+*/
+
+#if PY_MAJOR_VERSION >= 3
+
+wchar_t** MungeArgv (int argc, char *argv[])
+
+{
+   static wchar_t*  wargv [32];
+
+   int  idx;
+
+   /*********/
+   /* begin */
+   /*********/
+
+   if (dbug) fprintf (stdout, "MungeArgv()\n");
+
+   /* completely arbitrary */
+   if (argc >= 32) exit (SS$_BUGCHECK);
+
+   /* free any existing array of wide strings */
+   for (idx = 0; idx < 32; idx++)
+   {
+      if (!wargv[idx]) continue;
+      if (wargv[idx]) PyMem_RawFree (wargv[idx]);
+      wargv[idx] = NULL;
+   }
+
+   for (idx = 0; idx < argc; idx++)
+   {
+      if (dbug) fprintf (stdout, "%d |%s|\n", idx, argv[idx]);
+      if (!argv[idx]) return (NULL);
+      wargv[idx] = Py_DecodeLocale (argv[idx], NULL);
+   }
+
+   return (wargv);
+}
+
+#else /* PY_MAJOR_VERSION < 3 */
+
+char** MungeArgv (int argc, char *argv[])
+
+{
+   int  idx;
+
+   /*********/
+   /* begin */
+   /*********/
+
+   if (dbug) fprintf (stdout, "MungeArgv()\n");
+
+   if (dbug)
+      for (idx = 0; idx < argc; idx++)
+         fprintf (stdout, "%d |%s|\n", idx, argv[idx]);
+
+   return (argv);
+}
+
+#endif /* PY_MAJOR_VERSION >= 3 */
+
+/*****************************************************************************/
+/*
 Create the script byte-code by either loading the source code (.PY) and
 compiling, or loading the pre-compiled byte code (.PYC) or optimised,
 pre-compiled byte-code (.PYO).  Reports it's own errors.  Success is indicated
@@ -1545,6 +1715,6 @@
 struct CodeCacheStruct *ccptr
 )
 {
-   int  status,
+   int  flen, status,
         FileNameLength;
    unsigned long  magic, mtime;
@@ -1549,7 +1719,7 @@
         FileNameLength;
    unsigned long  magic, mtime;
-   char  *cptr, *sptr, *zptr,
+   char  *cptr, *fptr, *sptr, *zptr,
          *CharPtr;
    char  FileNameByteCode [256];
    FILE  *fp;
    stat_t  FstatBuffer;
@@ -1552,5 +1722,8 @@
          *CharPtr;
    char  FileNameByteCode [256];
    FILE  *fp;
    stat_t  FstatBuffer;
+#if PY_MAJOR_VERSION >= 3
+   struct _mod  *pNode;
+#else
    struct _node  *pNode;
@@ -1556,7 +1729,8 @@
    struct _node  *pNode;
+#endif
    struct CodeMetricStruct  *cmptr;
 
    /*********/
    /* begin */
    /*********/
 
@@ -1557,10 +1731,10 @@
    struct CodeMetricStruct  *cmptr;
 
    /*********/
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "LoadByteCode() |%s|\n", FileName);
+   if (dbug) fprintf (stdout, "LoadByteCode() |%s|\n", FileName);
 
    ccptr->LastUsedSecs = ccptr->ScriptMtimeSecs = ccptr->CodeUsageCount = 0;
 
@@ -1589,7 +1763,7 @@
    fp = NULL;
    for (;;)
    {
-      if (Debug) fprintf (stdout, "|%s|\n", FileNameByteCode);
+      if (dbug) fprintf (stdout, "|%s|\n", FileNameByteCode);
       /* note; opened in 'binary' mode */
       fp = fopen (FileNameByteCode, "rb", "shr=get");
       if (fp) break;
@@ -1602,7 +1776,7 @@
    {
       /* well, it's certainly not pre-compiled! */
       FileNameByteCode[0] = '\0';
-      if (Debug) fprintf (stdout, "|%s|\n", FileName);
+      if (dbug) fprintf (stdout, "|%s|\n", FileName);
       /* note; opened in 'record' mode */
       fp = fopen (FileName, "r", "ctx=rec", "shr=get");
       if (!fp)
@@ -1627,4 +1801,7 @@
       magic = PyMarshal_ReadLongFromFile (fp);
       mtime = PyMarshal_ReadLongFromFile (fp);
       /* what's left is the byte-code */
+#if PY_MAJOR_VERSION >= 3
+      ccptr->pByteCode = PyMarshal_ReadObjectFromFile (fp);
+#else
       ccptr->pByteCode = (PyCodeObject*)PyMarshal_ReadObjectFromFile (fp);
@@ -1630,4 +1807,5 @@
       ccptr->pByteCode = (PyCodeObject*)PyMarshal_ReadObjectFromFile (fp);
+#endif
       fclose (fp);
       if (!ccptr->pByteCode)
       {
@@ -1638,10 +1816,9 @@
    else
    {
       /* source code file */
-      pNode = PyParser_SimpleParseFile (fp, ScriptName, Py_file_input);
-      fclose (fp);
-      if (!pNode)
+      status = ReadFileIntoMemory (FileName, &fptr, &flen);
+      if (!(status & 1))
       {
          ReportError (__LINE__, 0, 1, NULL);
          return;
       }
@@ -1644,9 +1821,15 @@
       {
          ReportError (__LINE__, 0, 1, NULL);
          return;
       }
-      ccptr->pByteCode = (PyCodeObject*) PyNode_Compile (pNode, ScriptName);
-      PyNode_Free (pNode);
+#if PY_MAJOR_VERSION >= 3
+      ccptr->pByteCode = Py_CompileString (fptr, ScriptName, Py_file_input);
+#else
+      ccptr->pByteCode = (PyCodeObject*)Py_CompileString (fptr, ScriptName,
+                                                          Py_file_input);
+#endif
+      free (fptr);
+      fclose (fp);
       if (!ccptr->pByteCode)
       {
          ReportError (__LINE__, 0, 1, NULL);
@@ -1665,8 +1848,16 @@
       if (!ccptr->FileNameByteCodePtr) exit (vaxc$errno);
       strcpy (ccptr->FileNameByteCodePtr, FileNameByteCode);
    }
-   if (Debug) fprintf (stdout, "|%s|%s|\n", ccptr->FileNamePtr,
-                       ccptr->FileNameByteCodePtr);
+   if (dbug)
+   {
+      fprintf (stdout, "|%s|%s| %u", ccptr->FileNamePtr,
+               ccptr->FileNameByteCodePtr, ccptr->pByteCode);
+#if PY_MAJOR_VERSION >= 3
+      DEBUGPYOBJ("->pByteCode", ccptr->pByteCode)
+#else
+      DEBUGPYOBJ("->pByteCode", (struct _object*)ccptr->pByteCode)
+#endif
+   }
 }
 
 /*****************************************************************************/
@@ -1684,7 +1875,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "ByteCodeUpToDate()\n");
+   if (dbug) fprintf (stdout, "ByteCodeUpToDate()\n");
 
    if (ccptr->FileNameByteCodePtr)
       retval = stat (ccptr->FileNameByteCodePtr, &StatBuffer);
@@ -1692,8 +1883,9 @@
       retval = stat (ccptr->FileNamePtr, &StatBuffer);
    if (retval) return (0);
    /* if the script file is more recent than the cached byte-code */
-   if (Debug) fprintf (stdout, "|%d|%d|\n",
-                       StatBuffer.st_mtime, ccptr->ScriptMtimeSecs);
+   if (dbug) fprintf (stdout, "|%d|%d|%s\n",
+                       StatBuffer.st_mtime, ccptr->ScriptMtimeSecs,
+                 StatBuffer.st_mtime == ccptr->ScriptMtimeSecs ? "YES" : "NO");
    if (StatBuffer.st_mtime != ccptr->ScriptMtimeSecs) return (0);
    return (1);
 }
@@ -1719,7 +1911,7 @@
    /*********/
 
 /**
-   if (Debug) fprintf (stdout, "RteStdoutWrite()\n");
+   if (dbug) fprintf (stdout, "RteStdoutWrite()\n");
    DEBUGPYOBJ("self",self)
    DEBUGPYOBJ("args",args)
 **/
@@ -1734,4 +1926,7 @@
       return (Py_None);
    }
 
+#if PY_MAJOR_VERSION >= 3
+   if (PyBytes_Check (pValue))
+#else
    if (PyString_Check (pValue))
@@ -1737,2 +1932,3 @@
    if (PyString_Check (pValue))
+#endif
    {
@@ -1738,4 +1934,11 @@
    {
+#if PY_MAJOR_VERSION >= 3
+      PyBytes_AsStringAndSize (pValue, &DataPtr, &DataLength);
+#else
+      PyString_AsStringAndSize (pValue, &DataPtr, &DataLength);
+#endif
+      if (dbug) fprintf (stdout, "%d |%s|\n", DataLength, DataPtr);
+
       /* if the deprecated WSGI write() method is being used */
       if (WsgiRunApp && !WsgiHeadersSent) WsgiSendHeaders ();
 
@@ -1739,8 +1942,6 @@
       /* if the deprecated WSGI write() method is being used */
       if (WsgiRunApp && !WsgiHeadersSent) WsgiSendHeaders ();
 
-      PyString_AsStringAndSize (pValue, &DataPtr, &DataLength);
-
       AppOutputCount += DataLength;
 
       fwrite (DataPtr, DataLength, 1, stdout);
@@ -1776,10 +1977,10 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "SetupOsEnvCgiVar() %d\n", InitEnv);
+   if (dbug) fprintf (stdout, "SetupOsEnvCgiVar() %d\n", InitEnv);
 
    if (!HeadCvtGet)
       HeadCvtGet = (TrnLnm ("PYRTE_HEAD_CVT_GET", NULL) != NULL);
 
    if (InitEnv)
    {
@@ -1780,8 +1981,10 @@
 
    if (!HeadCvtGet)
       HeadCvtGet = (TrnLnm ("PYRTE_HEAD_CVT_GET", NULL) != NULL);
 
    if (InitEnv)
    {
+      /* borrowed reference */
+      pOsEnvironDict = PyDict_GetItemString (pOsDict, "environ");
       if (!pOsEnvironDict)
       {
@@ -1786,18 +1989,5 @@
       if (!pOsEnvironDict)
       {
-         /* borrowed reference */
-         pOsEnvironDict = PyDict_GetItemString (pOsDict, "environ");
-         if (!pOsEnvironDict)
-         {
-            ReportError (__LINE__, 0, 1, ErrorCgiVarEnv);
-            return (0);
-         }
-         Py_INCREF (pOsEnvironDict);
-         DEBUGPYOBJ("pOsEnvironDict",pOsEnvironDict)
-      }
-
-      if (!pEnvironDict)
-      {
-         /* new reference */
-         pEnvironDict = PyObject_CallMethod(pOsEnvironDict, "copy", "()");
+         ReportError (__LINE__, 0, 1, ErrorCgiVarEnv);
+         return (0);
       }
@@ -1803,29 +1993,9 @@
       }
-      else
-      {      
-          /* Restore missing environ variables */
-          pKeys = PyMapping_Keys(pOsEnvironDict);
-          pKenLen = PyList_Size(pKeys);
-          for (int i = 0; i < pKenLen; ++i)
-          {
-              pKey = PyList_GetItem(pKeys, i);
-              if (! PyMapping_HasKey(pEnvironDict, pKey))
-              {
-                  char *key;
-                  key = PyString_AsString(pKey);
-                  pValue = PyMapping_GetItemString(pOsEnvironDict, key);
-                  retval = PyMapping_SetItemString(pEnvironDict, key, pValue);
-                  if (retval == -1)
-                  {
-                      ReportError (__LINE__, 0, 1, ErrorCgiVarEnv);
-                      return (0);
-                  }
-                  Py_DECREF(pValue);
-              }
-          }
-          Py_DECREF(pKeys);
-      }
+      DEBUGPYOBJ("pOsEnvironDict",pOsEnvironDict)
+
+      /* new reference */
+      pEnvironDict = PyObject_CallMethod(pOsEnvironDict, "copy", "()");
       DEBUGPYOBJ("pEnvironDict",pEnvironDict)
 
       while (cptr = CgiVar ("*"))
       {
@@ -1828,8 +1998,8 @@
       DEBUGPYOBJ("pEnvironDict",pEnvironDict)
 
       while (cptr = CgiVar ("*"))
       {
-         /** if (Debug) fprintf (stdout, "|%s|\n", cptr); **/
+         /** if (dbug) fprintf (stdout, "|%s|\n", cptr); **/
 
          if ((toupper(*cptr) == 'F' &&
               !strncmp (cptr, "FORM_", 5)) ||
@@ -1852,4 +2022,7 @@
          for (sptr = cptr; *sptr && *sptr != '='; sptr++);
          if (!*sptr) continue;
          *sptr = '\0';
+#if PY_MAJOR_VERSION >= 3
+         pValue = PyUnicode_FromString (sptr+1);
+#else
          pValue = PyString_FromString (sptr+1);
@@ -1855,4 +2028,5 @@
          pValue = PyString_FromString (sptr+1);
+#endif
          retval = PyMapping_SetItemString (pEnvironDict, cptr, pValue);
          if (retval == -1)
          {
@@ -1870,6 +2044,6 @@
          ReportError (__LINE__, 0, 1, ErrorCgiVarEnv);
          return (0);
       }
-      if (Debug) fprintf (stdout, "PyMapping_SetItemString() %d\n", retval);
+      if (dbug) fprintf (stdout, "PyMapping_SetItemString() %d\n", retval);
    }
    else
@@ -1874,11 +2048,6 @@
    }
    else
-   {
-      DEBUGPYOBJ("1pEnvironDict",pEnvironDict)
-      pValue = PyObject_CallMethod(pEnvironDict, "clear", "()");
-      Py_DECREF (pValue);
-      DEBUGPYOBJ("2pEnvironDict",pEnvironDict)
-   }
+      Py_DECREF (pEnvironDict);
 
    return (1);
 }
@@ -1904,7 +2073,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "RtePyMethGetVar()\n");
+   if (dbug) fprintf (stdout, "RtePyMethGetVar()\n");
 
    if (!PyArg_ParseTuple (args, "S|O", &pVarName, &pVarDefault)) return (NULL);
 
@@ -1908,4 +2077,7 @@
 
    if (!PyArg_ParseTuple (args, "S|O", &pVarName, &pVarDefault)) return (NULL);
 
+#if PY_MAJOR_VERSION >= 3
+   if (!(cptr = PyBytes_AsString (pVarName))) return (NULL);
+#else
    if (!(cptr = PyString_AsString (pVarName))) return (NULL);
@@ -1911,4 +2083,5 @@
    if (!(cptr = PyString_AsString (pVarName))) return (NULL);
+#endif
    if (!(sptr = CgiVar (cptr)))
    {
       if (pVarDefault) return (pVarDefault);
@@ -1931,7 +2104,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "RtePyMethUsageCode()\n");
+   if (dbug) fprintf (stdout, "RtePyMethUsageCode()\n");
 
    return (Py_BuildValue ("i", CodeCachePtr->CodeUsageCount));
 }
@@ -1948,7 +2121,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "RtePyMethUsageInterpreter()\n");
+   if (dbug) fprintf (stdout, "RtePyMethUsageInterpreter()\n");
 
    return (Py_BuildValue ("i", CodeCachePtr->InterpreterUsageCount));
 }
@@ -1965,7 +2138,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "RtePyMethUsageRte()\n");
+   if (dbug) fprintf (stdout, "RtePyMethUsageRte()\n");
 
    return (Py_BuildValue ("i", UsageCount));
 }
@@ -1982,7 +2155,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "RtePyMethStatTimer()\n");
+   if (dbug) fprintf (stdout, "RtePyMethStatTimer()\n");
 
    return (Py_BuildValue ("s", StatTimer (TRUE)));
 }
@@ -2025,7 +2198,7 @@
       return (NULL);
    }
 
-   if (Debug) fprintf (stdout, "RtePyMethCgiPlusBegin()\n");
+   if (dbug) fprintf (stdout, "RtePyMethCgiPlusBegin()\n");
 
    if (WsgiRunApp)
    {
@@ -2087,16 +2260,7 @@
    CgiPlusPythonEnd = 1;
    AppOutputCount = 0;
 
-   if (!(Debug = GlobalDebug))
-      if (cptr = TrnLnm ("PYRTE$DBUG", NULL))
-         if (sptr = CgiVar ("SCRIPT_NAME"))
-            if (strstr (sptr, cptr))
-               Debug = 1;
-   if (Debug)
-   {
-      fputs ("Content-Type: text/plain\n\n", stdout);
-      fflush (stdout);
-   }
+   DbugCheck();
 
    RteScriptParam ();
 
@@ -2135,7 +2299,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "RtePyMethCgiPlusEnd()\n");
+   if (dbug) fprintf (stdout, "RtePyMethCgiPlusEnd()\n");
 
    if (!IsCgiPlusScript)
    {
@@ -2167,6 +2331,111 @@
 
 /*****************************************************************************/
 /*
+Full CGI callout including response as available.
+*/
+
+static PyObject* RtePyMethCgiCallout
+(
+PyObject *self,
+PyObject *args
+)
+{
+   int  retval;
+   char  *sptr;
+   char  buf [1024];
+   PyObject*  pReturn;
+
+   if (!PyArg_ParseTuple (args, "s", &sptr)) return (NULL);
+
+   fflush(stdout);
+   fputs (CgiPlusEscPtr, stdout);
+   fflush(stdout);
+   fputs (sptr, stdout);
+   fflush(stdout);
+
+   if (*sptr == '!' || *sptr == '#')
+   {
+      Py_INCREF (Py_None);
+      pReturn = Py_None;
+   }
+   else
+   {
+      /* with plain old CGI might not already be open */
+      if (!CgiPlusInFp)
+         if (!(CgiPlusInFp = fopen (TrnLnm("CGIPLUSIN", NULL), "r")))
+            exit (vaxc$errno);
+
+      rewind (CgiPlusInFp);
+      retval = read (fileno(CgiPlusInFp), buf, sizeof(buf));
+      if (retval < 0)
+      {
+         Py_INCREF (Py_None);
+         pReturn = Py_None;
+      }
+      else
+      {
+         /* excise the (CRTL) trailing newline */
+         if (retval) retval--;
+#if PY_MAJOR_VERSION >= 3
+         pReturn = PyUnicode_FromStringAndSize (buf, retval);
+#else
+         pReturn = PyString_FromStringAndSize (buf, retval);
+#endif
+      }
+   }
+
+   fputs (CgiPlusEotPtr, stdout);
+   fflush(stdout);
+
+   return (pReturn);
+}
+
+/*****************************************************************************/
+/*
+Read a record directly from CGIPLUSIN.
+Optional parameter specifies non-default (255 bytes) size of buffer.
+*/
+
+static PyObject* RtePyMethReadCgiPlusIn
+(
+PyObject *self,
+PyObject *args
+)
+{
+   int  bsize, retval;
+   char  *bptr;
+   PyObject*  pReturn;
+
+   bsize = 255;
+   if (!PyArg_ParseTuple(args, "|i", &bsize)) return (NULL);
+   bptr = calloc (1, bsize+32);
+
+   rewind (CgiPlusInFp);
+   retval = read (fileno(CgiPlusInFp), bptr, bsize);
+
+   if (retval < 0)
+   {
+      Py_INCREF (Py_None);
+      pReturn = Py_None;
+   }
+   else
+   {
+      /* excise the (CRTL) trailing newline */
+      if (retval) retval--;
+#if PY_MAJOR_VERSION >= 3
+      pReturn = PyUnicode_FromStringAndSize (bptr, retval);
+#else
+      pReturn = PyString_FromStringAndSize (bptr, retval);
+#endif
+   }
+
+   free (bptr);
+
+   return (pReturn);
+}
+
+/*****************************************************************************/
+/*
 Set whether the Python interpreter being used is disposed of at the end of the
 current request (0 or False) or resued for the next request (1 or True).
 */
@@ -2181,7 +2450,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "RtePyMethReuseInterpreter()\n");
+   if (dbug) fprintf (stdout, "RtePyMethReuseInterpreter()\n");
 
    if (!PyArg_ParseTuple (args, "i", &ReuseInterpreter)) return (NULL);
    Py_INCREF(Py_None);
@@ -2202,9 +2471,9 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "RtePyMethRteId()\n");
-
-   sprintf (RteIdBuf, "%s, %s", SOFTWAREID, BUILD_DATETIME);
+   if (dbug) fprintf (stdout, "RtePyMethRteId()\n");
+
+   sprintf (RteIdBuf, "%s, %s", SoftwareId, BUILD_DATETIME);
    return (Py_BuildValue ("s", RteIdBuf));
 }
 
@@ -2230,7 +2499,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "RtePyMethRteCacheEntry()\n");
+   if (dbug) fprintf (stdout, "RtePyMethRteCacheEntry()\n");
 
    if (!TrnLnm ("PYRTE_CACHE_ENTRY", NULL))
    {
@@ -2288,7 +2557,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "WsgiRun()\n");
+   if (dbug) fprintf (stdout, "WsgiRun()\n");
 
    WsgiRunApp = 1;
 
@@ -2351,7 +2620,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "WsgiStartResponse()\n");
+   if (dbug) fprintf (stdout, "WsgiStartResponse()\n");
 
    if (!WsgiRunApp)
    {
@@ -2431,9 +2700,9 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "WsgiSendResponse() 0x%08.08x\n", pResponse);
+   if (dbug) fprintf (stdout, "WsgiSendResponse() 0x%08.08x\n", pResponse);
 
    if (!WsgiRunApp || !pResponse) return (1);
 
    DEBUGPYOBJ("pResponse",pResponse)
 
@@ -2435,6 +2704,9 @@
 
    if (!WsgiRunApp || !pResponse) return (1);
 
    DEBUGPYOBJ("pResponse",pResponse)
 
+#if PY_MAJOR_VERSION >= 3
+   if (PyBytes_Check (pResponse))
+#else
    if (PyString_Check (pResponse))
@@ -2440,2 +2712,3 @@
    if (PyString_Check (pResponse))
+#endif
    {
@@ -2441,2 +2714,5 @@
    {
+#if PY_MAJOR_VERSION >= 3
+      PyBytes_AsStringAndSize (pResponse, &DataPtr, &DataLength);
+#else
       PyString_AsStringAndSize (pResponse, &DataPtr, &DataLength);
@@ -2442,4 +2718,6 @@
       PyString_AsStringAndSize (pResponse, &DataPtr, &DataLength);
+#endif
+      if (dbug) fprintf (stdout, "%d |%s|\n", DataLength, DataPtr);
       AppOutputCount += DataLength;
       fwrite (DataPtr, DataLength, 1, stdout);
       return (1);
@@ -2451,4 +2729,7 @@
    while (pItem = PyIter_Next(pIter))
    {
       if (!WsgiHeadersSent) WsgiSendHeaders ();
+#if PY_MAJOR_VERSION >= 3
+      if (PyBytes_Check (pItem))
+#else
       if (PyString_Check (pItem))
@@ -2454,2 +2735,6 @@
       if (PyString_Check (pItem))
+#endif
+#if PY_MAJOR_VERSION >= 3
+         if (!PyBytes_AsStringAndSize (pItem, &DataPtr, &DataLength))
+#else
          if (!PyString_AsStringAndSize (pItem, &DataPtr, &DataLength))
@@ -2455,3 +2740,4 @@
          if (!PyString_AsStringAndSize (pItem, &DataPtr, &DataLength))
+#endif
             if (DataPtr && DataLength)
             {
@@ -2456,6 +2742,6 @@
             if (DataPtr && DataLength)
             {
-               /** if (Debug) fprintf (stdout, "pIter()\n"); **/
+               /** if (dbug) fprintf (stdout, "pIter()\n"); **/
                AppOutputCount += DataLength;
                fwrite (DataPtr, DataLength, 1, stdout);
                if (!WsgiForceBuffering) fflush (stdout);
@@ -2490,9 +2776,9 @@
    /* begin */
    /*********/
 
-   if (Debug)
+   if (dbug)
       fprintf (stdout, "WsgiSendHeaders() 0x%08.08x 0x%08.08x\n",
                pWsgiStatus, pWsgiHeaders);
 
    if (!pWsgiHeaders || !pWsgiStatus) return (0);
 
@@ -2494,6 +2780,9 @@
       fprintf (stdout, "WsgiSendHeaders() 0x%08.08x 0x%08.08x\n",
                pWsgiStatus, pWsgiHeaders);
 
    if (!pWsgiHeaders || !pWsgiStatus) return (0);
 
+#if PY_MAJOR_VERSION >= 3
+   if (!PyBytes_Check (pWsgiStatus))
+#else
    if (!PyString_Check (pWsgiStatus))
@@ -2499,7 +2788,8 @@
    if (!PyString_Check (pWsgiStatus))
+#endif
    {
       ReportError (__LINE__, 0, 1, NULL);
       return (0);
    }
 
    WsgiHeadersSent = 1;
@@ -2500,7 +2790,10 @@
    {
       ReportError (__LINE__, 0, 1, NULL);
       return (0);
    }
 
    WsgiHeadersSent = 1;
+#if PY_MAJOR_VERSION >= 3
+   StatusPtr = PyBytes_AsString (pWsgiStatus);
+#else
    StatusPtr = PyString_AsString (pWsgiStatus);
@@ -2506,4 +2799,5 @@
    StatusPtr = PyString_AsString (pWsgiStatus);
+#endif
    StatusCode = atoi(StatusPtr);
    if (!StatusCode || strlen(StatusPtr) < 5) return (0);
    StatusPtr += 4;
@@ -2549,7 +2843,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "WsgiOsEnvVar()\n");
+   if (dbug) fprintf (stdout, "WsgiOsEnvVar()\n");
 
    pValue = Py_BuildValue ("(ii)", 1, 0);
    retval = PyMapping_SetItemString (pEnvironDict, "wsgi.version", pValue);
@@ -2553,8 +2847,8 @@
 
    pValue = Py_BuildValue ("(ii)", 1, 0);
    retval = PyMapping_SetItemString (pEnvironDict, "wsgi.version", pValue);
-   if (Debug) fprintf (stdout, "retval: %d\n", retval);
+   if (dbug) fprintf (stdout, "retval: %d\n", retval);
    Py_DECREF(pValue);
 
    cptr = CgiVar ("REQUEST_SCHEME");
    if (!*cptr || !strcmp (cptr, "http:"))
@@ -2557,5 +2851,8 @@
    Py_DECREF(pValue);
 
    cptr = CgiVar ("REQUEST_SCHEME");
    if (!*cptr || !strcmp (cptr, "http:"))
+#if PY_MAJOR_VERSION >= 3
+      pValue = PyUnicode_FromString ("http");
+#else
       pValue = PyString_FromString ("http");
@@ -2561,2 +2858,3 @@
       pValue = PyString_FromString ("http");
+#endif
    else
@@ -2562,2 +2860,5 @@
    else
+#if PY_MAJOR_VERSION >= 3
+      pValue = PyUnicode_FromString ("https");
+#else
       pValue = PyString_FromString ("https");
@@ -2563,4 +2864,5 @@
       pValue = PyString_FromString ("https");
+#endif
    PyMapping_SetItemString (pEnvironDict, "wsgi.url_scheme", pValue);
    Py_DECREF(pValue);
 
@@ -2602,7 +2904,7 @@
 
 /*****************************************************************************/
 /*
-Jean-Fran�ois Pi�ronne's original '_wasd' module functions (massaged just a
+Jean-Francois Pieronne's original '_wasd' module functions (massaged just a
 little :-)
 */
 
@@ -2618,4 +2920,7 @@
 PyObject *args
 )
 {
+#if PY_MAJOR_VERSION >= 3
+   if (!PyArg_ParseTuple (args, "")) return (NULL);
+#else
    if (!PyArg_NoArgs(args)) return (NULL);
@@ -2621,3 +2926,4 @@
    if (!PyArg_NoArgs(args)) return (NULL);
+#endif
 
    if (IsCgiPlusScript)
@@ -2622,3 +2928,6 @@
 
    if (IsCgiPlusScript)
+#if PY_MAJOR_VERSION >= 3
+      return (PyObject *)PyLong_FromLong(1L);
+#else
       return (PyObject *)PyInt_FromLong(1L);
@@ -2624,4 +2933,5 @@
       return (PyObject *)PyInt_FromLong(1L);
+#endif
    else
    {
       Py_INCREF(Py_None);
@@ -2635,4 +2945,7 @@
 PyObject *args
 )
 {
+#if PY_MAJOR_VERSION >= 3
+   if (!PyArg_ParseTuple (args, "")) return (NULL);
+#else
    if (!PyArg_NoArgs(args)) return (NULL);
@@ -2638,4 +2951,5 @@
    if (!PyArg_NoArgs(args)) return (NULL);
+#endif
 
    if (IsCgiPlusScript)
    {
@@ -2669,4 +2983,7 @@
       res = Py_None;
    }
    else
+#if PY_MAJOR_VERSION >= 3
+      res = PyBytes_FromString (buffer);
+#else
       res = PyString_FromString(buffer);
@@ -2672,4 +2989,5 @@
       res = PyString_FromString(buffer);
+#endif
 
    return (res);
 }
@@ -2704,4 +3022,7 @@
    BodyLength = cptr - BodyPtr;
 
    if (BodyLength == 0)
+#if PY_MAJOR_VERSION >= 3
+      pBody = PyUnicode_FromString("");
+#else
       pBody = PyString_FromString("");
@@ -2707,3 +3028,4 @@
       pBody = PyString_FromString("");
+#endif
    else
    if (BodyLength == strlen (BodyPtr))
@@ -2708,3 +3030,6 @@
    else
    if (BodyLength == strlen (BodyPtr))
+#if PY_MAJOR_VERSION >= 3
+      pBody = PyUnicode_FromString (BodyPtr);
+#else
       pBody = PyString_FromString (BodyPtr);
@@ -2710,2 +3035,3 @@
       pBody = PyString_FromString (BodyPtr);
+#endif
    else
@@ -2711,2 +3037,5 @@
    else
+#if PY_MAJOR_VERSION >= 3
+      pBody = PyUnicode_FromStringAndSize (BodyPtr, BodyLength);
+#else
       pBody = PyString_FromStringAndSize (BodyPtr, BodyLength);
@@ -2712,4 +3041,5 @@
       pBody = PyString_FromStringAndSize (BodyPtr, BodyLength);
+#endif
 
    if (BodyPtr) free (BodyPtr);
 
@@ -2729,9 +3059,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "RteScriptParam()\n");
-
-   NoStreamMode = HeadCvtGet = 0;
+   if (dbug) fprintf (stdout, "RteScriptParam()\n");
 
    cptr = CgiVar ("PYRTE");
    if (!cptr) return;
@@ -2735,6 +3063,7 @@
 
    cptr = CgiVar ("PYRTE");
    if (!cptr) return;
+   NoStreamMode = HeadCvtGet = 0;
    while (*cptr)
    {
       while (*cptr && *cptr != '/') cptr++;
@@ -2755,10 +3084,10 @@
          HeadCvtGet = 1;
       else
       if (!strncasecmp (cptr, "/dbug", 5)) 
-         Debug = 1;
+         dbug = 1;
       cptr++;
    }
 }
 
 /*****************************************************************************/
 /*
@@ -2759,9 +3088,157 @@
       cptr++;
    }
 }
 
 /*****************************************************************************/
 /*
+*/
+
+void DbugCheck ()
+{
+   char  *cptr, *sptr;
+
+   /*********/
+   /* begin */
+   /*********/
+
+   if (!GlobalDebug)
+      if (cptr = TrnLnm ("PYRTE$DBUG", NULL))
+         if (!strchr (cptr, '*'))
+            if (sptr = CgiVar ("SCRIPT_NAME"))
+               if (!strstr (sptr, cptr))
+                  cptr = NULL;
+
+   if ((dbug = GlobalDebug) || (dbug = (cptr != NULL)))
+   {
+      fprintf (stdout,
+"Script-Control: X-record-mode\n\
+Content-Type: text/plain\n\
+\n\
+***** %s (%s) Python %s *****\n",
+               SoftwareId, BUILD_DATETIME, Py_GetVersion());
+fprintf (stdout, "+++++ %d %d\n",cptr,sptr);
+      fflush (stdout);
+      NoStreamMode = 1;
+   }
+
+}
+
+/****************************************************************************/
+/*
+Read the file contents specified by 'FileName' into memory, set the pointer
+at 'FileTextPtr' to the contents and the file size at 'FileSizePtr'.  Returns a
+VMS status value that should be checked.
+*/ 
+
+int ReadFileIntoMemory
+(
+char *FileName,
+char **FileTextPtr,
+int *FileSizePtr
+)
+{
+   int  status,
+        Bytes,
+        BytesRemaining,
+        BufferCount;
+   char  *cptr, *sptr,
+         *BufferPtr,
+         *LinePtr;
+   FILE  *FilePtr;
+   stat_t  StatBuffer;
+
+   /*********/
+   /* begin */
+   /*********/
+
+   if (dbug) fprintf (stdout, "ReadFileIntoMemory() |%s|\n", FileName);
+
+   if (FileTextPtr != NULL) *FileTextPtr = NULL;
+   if (FileSizePtr != NULL) *FileSizePtr = 0;
+
+   if (stat (FileName, &StatBuffer) < 0)
+   {
+      status = vaxc$errno;
+      if (dbug) fprintf (stdout, "stat() %%X%08.08X\n", status);
+      return (status);
+   }
+
+   if (StatBuffer.st_fab_rfm == FAB$C_VAR ||
+       StatBuffer.st_fab_rfm == FAB$C_VFC)
+      FilePtr = fopen (FileName, "r", "shr=put");
+   else
+      FilePtr = fopen (FileName, "r", "shr=put", "ctx=bin");
+   if (FilePtr == NULL)
+   {
+      status = vaxc$errno;
+      if (dbug) fprintf (stdout, "fopen() %%X%08.08X\n", status);
+      return (status);
+   }
+
+   Bytes = StatBuffer.st_size;
+   if (dbug) fprintf (stdout, "%d bytes\n", Bytes);
+
+   /* a little margin for error ;^) */
+   BufferPtr = calloc (1, Bytes+32);
+   if (!BufferPtr) return (vaxc$errno);
+
+   BufferCount = 0;
+
+   if (StatBuffer.st_fab_rfm == FAB$C_VAR ||
+       StatBuffer.st_fab_rfm == FAB$C_VFC)
+   {
+      BytesRemaining = Bytes;
+      LinePtr = BufferPtr;
+      while (fgets (LinePtr, BytesRemaining, FilePtr) != NULL)
+      {
+         /** if (dbug) fprintf (stdout, "|%s|\n", LinePtr); **/
+         if (!*LinePtr) break;
+         for (cptr = LinePtr; *cptr; cptr++);
+         BufferCount += cptr - LinePtr;
+         BytesRemaining -= cptr - LinePtr;
+         LinePtr = cptr;
+      }
+   }
+   else
+   {
+      status = fread (BufferPtr, Bytes, 1, FilePtr);
+      if (status == 1) BufferCount = Bytes;
+   }
+
+   fclose (FilePtr);
+
+   if (StatBuffer.st_fab_rfm == FAB$C_STMLF)
+   {
+      /* text file, newlines only (check first 512 characters and quit) */
+      for (cptr = BufferPtr; *cptr && cptr < BufferPtr+512; cptr++)
+         if (*(USHORTPTR)cptr == '\r\n')
+         {
+            sptr = cptr;
+            while (*cptr)
+            {
+               if (*(USHORTPTR)cptr == '\r\n') cptr++;
+               *sptr++ = *cptr++;
+            }
+            *sptr = '\0';
+            BufferCount = sptr - BufferPtr;
+            break;
+         }
+   }
+
+   if (dbug)
+      if (BufferCount < 50000)
+         fprintf (stdout, "%d |%s|\n", BufferCount, BufferPtr);
+      else
+         fprintf (stdout, "%d || TOO LARGE!\n", BufferCount);
+
+   if (FileTextPtr != NULL) *FileTextPtr = BufferPtr;
+   if (FileSizePtr != NULL) *FileSizePtr = BufferCount;
+
+   return (SS$_NORMAL);
+}
+
+/*****************************************************************************/
+/*
 Self-contained functionality.  Designed to be called if the script is not
 found.  If found the script needs to instantiate whatever resources it is
 proctored for and then return an HTTP 204 to the server.  If not found then
@@ -2783,7 +3260,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "ProctorDetect()\n");
+   if (dbug) fprintf (stdout, "ProctorDetect()\n");
 
    if (DetectCount++) return (0);
 
@@ -2832,9 +3309,9 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "ReportError() %d\n", SourceCodeLine);
+   if (dbug) fprintf (stdout, "ReportError() %d\n", SourceCodeLine);
 
    CgiTbLoaded = 0;
    if (Py_IsInitialized())
    {
       /* assume that if it's loaded it's also enabled */
@@ -2836,12 +3313,12 @@
 
    CgiTbLoaded = 0;
    if (Py_IsInitialized())
    {
       /* assume that if it's loaded it's also enabled */
-      pObject = PyString_FromString ("cgitb");
+      pObject = PyUnicode_FromString ("cgitb");
       if (pObject)
       {
          if (pMainDict && PyDict_Contains (pMainDict, pObject) == 1)
             CgiTbLoaded = 1;
          Py_DECREF (pObject);
       }
@@ -2842,9 +3319,21 @@
       if (pObject)
       {
          if (pMainDict && PyDict_Contains (pMainDict, pObject) == 1)
             CgiTbLoaded = 1;
          Py_DECREF (pObject);
       }
+      if (dbug) fprintf (stdout, "pObject:%u CgiTbLoaded:%d\n",
+                         pObject, CgiTbLoaded);
+      if (CgiTbLoaded)
+      {
+         if (PythonErrorPrint)
+         {
+            PyErr_Print();
+            fprintf (stdout, "<!-- PyRTE %s LINE:%d -->\n",
+                     SoftwareId, SourceCodeLine);
+            return;
+         }
+      }
    }
 
    va_count (argcnt);
@@ -2860,7 +3349,7 @@
       FaoStringDsc.dsc$w_length = strlen(FaoString);
       status = sys$faol (&FaoStringDsc, &ShortLen, &BufferDsc,
                          (unsigned long*)&FaoVector);
-      if (Debug) fprintf (stdout, "sys$fao() %%X%08.08X\n", status);
+      if (dbug) fprintf (stdout, "sys$fao() %%X%08.08X\n", status);
       if (status & 1)
          Buffer[ShortLen] = '\0';
       else
@@ -2871,7 +3360,8 @@
 
    if (AppOutputCount)
    {
-      fprintf (stdout, "\n<!-- PyRTE LINE:%d -->\n", SourceCodeLine);
+      fprintf (stdout, "\n<!-- PyRTE %s LINE:%d -->\n",
+               SoftwareId, SourceCodeLine);
       if (VmsStatus) fprintf (stdout, "<!-- %%X%08.08X -->\n", VmsStatus);
       if (!CgiTbLoaded) fputs ("<pre>\n----------\n", stdout);
       PyErr_Print();
@@ -2881,14 +3371,4 @@
 
    fputs ("Status: 502\nContent-Type: text/html\n\n", stdout);
 
-   if (CgiTbLoaded)
-   {
-      fputs ("<html>\n", stdout);
-      fprintf (stdout, "<!-- PyRTE LINE:%d -->\n", SourceCodeLine);
-      if (VmsStatus) fprintf (stdout, "<!-- %%X%08.08X -->\n", VmsStatus);
-      PyErr_Print();
-      fputs ("</html>\n", stdout);
-      return;
-   }
-
    fprintf (stdout,
@@ -2894,15 +3374,16 @@
    fprintf (stdout,
-"<HTML>\n\
-<HEAD>\n\
-<META NAME=\"generator\" CONTENT=\"%s\">\n\
-<META NAME=\"line\" CONTENT=\"%d\">\n\
-<TITLE>ERROR 502 Bad Gateway</TITLE>\n\
-</HEAD>\n\
-<BODY>\n\
-<FONT SIZE=\"+1\"><B>ERROR 502</B> &nbsp;-&nbsp; \
-External agent did not respond (or not acceptably)</FONT>\n",
-           SOFTWAREID,
+"<!DOCTYPE html>\n\
+<html>\n\
+<head>\n\
+<meta name=\"generator\" content=\"%s\">\n\
+<meta name=\"line\" content=\"%d\">\n\
+<title>ERROR 502 Bad Gateway</title>\n\
+</head>\n\
+<body>\n\
+<font size=\"+1\"><b>ERROR 502</b> &nbsp;-&nbsp; \
+External agent did not respond (or not acceptably)</font>\n",
+           SoftwareId,
            SourceCodeLine);
 
    if (VmsStatus) fprintf (stdout, "<!-- %%X%08.08X -->\n", VmsStatus);
 
@@ -2905,8 +3386,8 @@
            SourceCodeLine);
 
    if (VmsStatus) fprintf (stdout, "<!-- %%X%08.08X -->\n", VmsStatus);
 
-   if (Buffer[0]) fprintf (stdout, "<P>%s", Buffer);
+   if (Buffer[0]) fprintf (stdout, "<p>%s", Buffer);
 
    if (PythonErrorPrint)
    {
@@ -2910,5 +3391,5 @@
 
    if (PythonErrorPrint)
    {
-      fprintf (stdout, "<P><PRE>");
+      fprintf (stdout, "<p><pre>");
       PyErr_Print();
@@ -2914,7 +3395,7 @@
       PyErr_Print();
-      fprintf (stdout, "</PRE>\n");
+      fprintf (stdout, "</pre>\n");
    }
 
    cptr = CgiVar ("SERVER_SIGNATURE");
 
    fprintf (stdout,
@@ -2916,7 +3397,7 @@
    }
 
    cptr = CgiVar ("SERVER_SIGNATURE");
 
    fprintf (stdout,
-"<P><HR WIDTH=85%% ALIGN=left SIZE=2 NOSHADE>\n\
+"<p><hr width=85%% align=\"left\" size=\"2\" noshade>\n\
 %s%s\
@@ -2922,6 +3403,6 @@
 %s%s\
-</BODY>\n\
-</HTML>\n",
+</body>\n\
+</html>\n",
             cptr ? cptr : "", cptr ? "\n" : "");
 }
 
@@ -2954,7 +3435,6 @@
    static char  *EmptyScriptNamePtr = NULL,
                 *NextVarNamePtr;
    static char  StructBuffer [CGIVAR_STRUCT_SIZE];
-   static FILE  *CgiPlusIn;
    
    int  status;
    int  Length;
@@ -2964,7 +3444,7 @@
    /* begin */
    /*********/
 
-   if (Debug && VarName && VarName[0] && VarName[0] != '*')
+   if (dbug && VarName && VarName[0] && VarName[0] != '*')
       fprintf (stdout, "CgiVar() |%s|\n", !VarName ? "NULL" : VarName);
 
    if (!VarName || !VarName[0])
@@ -3053,10 +3533,10 @@
    }
 
    /* the CGIPLUSIN stream can be left open */
-   if (!CgiPlusIn)
-      if (!(CgiPlusIn = fopen (TrnLnm("CGIPLUSIN", NULL), "r")))
+   if (!CgiPlusInFp)
+      if (!(CgiPlusInFp = fopen (TrnLnm("CGIPLUSIN", NULL), "r")))
          exit (vaxc$errno);
 
    /* get the starting record (the essentially discardable one) */
    for (;;)
    {
@@ -3058,9 +3538,9 @@
          exit (vaxc$errno);
 
    /* get the starting record (the essentially discardable one) */
    for (;;)
    {
-      cptr = fgets (StructBuffer, sizeof(StructBuffer), CgiPlusIn);
+      cptr = fgets (StructBuffer, sizeof(StructBuffer), CgiPlusInFp);
       if (!cptr) exit (vaxc$errno);
       /* if the starting sentinal is detected then break */
       if (*(unsigned short*)cptr == '!\0' ||
@@ -3082,7 +3562,7 @@
       if (StructLength <= 0 || StructLength > sizeof(StructBuffer))
          exit (SS$_BUGCHECK);
 
-      if (!fread (StructBuffer, 1, StructLength, CgiPlusIn))
+      if (!fread (StructBuffer, 1, StructLength, CgiPlusInFp))
          exit (vaxc$errno);
    }
    else
@@ -3093,7 +3573,7 @@
 
       /* reconstructs the original 'struct'ure from the records */
       sptr = (bptr = StructBuffer) + sizeof(StructBuffer);
-      while (fgets (bptr+SOUS, sptr-(bptr+SOUS), CgiPlusIn))
+      while (fgets (bptr+SOUS, sptr-(bptr+SOUS), CgiPlusInFp))
       {
          /* first empty record (line) terminates variables */
          if (bptr[SOUS] == '\n') break;
@@ -3211,7 +3691,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "CgiVarDclSymbol()\n");
+   if (dbug) fprintf (stdout, "CgiVarDclSymbol()\n");
 
    if (VarName[0] == '*')
       cptr = SymbolNames[SymbolIndex++];
@@ -3269,7 +3749,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "EmptyScriptName() %s %s\n", VarName, VarValue);
+   if (dbug) fprintf (stdout, "EmptyScriptName() %s %s\n", VarName, VarValue);
 
    while (*cptr && *sptr && *sptr != '=')
    { 
@@ -3324,7 +3804,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "MetricsReport()\n");
+   if (dbug) fprintf (stdout, "MetricsReport()\n");
 
    if (!CodeMetricEnabled) return (0);
 
@@ -3336,4 +3816,7 @@
 
    pValue = PyObject_CallFunction (pFunc, NULL);
    if (!pValue) return (0);
+#if PY_MAJOR_VERSION >= 3
+   strcpy (pyver, PyBytes_AsString (pValue));
+#else
    strcpy (pyver, PyString_AsString (pValue));
@@ -3339,4 +3822,5 @@
    strcpy (pyver, PyString_AsString (pValue));
+#endif
 
    Py_DECREF(pPlatMod);
    Py_DECREF(pFunc);
@@ -3346,12 +3830,19 @@
 "Status: 200\n\
 Content-Type: text/html\n\
 \n\
-<HTML>\n\
-<HEAD>\n\
-<TITLE>Metrics Report - %s (%s)</TITLE>\n\
-</HEAD>\n\
-<STYLE TYPE=\"text/css\">\n\
+<!DOCTYPE html>\n\
+<html>\n\
+<head>\n\
+<title>Metrics Report - %s (%s)</title>\n\
+</head>\n\
+<style type=\"text/css\">\n\
+body {\n\
+  font-family:arial,helvetica,sans-serif;\n\
+  font-size:11pt;\n\
+  background-color:#ffffff; color:#000000;\n\
+  margin:1.5em; padding:0;\n\
+}\n\
 th { margin:0; padding:0 0 2px 1em; white-space:nowrap; \
 text-decoration:underline; }\n\
 td { margin:0; padding:0 0 2px 1em; white-space:nowrap; }\n\
 pre { font-size:80%%; line-height:90%%; }\n\
@@ -3354,18 +3845,19 @@
 th { margin:0; padding:0 0 2px 1em; white-space:nowrap; \
 text-decoration:underline; }\n\
 td { margin:0; padding:0 0 2px 1em; white-space:nowrap; }\n\
 pre { font-size:80%%; line-height:90%%; }\n\
-</STYLE>\n\
-<BODY>\n\
-<FONT SIZE=\"+1\"><B>Metrics Report &nbsp;-&nbsp; %s \
-&nbsp;-&nbsp; Python %s</B></FONT>\n\
-<P>PID&nbsp; <TT>%08.08X</TT> &nbsp;Usage Count: %u\n\
-<P>%d Item(s)\n",
-           SOFTWAREID, BUILD_DATETIME,
-           SOFTWAREID, pyver,
+</style>\n\
+<body>\n\
+<span style=\"font-size:120%%;font-weight:bold;\">\
+Metrics Report &nbsp;-&nbsp; %s &nbsp;-&nbsp; Python %s\
+</span>\n\
+<p>PID&nbsp; <tt>%08.08X</tt> &nbsp;Usage Count: %u\n\
+<p>%d Item(s)\n",
+           SoftwareId, BUILD_DATETIME,
+           SoftwareId, pyver,
            ProcessPid, UsageCount,
            CodeCacheCount);
 
    if (CodeCacheCount)
    {
       fputs (
@@ -3366,26 +3858,26 @@
            ProcessPid, UsageCount,
            CodeCacheCount);
 
    if (CodeCacheCount)
    {
       fputs (
-"<P><TABLE BORDER=\"0\">\n\
-<TR>\
-<TH></TH>\n\
-<TH ALIGN=\"right\">Usage</TH>\
-<TH ALIGN=\"right\">Size</TH>\
-<TH ALIGN=\"right\">Number</TH>\
-<TH ALIGN=\"left\">Last Used</TH>\
-<TH ALIGN=\"right\">Duration</TH>\
-<TH ALIGN=\"right\">CPU</TH>\
-<TH ALIGN=\"right\">BIO</TH>\
-<TH ALIGN=\"right\">DIO</TH>\
-<TH ALIGN=\"right\">FLT</TH>\
-<TH ALIGN=\"right\">PGS</TH>\
-<TH ALIGN=\"left\">Modified</TH>\
-<TH ALIGN=\"left\">Script File</TH>\
-<TH ALIGN=\"left\">Byte-Code File</TH>\
-</TR>\n",
+"<p><table border=\"0\">\n\
+<tr>\
+<th></th>\n\
+<th align=\"right\">Usage</th>\
+<th align=\"right\">Size</th>\
+<th align=\"right\">Number</th>\
+<th align=\"left\">Last Used</th>\
+<th align=\"right\">Duration</th>\
+<th align=\"right\">CPU</th>\
+<th align=\"right\">BIO</th>\
+<th align=\"right\">DIO</th>\
+<th align=\"right\">FLT</th>\
+<th align=\"right\">PGS</th>\
+<th align=\"left\">Modified</th>\
+<th align=\"left\">Script File</th>\
+<th align=\"left\">Byte-Code File</th>\
+</tr>\n",
       stdout);
 
       /* lib$cvts..() is not available before VMS V8.2 so work around */
@@ -3398,14 +3890,14 @@
       if (!(status & 1)) exit (status);
 
       fprintf (stdout,
-"<TR><TD COLSPAN=\"4\"></TD>\
-<TD ALIGN=\"right\"><I>RTE cummulative</I></TD>\
-<TD ALIGN=\"right\">%.4f</TD>\
-<TD ALIGN=\"right\">%.4f</TD>\
-<TD ALIGN=\"right\">%u</TD>\
-<TD ALIGN=\"right\">%u</TD>\
-<TD ALIGN=\"right\">%u</TD>\
-<TD ALIGN=\"right\">%u</TD></TR>\n",
+"<tr><td colspan=\"4\"></td>\
+<td align=\"right\"><i>RTE cummulative</i></td>\
+<td align=\"right\">%.4f</td>\
+<td align=\"right\">%.4f</td>\
+<td align=\"right\">%u</td>\
+<td align=\"right\">%u</td>\
+<td align=\"right\">%u</td>\
+<td align=\"right\">%u</td></tr>\n",
                tfloat,
                (float)(RteJpiCpuTim)/100.0,
                RteJpiBufIO,
@@ -3442,21 +3934,21 @@
          bcsize = -1;
 
       fprintf (stdout,
-"<TR><TD ALIGN=\"right\">%d.</TD>\
-<TD ALIGN=\"right\">%d</TD>\
-<TD ALIGN=\"right\">%d</TD>\
-<TD ALIGN=\"right\"></TD>\
-<TD ALIGN=\"right\"><I>cummulative</I></TD>\
-<TD ALIGN=\"right\">%.4f</TD>\
-<TD ALIGN=\"right\">%.4f</TD>\
-<TD ALIGN=\"right\">%u</TD>\
-<TD ALIGN=\"right\">%u</TD>\
-<TD ALIGN=\"right\">%u</TD>\
-<TD ALIGN=\"right\">%u</TD>\
-<TD>%s</TD>\
-<TD><TT>%s</TT></TD>\
-<TD><TT>%s</TT></TD>\
-</TR>\n",
+"<tr><td align=\"right\">%d.</td>\
+<td align=\"right\">%d</td>\
+<td align=\"right\">%d</td>\
+<td align=\"right\"></td>\
+<td align=\"right\"><i>cummulative</i></td>\
+<td align=\"right\">%.4f</td>\
+<td align=\"right\">%.4f</td>\
+<td align=\"right\">%u</td>\
+<td align=\"right\">%u</td>\
+<td align=\"right\">%u</td>\
+<td align=\"right\">%u</td>\
+<td>%s</td>\
+<td><tt>%s</tt></td>\
+<td><tt>%s</tt></td>\
+</tr>\n",
                idx + 1,
                ccptr->CodeUsageCount, 
                bcsize, 
@@ -3488,16 +3980,16 @@
          tsecs = decc$fix_time(&cmptr->StartBinTime[midx]);
 
          fprintf (stdout,
-"<TR><TD COLSPAN=\"3\"></TD>\
-<TD ALIGN=\"right\">%u</TD>\
-<TD>%s</TD>\
-<TD ALIGN=\"right\">%.4f</TD>\
-<TD ALIGN=\"right\">%.4f</TD>\
-<TD ALIGN=\"right\">%u</TD>\
-<TD ALIGN=\"right\">%u</TD>\
-<TD ALIGN=\"right\">%u</TD>\
-<TD ALIGN=\"right\">%u</TD>\
-<TD COLSPAN=\"3\"><TT>%s</TT>%s</TD></TR>\n",
+"<tr><td colspan=\"3\"></td>\
+<td align=\"right\">%u</td>\
+<td>%s</td>\
+<td align=\"right\">%.4f</td>\
+<td align=\"right\">%.4f</td>\
+<td align=\"right\">%u</td>\
+<td align=\"right\">%u</td>\
+<td align=\"right\">%u</td>\
+<td align=\"right\">%u</td>\
+<td colspan=\"3\"><tt>%s</tt>%s</td></tr>\n",
                   cmptr->UsageNumber[midx],
                   my_ctime_r(&tsecs,lubuf), 
                   tfloat,
@@ -3520,5 +4012,5 @@
 /***
       if (pValue)
       {
-         fputs("<TR><TD COLSPAN=\"3\"></TD><TD COLSPAN=\"5\"><TT>", stdout);
+         fputs("<tr><td colspan=\"3\"></td><td colspan=\"5\"><tt>", stdout);
          PyObject_Print ((PyObject*)CodeCache[idx].pByteCode, stdout, 0);
@@ -3524,5 +4016,5 @@
          PyObject_Print ((PyObject*)CodeCache[idx].pByteCode, stdout, 0);
-         fputs("</TT></TD></TR>\n", stdout);
-
-         fputs("<TR><TD COLSPAN=\"3\"></TD><TD COLSPAN=\"5\"><TT>", stdout);
+         fputs("</tt></td></tr>\n", stdout);
+
+         fputs("<tr><td colspan=\"3\"></td><td colspan=\"5\"><tt>", stdout);
          PyObject_Print (pValue, stdout, 0);
@@ -3528,5 +4020,5 @@
          PyObject_Print (pValue, stdout, 0);
-         fputs("</TT></TD></TR>\n", stdout);
+         fputs("</tt></td></tr>\n", stdout);
 
          Py_DECREF(pValue);
       }
@@ -3536,9 +4028,9 @@
 ***/
    }
 
-   fputs ("</TABLE>\n<PRE>", stdout);
+   fputs ("</table>\n<pre>", stdout);
 
 /***
    LibVmReport (NULL);
 ***/
 
@@ -3540,12 +4032,12 @@
 
 /***
    LibVmReport (NULL);
 ***/
 
-   fputs ("</PRE>\n\
-<P><HR WIDTH=85%% ALIGN=left SIZE=2 NOSHADE>\n\
-</BODY>\n\
-</HTML>\n", stdout);
+   fputs ("</pre>\n\
+<p><hr width=\"85%%\" align=\"left\" size=\"2\" noshade>\n\
+</body>\n\
+</html>\n", stdout);
 
    fflush (stdout);
    fputs (CgiPlusEofPtr, stdout);
@@ -3569,7 +4061,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "AddMetrics()\n");
+   if (dbug) fprintf (stdout, "AddMetrics()\n");
 
    if (!CodeMetricEnabled) return;
    if (ccptr->CodeMetricPtr) return;
@@ -3622,7 +4114,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "CollectMetrics()\n");
+   if (dbug) fprintf (stdout, "CollectMetrics()\n");
 
    if (!CodeMetricEnabled) return;
    /* possible if metric reporting is enabled on an existing RTE */
@@ -3720,7 +4212,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "LibVmReport()\n");
+   if (dbug) fprintf (stdout, "LibVmReport()\n");
 
    if (StrDscPtr)
    {
@@ -3840,7 +4332,7 @@
    /* begin */
    /*********/
 
-   if (Debug) fprintf (stdout, "TrnLnm() |%s|\n", LogName);
+   if (dbug) fprintf (stdout, "TrnLnm() |%s|\n", LogName);
 
    LogNameDsc.dsc$a_pointer = LogName;
    LogNameDsc.dsc$w_length = strlen(LogName);
@@ -3850,6 +4342,6 @@
       cptr = LnmItems[0].buf_addr = StaticLogValue;
 
    status = sys$trnlnm (0, &LnmFileDevDsc, &LogNameDsc, 0, &LnmItems);
-   if (Debug) fprintf (stdout, "sys$trnlnm() %%X%08.08X\n", status);
+   if (dbug) fprintf (stdout, "sys$trnlnm() %%X%08.08X\n", status);
    if (!(status & 1))
    {
@@ -3854,7 +4346,7 @@
    if (!(status & 1))
    {
-      if (Debug) fprintf (stdout, "|(null)|\n");
+      if (dbug) fprintf (stdout, "|(null)|\n");
       return (NULL);
    }
 
    cptr[ShortLength] = '\0';
@@ -3857,8 +4349,8 @@
       return (NULL);
    }
 
    cptr[ShortLength] = '\0';
-   if (Debug) fprintf (stdout, "|%s|\n", cptr);
+   if (dbug) fprintf (stdout, "|%s|\n", cptr);
    return (cptr);
 }