diff --git a/core/TESTS/tests.py b/core/TESTS/tests.py
index b8b915d..ec7de15 100644
--- a/core/TESTS/tests.py
+++ b/core/TESTS/tests.py
@@ -314,7 +314,19 @@ class PageTests(TestCase):
             self.assertEqual(response.status_code, 302)  
         if response.status_code != 302:
             self.assertEqual(response.status_code, 200)  
-            self.assertEqual(len(response.content), 39482 ) 
+            self.assertEqual(len(response.content), 39482 ) # need to check it is not just an error page
+ 
+    def test_page_site_media_css(self):
+        # Flat file tests.
+        response = self.client.get('/site_media/css/main3.css')
+        if response.status_code != 200:
+            self.assertEqual(response.status_code, 302)  
+        if response.status_code != 302:
+            self.assertEqual(response.status_code, 200)  
+            content = response.content.decode() # need to check it is not just an error page
+            ph = r'This text is used by the test system to determine that main3.css loaded correctly'
+            phmatch    = re.search(ph, content)
+            self.assertIsNotNone(phmatch, "Failed to find expected text: '" + ph +"'")
 
     def test_page_photos_ok(self):
         # Flat file tests.
@@ -323,7 +335,7 @@ class PageTests(TestCase):
             self.assertEqual(response.status_code, 302)  
         if response.status_code != 302:
             self.assertEqual(response.status_code, 200)  
-            self.assertEqual(len(response.content), 67487 ) 
+            self.assertEqual(len(response.content), 67487 ) # need to check it is not just an error page
 
     def test_page_photos_not_ok(self):
         # Flat file tests.
