diff --git a/books/bookvol5.pamphlet b/books/bookvol5.pamphlet
index 57b68fa..3600120 100644
--- a/books/bookvol5.pamphlet
+++ b/books/bookvol5.pamphlet
@@ -5625,7 +5625,6 @@ information is initialized.
 \calls{restart0}{operationopen}
 \calls{restart0}{categoryopen}
 \calls{restart0}{browseopen}
-\calls{restart0}{getEnv}
 \begin{chunk}{defun restart0}
 (defun restart0 ()
   (interpopen)      ;; open up the interpreter database
@@ -6188,6 +6187,15 @@ will end up as a recursive call to ourselves.
 
 \end{chunk}
 
+\defun{substring}{substring}
+\begin{chunk}{defun substring 0}
+(defun substring (cvec start length)
+  (if length 
+   (subseq (string cvec) start (+ start length))
+   (subseq (string cvec) start)))
+
+\end{chunk}
+
 \defun{intProcessSynonyms}{Handle Synonyms}
 \calls{intProcessSynonyms}{processSynonyms}
 \uses{intProcessSynonyms}{line}
@@ -43143,7 +43151,7 @@ This is indexed by (domain . category)
 
 \defun{initial-getdatabase}{Preload algebra into saved system}
 \calls{initial-getdatabase}{getdatabase}
-\calls{initial-getdatabase}{getEnv}
+\calls{initial-getdatabase}{getenviron}
 \begin{chunk}{defun initial-getdatabase}
 (defun initial-getdatabase ()
  "fetch data we want in the saved system"
@@ -43222,7 +43230,7 @@ This is indexed by (domain . category)
   |Integer| |List| |OutputForm|))
  (dolist (con constr)
   (let ((c (concatenate 'string
-             (|getEnv| "AXIOM") "/algebra/"
+             (getenviron "AXIOM") "/algebra/"
              (string (getdatabase con 'abbreviation)) ".o")))
     (format t "   preloading ~a.." c)
     (if (probe-file c)
@@ -43932,7 +43940,7 @@ the source file without any path information. We  hash the
 constructor abbreviation to pamphlet file name.
 
 \calls{make-databases}{localdatabase}
-\calls{make-databases}{getEnv}
+\calls{make-databases}{getenviron}
 \calls{make-databases}{browserAutoloadOnceTrigger}
 \calls{make-databases}{mkTopicHashTable}
 \calls{make-databases}{buildLibdb}
@@ -44035,12 +44043,12 @@ constructor abbreviation to pamphlet file name.
     (list (list '|dir| (namestring (truename (format nil "./~a" dir)))))
     'make-database))
 ;browse.daase
-  (load (concatenate 'string (|getEnv| "AXIOM") "/autoload/topics"))  ;; hack
+  (load (concatenate 'string (getenviron "AXIOM") "/autoload/topics"))  ;; hack
   (|browserAutoloadOnceTrigger|)
   (|mkTopicHashTable|)
   (setq |$constructorList| nil) ;; affects buildLibdb
   (setq *sourcefiles* (build-name-to-pamphlet-hash 
-    (concatenate 'string (|getEnv| "AXIOM") "/../../books/*.pamphlet")))
+    (concatenate 'string (getenviron "AXIOM") "/../../books/*.pamphlet")))
   (|buildLibdb|)
   (|dbSplitLibdb|)
 ; (|dbAugmentConstructorDataTable|)
@@ -44133,13 +44141,13 @@ constructor abbreviation to pamphlet file name.
 \end{chunk}
 
 \defun{DaaseName}{Construct the proper database full pathname}
-\calls{DaaseName}{getEnv}
+\calls{DaaseName}{getenviron}
 \usesdollar{DaaseName}{spadroot}
 \begin{chunk}{defun DaaseName}
 (defun DaaseName (name erase?)
  (let (daase filename)
   (declare (special $spadroot))
-  (if (setq daase (|getEnv| "DAASE"))
+  (if (setq daase (getenviron "DAASE"))
    (progn
     (setq filename  (concatenate 'string daase "/algebra/" name))
     (format t "   Using local database ~a.." filename))
@@ -50013,7 +50021,7 @@ Hash primitive hyperdoc macros into {\bf htMacroTable}.
 \calls{buildHtMacroTable}{getHtMacroItem}
 \calls{buildHtMacroTable}{sayBrightly}
 \calls{buildHtMacroTable}{concat}
-\calls{buildHtMacroTable}{getEnv}
+\calls{buildHtMacroTable}{getenviron}
 \calls{buildHtMacroTable}{hput}
 \usesdollar{buildHtMacroTable}{htMacroTable}
 \usesdollar{buildHtMacroTable}{primitiveHtCommands}
@@ -50021,7 +50029,7 @@ Hash primitive hyperdoc macros into {\bf htMacroTable}.
 (defun |buildHtMacroTable| ()
  (let (fn instream)
   (declare (special |$htMacroTable| |$primitiveHtCommands|))
-  (setq fn (concat (|getEnv| "AXIOM") "/doc/util.ht"))
+  (setq fn (concat (getenviron "AXIOM") "/doc/util.ht"))
   (cond 
    ((probe-file fn)
     (with-open-file (instream fn)
@@ -50030,7 +50038,7 @@ Hash primitive hyperdoc macros into {\bf htMacroTable}.
        until (eq line :eof)
        do
         (when 
-         (mulitple-value-bind (command numOfArgs) (|getHtMacroItem| line)
+         (multiple-value-bind (command numOfArgs) (|getHtMacroItem| line)
           (hput |$htMacroTable| command numOfArgs))))
      (dolist (pair |$primitiveHtCommands|)
       (hput |$htMacroTable| (car pair) (cdr pair)))))
@@ -50068,7 +50076,7 @@ starting after the first closing brace.
     (setq command (substring line 12 (- k 12)))
     (setq m (length line))
     (setq i (position #\[ line :start k))
-    (if (and i (< i m) (< i wall))
+    (if (and i (< i m) wall (< i wall))
      (progn                 ; brackets. parse number of args
       (setq j (position #\] line :start (+ i 1)))
       (setq digitString (substring line (+ i 1) (- (- j i) 1)))
@@ -50085,6 +50093,18 @@ We populate the htMacroTable at load time.
 
 \end{chunk}
 
+\defun{stringPrefix?}{Is the first string a prefix of the second?}
+\begin{chunk}{defun stringPrefix? 0}
+(defun |stringPrefix?| (pref str)
+ (let (lp)
+  (cond
+   ((null (and (stringp pref) (stringp str))) nil)
+   ((eql (setq lp (length pref)) 0) t)
+   ((> lp (length str)) nil)
+   (t (every #'char= pref str)))))
+
+\end{chunk}
+
 \section{Functions creating pages}
 Most of the functions create a new page with a call to the function
 {\tt htMakePage}. This function takes an association list which has
@@ -56070,7 +56090,7 @@ Given \verb|("one" "two" "three")| generate \verb|"(one,two,three)"|
                 (setq results (|applyGrep| grepForm '|gloss|))
                 (setq defstream
                          (make-instream
-                             (STRCONC (|getEnv| "AXIOM")
+                             (STRCONC (getenviron "AXIOM")
                               "/algebra/glossdef.text")))
                 (setq lines
                          (|gatherGlossLines| results defstream))
@@ -56537,13 +56557,12 @@ Given \verb|("one" "two" "three")| generate \verb|"(one,two,three)"|
 \calls{conPage}{ySearch}
 \usesdollar{conPage}{conArgstrings}
 \begin{chunk}{defun conPage}
-(defun |conPage| (&rest arglist)
- (let (|$conArgstrings| form da pageName line a b)
+(defun |conPage| (a &rest b)
+ (let (|$conArgstrings| form da pageName line)
  (declare (special |$conArgstrings|))
-  (setq a (car arglist))
-  (setq b (cdr arglist))
-  (setq form (cond ((atom a) (cons a b)) (t a)))
-  (setq |$conArgstrings| (loop for x in (cdr a) collect (|form2HtString| x)))
+  ; the next 4 lines allow e.g. MATRIX INT ==> Matrix Integer (see kPage)
+  (setq form (if (atom a) (cons a b) a))
+  (setq |$conArgstrings| (loop for x in (ifcdr a) collect (|form2HtString| x)))
   (cond ((null (atom a)) (setq a (car a))))
   (setq da (downcase a))
   (cond
@@ -56555,9 +56574,11 @@ Given \verb|("one" "two" "three")| generate \verb|"(one,two,three)"|
           (|mapping| . |DomainMapping|)
           (|enumeration| . |DomainEnumeration|))))
        (|downlink| pageName))
-    ((setq line (|conPageFastPath| da)) (|kPage| line form))
-    ((setq line (|conPageFastPath| (upcase a))) (|kPage| line form))
-    (t (|ySearch| a)))))
+    ((setq line (|conPageFastPath| da)) ; lower case name of cons?
+      (|kPage| line form))
+    ((setq line (|conPageFastPath| (upcase a))) ; upper case an abbrev?
+      (|kPage| line form))
+    (t (|ySearch| a))))) ; slow search (include default packages)
 
 \end{chunk}
 
@@ -59162,6 +59183,17 @@ digits in TechExplorer. Since Saturn is gone we can remove it.
 
 \end{chunk}
 
+\chapter{Utility functions}
+
+\defun{readline}{readline}
+\begin{chunk}{defun readline}
+(DEFUN READLINE (t1)
+ (if t1
+  (|read-line| t1)
+  (|read-line| *STANDARD-INPUT*)))
+
+\end{chunk}
+
 \chapter{The Interpreter}
 \begin{chunk}{Interpreter}
 (setq *print-array* nil)
@@ -59586,8 +59618,10 @@ digits in TechExplorer. Since Saturn is gone we can remove it.
 \getchunk{defun showMsgPos? 0}
 \getchunk{defun startsComment? 0}
 \getchunk{defun StreamNull 0}
+\getchunk{defun stringPrefix? 0}
 \getchunk{defun stripLisp 0}
 \getchunk{defun stripSpaces 0}
+\getchunk{defun substring 0}
 
 \getchunk{defun theid 0}
 \getchunk{defun thefname 0}
@@ -59727,6 +59761,7 @@ digits in TechExplorer. Since Saturn is gone we can remove it.
 \getchunk{defun brightprint-0}
 \getchunk{defun browse}
 \getchunk{defun browseopen}
+\getchunk{defun buildHtMacroTable}
 \getchunk{defun buttonNames}
 
 \getchunk{defun cacheKeyedMsg}
@@ -59934,6 +59969,7 @@ digits in TechExplorer. Since Saturn is gone we can remove it.
 \getchunk{defun getDependentsOfConstructor}
 \getchunk{defun getDirectoryList}
 \getchunk{defun getFirstWord}
+\getchunk{defun getHtMacroItem}
 \getchunk{defun getKeyedMsg}
 \getchunk{defun getMapSig}
 \getchunk{defun getMapSubNames}
@@ -60843,6 +60879,7 @@ digits in TechExplorer. Since Saturn is gone we can remove it.
 \getchunk{defun read}
 \getchunk{defun /read}
 \getchunk{defun readHiFi}
+\getchunk{defun readline}
 \getchunk{defun readSpadProfileIfThere}
 \getchunk{defun readSpad2Cmd}
 \getchunk{defun recordAndPrint}
diff --git a/buglist b/buglist
index af22d96..9aa7de7 100644
--- a/buglist
+++ b/buglist
@@ -12,14 +12,6 @@ dup 50006:
 nonextend 60077:
 
 =========================================================================
-bug 7274: Hyperdoc failed 
-
-Browse -> "Integer" -> IntegerNumberSystem
-
-   >> System error:
-   Caught fatal error [memory may be damaged]
-
-=========================================================================
 todo 336: getdatabase should handle special forms
 
 This code should not exist. Fix getdatabase to return the right answer.
@@ -41344,4 +41336,13 @@ the context, it seems the intention was to write:
 
 (23/5)::Float
 
+fixed by 20141228.04.tpd.patch
+=========================================================================
+bug 7274: Hyperdoc failed 
+
+Browse -> "Integer" -> IntegerNumberSystem
+
+   >> System error:
+   Caught fatal error [memory may be damaged]
+
 
diff --git a/changelog b/changelog
index b5b534a..55627d5 100644
--- a/changelog
+++ b/changelog
@@ -1,3 +1,6 @@
+20141228 tpd src/axiom-website/patches.html 20141228.04.tpd.patch
+20141228 tpd books/bookvol5 close bug 7274
+20141228 tpd buglist: mark bug 7274 fixed
 20141228 tpd src/axiom-website/patches.html 20141228.03.tpd.patch
 20141228 tpd buglist: bug 7274: Hyperdoc failed 
 20141228 tpd src/axiom-website/patches.html 20141228.02.tpd.patch
diff --git a/patch b/patch
index 6275c34..c3a6315 100644
--- a/patch
+++ b/patch
@@ -1,5 +1,2 @@
-buglist: bug 7274: Hyperdoc failed 
-
-Hyperdoc failed while trying to follow the constructor path
-from Integer to IntegerNumberSystem.
+buglist: bug 7274 was fixed by 20141228.04.tpd.patch
 
diff --git a/src/axiom-website/patches.html b/src/axiom-website/patches.html
index a27b2f7..5d7d335 100644
--- a/src/axiom-website/patches.html
+++ b/src/axiom-website/patches.html
@@ -4857,7 +4857,9 @@ src/axiom-website/videos.html add LP in the Large video<br/>
 <a href="patches/20141228.02.tpd.patch">20141228.02.tpd.patch</a>
 git add books/bookvol5, bookvol9 add additional functions<br/>
 <a href="patches/20141228.03.tpd.patch">20141228.03.tpd.patch</a>
-buglist: bug 7274: Hyperdoc failed 
+buglist: bug 7274: Hyperdoc failed <br/>
+<a href="patches/20141228.04.tpd.patch">20141228.03.tpd.patch</a>
+buglist: bug 7274 was fixed by 20141228.04.tpd.patch
  </body>
 </html>
 