diff --git a/core/views/statistics.py b/core/views/statistics.py
index 3102d51..9d5cd16 100644
--- a/core/views/statistics.py
+++ b/core/views/statistics.py
@@ -24,6 +24,7 @@ def pathsreport(request):
         pathsdict = {
 #       "BOGUS" : str( settings.BOGUS),
         "JSLIB_URL" : str( settings.JSLIB_URL),
+        "JSLIB_ROOT" : str( settings.JSLIB_ROOT),
 #       "CSSLIB_URL" : str( settings.CSSLIB_URL),
         "CAVEDESCRIPTIONS" : str( settings.CAVEDESCRIPTIONS),
         "DIR_ROOT" : str( settings.DIR_ROOT),
@@ -60,6 +61,7 @@ def pathsreport(request):
         pathstype = {
 #       "BOGUS" : type(settings.BOGUS),
         "JSLIB_URL" : type(settings.JSLIB_URL),
+        "JSLIB_ROOT" : str( settings.JSLIB_ROOT),
 #       "CSSLIB_URL" : type(settings.CSSLIB_URL),
         "CAVEDESCRIPTIONS" : type(settings.CAVEDESCRIPTIONS),
         "DIR_ROOT" : type(settings.DIR_ROOT),
diff --git a/media/css/main3.css b/media/css/main3.css
index 1a201eb..f139a3e 100644
--- a/media/css/main3.css
+++ b/media/css/main3.css
@@ -2,7 +2,7 @@ html, body {
 	height: 100%;
 }
 
-
+/* This text is used by the test system to determine that main3.css loaded correctly */
 .caption			{ font-size: 8pt; margin-bottom: 0pt; }
 .centre				{ text-align: center; }
 .plus2pt			{ font-size: 160%; }
diff --git a/pre-push.sh b/pre-push.sh
index 7ae6878..92cf6d2 100644
--- a/pre-push.sh
+++ b/pre-push.sh
@@ -13,18 +13,16 @@ python manage.py inspectdb > troggle-inspectdb.py
 #egrep -in "unable|error" troggle-inspectdb.py
 echo remove passwords.
 cp localsettings.py localsettingsWSL.py
-grep EXPOUSERPASS localsettings*.py
-sed -i '/EXPOUSERPASS/ s/^.*$/EXPOUSERPASS = "nnn:gggggg"/' localsettings*.py
-sed -i '/EXPOUSERPASS/ s/^.*$/EXPOUSERPASS = "nnn:gggggg"/' diffsettings.txt
-echo "    " reset: EXPOUSERPASS = \"nnn:gggggg\"
-grep EMAIL_HOST_PASSWORD localsettings*.py
-sed -i '/EMAIL_HOST_PASSWORD/ s/^.*$/EMAIL_HOST_PASSWORD = "insert-real-email-password-here"/' localsettings*.py
-sed -i '/EMAIL_HOST_PASSWORD/ s/^.*$/EMAIL_HOST_PASSWORD = "insert-real-email-password-here"/' diffsettings.txt
-echo "    " reset: EMAIL_HOST_PASSWORD = \"insert-real-email-password-here\"
-grep SECRET_KEY *settings.*
-sed -i '/SECRET_KEY/ s/^.*$/SECRET_KEY = "not-the-real-secret-key-a#vaeozn0---^fj!355qki*vj2"/' settings.py
-sed -i '/SECRET_KEY/ s/^.*$/SECRET_KEY = "not-the-real-secret-key-a#vaeozn0---^fj!355qki*vj2"/' diffsettings.txt
-echo "    " reset: SECRET_KEY = \"not-the-real-secret-key-a#vaeozn0---^fj!355qki*vj2\"
+sed -i '/EXPOUSERPASS/ s/^.*$/EXPOUSERPASS = "nnn:gggggg - real-expo-password--is-imported-from-credentials.py"/' diffsettings.txt
+echo "    reset: EXPOUSERPASS = \"nnn:gggggg\"  - real-expo-password--is-imported-from-credentials.py"
+
+sed -i '/EMAIL_HOST_PASSWORD/ s/^.*$/EMAIL_HOST_PASSWORD = "real-email-password--is-imported-from-credentials.py"/' diffsettings.txt
+echo "    reset: EMAIL_HOST_PASSWORD = \"real-email-password-is-imported-from-credentials.py\""
+
+sed -i '/SECRET_KEY/ s/^.*$/SECRET_KEY = "real-SECRET_KEY-is-imported-from-credentials.py"/' diffsettings.txt
+echo "    reset: SECRET_KEY = \"real-SECRET_KEY-is-imported-from-credentials.py\""
+
+
 #
 # Do these before final testing, *not* just before pushing:
 # in ./pre-run.sh
diff --git a/urls.py b/urls.py
index f03928d..8aa68ba 100644
--- a/urls.py
+++ b/urls.py
@@ -34,7 +34,7 @@ The API urls return TSV or JSON and are new in July 2020.
 
 if settings.EXPOFILESREMOTE:
     expofilesurls = [
-        url(r'^(?P<path>.*)$',    expofiles_redirect, name="expofiles_redirect"), # to expo.survex.com/expofiles
+        url(r'^(?P<path>.*)$',    expofiles_redirect, name="expofiles_redirect"), # to http://expo.survex.com/expofiles
     ]
 else:
     expofilesurls = [
@@ -111,36 +111,41 @@ trogglepatterns = [
 
 #   url(r'^map/', .........), # Intercepted by Apache. Yields OpenStreetMap. Redirects to expoweb/map
 
+    url(r'^prospecting_guide/$', caves.prospecting),    
+    url(r'^prospecting/(?P<name>[^.]+).png$', prospecting_image, name="prospecting_image"),
+
+    # The survexfile pages
     url(r'^survexfile/(?P<survex_file>.*?)\.svx$', survex.svx,        name="svx"),
     url(r'^survexfile/(?P<survex_file>.*?)\.3d$',  survex.threed,     name="threed"),
     url(r'^survexfile/(?P<survex_file>.*?)\.log$', survex.svxraw),
     url(r'^survexfile/(?P<survex_file>.*?)\.err$', survex.err),
 
-    url(r'^survexfile/caves/$',                       survex.survexcaveslist,  name="survexcaveslist"),
-    url(r'^survexfile/(?P<survex_cave>.*)$',          survex.survexcavesingle, name="survexcavessingle"),
+    url(r'^survexfile/caves/$',                       survex.survexcaveslist,     name="survexcaveslist"),
+    url(r'^survexfile/(?P<survex_cave>.*)$',          survex.survexcavesingle,    name="survexcavessingle"),
 
     url(r'^survey_scans/$',                           surveys.surveyscansfolders, name="surveyscansfolders"), 
     url(r'^survey_scans/(?P<path>[^/]+)/$',           surveys.surveyscansfolder,  name="surveyscansfolder"),
     url(r'^survey_scans/(?P<path>[^/]+)/(?P<file>[^/]+)$', 
                                                       surveys.surveyscansingle,   name="surveyscansingle"), 
 
+    # The tunnel drawings files pages
     url(r'^tunneldata/$',                             surveys.tunneldata,         name="tunneldata"), 
     url(r'^tunneldataraw/(?P<path>.+?\.xml)$',        surveys.tunnelfilesingle,   name="tunnelfile"), 
-#   url(r'^tunneldatainfo/(?P<path>.+?\.xml)$',       surveys.tunnelfileinfo,     name="tunnelfileinfo"), 
+#   url(r'^tunneldatainfo/(?P<path>.+?\.xml)$',       surveys.tunnelfileinfo,     name="tunnelfileinfo"), # parses tunnel for info
     url(r'^tunneldataraw/(?P<path>.+?\.xml)/upload$', surveys.tunnelfileupload,   name="tunnelfileupload"), 
-
-    url(r'^prospecting_guide/$', caves.prospecting),    
-    url(r'^prospecting/(?P<name>[^.]+).png$', prospecting_image, name="prospecting_image"),
     
-  
+    # This next set are all intercepted by Apache, if it is running.
     url(r'^photos/(?P<subpath>.*)$',      mediapage, {'doc_root': settings.PHOTOS_ROOT}, name="mediapage"), # photo galleries 
     url(r'^site_media/(?P<subpath>.*)$',  mediapage, {'doc_root': settings.MEDIA_ROOT},  name="mediapage"), # MEDIA_ROOT: CSS and JS 
     url(r'^static/(?P<subpath>.*)$',      mediapage, {'doc_root': settings.MEDIA_ROOT},  name="mediapage"), # STATIC is in MEDIA now!
+    url(r'^javascript/(?P<subpath>.*)$',  mediapage, {'doc_root': settings.JSLIB_ROOT},  name="mediapage"), # JSLIB_URL 
 
+    # This next is for shorthand references such as /1623/264
     url(r'^(?P<karea>\d\d\d\d)(?P<subpath>.*)$',     cavepage,     name="cavepage"), # Cave description
 
+    # Final catchall which also serves expoweb handbook pages and images
     url(r'^(.*)_edit$',         editexpopage, name="editexpopage"),
-    url(r'^(.*)$',              expopage,     name="expopage"), # CATCHALL assumed relative to EXPOWEB
+    url(r'^(.*)$',              expopage,     name="expopage"),     # CATCHALL assumed relative to EXPOWEB
 ]
 
 # do not allow DIR_ROOT prefix to all urls
@@ -151,11 +156,11 @@ urlpatterns = [
 
 # When apache is running these prempt Django so Django never sees them.
 
-# NEW apache configurations suggested as of 20 March 2021: 
+# NEW apache configurations suggested as of 2 April 2021: 
 # Alias /site-media/ /home/expo/troggle/media/
 # Alias /robots.txt  /home/expo/troggle/media/robots.txt
 # Alias /favicon.ico /home/expo/troggle/media/favicon.ico  # comes from /expoweb/* when running runserver
-# Alias /javascript  /home/expo/troggle/media/javascript   # empty
+# Alias /javascript  /home/expo/troggle/media/jslib        # empty
 
 # Copy of old standard apache configurations:
 # Alias /expofiles   /home/expo/expofiles