1 2 3 | ||
Editor: alfredo
Time: 2008/03/16 19:56:27 GMT-7 |
||
Note: |
changed: - \documentclass{article} \usepackage{axiom} \begin{document} \title{\$SPAD/src/algebra axserver.spad} \author{Arthur C. Ralfs} \maketitle \begin{abstract} The AxiomServer package is designed to provide a web interface to axiom. \end{abstract} \eject \tableofcontents \eject \section{Lisp preliminaries} Extract the lisp to a file named, say, http.lisp with the command notangle -RServer$\backslash$ Lisp axserver.pamphlet $>$ http.lisp <<Server Lisp>>= ;; file: http.lisp (defvar |StandardOutput| *standard-output*) (defvar |NewLine| '#\NewLine) ;; some regexp stuff (defun |StringMatch| (s1 s2) (si::string-match s1 s2) ) (defun |ListMatches| (&rest args) (si::list-matches args) ) (defun |MatchBeginning| (i) (si::match-beginning i) ) (defun |MatchEnd| (i) (si::match-end i) ) ;; the socket stuff (defun |SiSock| (p spadfn) ;; (format t "SiSocket-1") (si::socket p :server (function (lambda (w) (SPADCALL w spadfn) ) ) :daemon nil) ) (defun |SiListen| (s) ;; (format t "SiListen-1") (si::listen s) ) (defun |SiAccept| (s) (si::accept s)) (defun |SiCopyStream| (q s) (si::copy-stream q s)) ;; Camm Maguire's modified demo server (defun foo (s) (setq get "" pathvar "") (do ((c (read-char s) (read-char s))) ((eq c '#\Space)) (setq get (concat get (string c))) ) (write-line "get: ") (write-line get) (do ((c (read-char s) (read-char s nil 'the-end))) ((eq c '#\Space)) (setq pathvar (concat pathvar (string c))) ) (write-line "pathvar: ") (write-line pathvar) (when pathvar (if (pathname-name (pathname pathvar)) (with-open-file (q pathvar) (si::copy-stream q s)) (dolist (l (directory pathvar)) (format s "~a~%" (namestring l))) ) ) (close s) ) (defun bar (p fn) (let ((s (si::socket p :server fn))) (tagbody l (when (si::listen s) (let ((w (si::accept s))) (foo w))) (sleep 3) (go l)))) ;;(bar 8080 #'foo) @ \section{Axiom Server} Extract the AxiomServer package with the command notangle axserver.pamphlet $>$ axserver.spad <<package AXSERV AxiomServer>>= )abbrev package AXSERV AxiomServer AxiomServer: public == private where public == with axServer: (Integer, SExpression->Void) -> Void multiServ: SExpression -> Void fileserver: SExpression -> Void axget: SExpression -> Void axpost: SExpression -> Void private == add getFile: (SExpression,String) -> Void getCommand: (SExpression,String) -> Void lastStep: () -> String lastType: () -> String formatMessages: String -> String formatMessages1: String -> String axServer(port:Integer,serverfunc:SExpression->Void):Void == WriteLine("socketServer")$Lisp s := SiSock(port,serverfunc)$Lisp -- To listen for just one connection and then close the socket -- uncomment i := 0. i:Integer := 1 while (i > 0) repeat if not null?(SiListen(s)$Lisp)$SExpression then w := SiAccept(s)$Lisp serverfunc(w) -- i := 0 multiServ(s:SExpression):Void == WriteLine("multiServ")$Lisp headers:String := "" char:String -- read in the http headers while (char := STRING(READ_-CHAR_-NO_-HANG(s,NIL$Lisp,'EOF)$Lisp)$Lisp) ^= "EOF" repeat headers := concat [headers,char] sayTeX$Lisp headers StringMatch("([^ ]*)", headers)$Lisp u:UniversalSegment(Integer) u := segment(MatchBeginning(1)$Lisp+1,MatchEnd(1)$Lisp)$UniversalSegment(Integer) reqtype:String := headers.u sayTeX$Lisp concat ["request type: ",reqtype] if reqtype = "GET" then StringMatch("GET ([^ ]*)",headers)$Lisp u:UniversalSegment(Integer) u := segment(MatchBeginning(1)$Lisp+1,MatchEnd(1)$Lisp)$UniversalSegment(Integer) getFile(s,headers.u) if reqtype = "POST" then StringMatch("command=(.*)$",headers)$Lisp u:UniversalSegment(Integer) u := segment(MatchBeginning(1)$Lisp+1,MatchEnd(1)$Lisp)$UniversalSegment(Integer) getCommand(s,headers.u) getFile(s:SExpression,pathvar:String):Void == WriteLine("getFile")$Lisp if not null? PATHNAME_-NAME(PATHNAME(pathvar)$Lisp)$Lisp then -- display contents of file q:=OPEN(pathvar)$Lisp else q:=MAKE_-STRING_-INPUT_-STREAM("Problem with file path")$Lisp file:String := "" while (char := STRING(READ_-CHAR_-NO_-HANG(q,NIL$Lisp,'EOF)$Lisp)$Lisp) ^= "EOF" repeat file := concat [file,char] CLOSE(q)$Lisp file := concat ["Content-Length: ",string(#file),STRING(NewLine$Lisp)$Lisp,STRING(NewLine$Lisp)$Lisp,file] file := concat ["Connection: close",STRING(NewLine$Lisp)$Lisp,file] file := concat ["Content-Type: application/xhtml+xml",STRING(NewLine$Lisp)$Lisp,file] file := concat ["HTTP/1.1 200 OK",STRING(NewLine$Lisp)$Lisp,file] f:=MAKE_-STRING_-INPUT_-STREAM(file)$Lisp SiCopyStream(f,s)$Lisp CLOSE(f)$Lisp CLOSE(s)$Lisp getCommand(s:SExpression,command:String):Void == WriteLine$Lisp concat ["getCommand: ",command] SETQ(tmpmathml$Lisp, MAKE_-STRING_-OUTPUT_-STREAM()$Lisp)$Lisp SETQ(tmpalgebra$Lisp, MAKE_-STRING_-OUTPUT_-STREAM()$Lisp)$Lisp SETQ(savemathml$Lisp, _$texOutputStream$Lisp)$Lisp SETQ(savealgebra$Lisp, _$algebraOutputStream$Lisp)$Lisp SETQ(_$texOutputStream$Lisp,tmpmathml$Lisp)$Lisp SETQ(_$algebraOutputStream$Lisp,tmpalgebra$Lisp)$Lisp -- parseAndInterpret$Lisp command -- parseAndEvalStr$Lisp command -- The previous two commands don't exit nicely when a syntactically incorrect command is -- given to them. They somehow need to be wrapped in CATCH statements but I haven't -- figured out how to do this. parseAndEvalToStringEqNum uses the following CATCH -- statements to call parseAndEvalStr but when I try these they don't work. I get a -- "NIL is not a valid identifier to use in AXIOM" message. Using parseAndEvalToStringEqNum -- works and doesn't crash on a syntax error. -- v := CATCH('SPAD__READER, CATCH('top__level, parseAndEvalStr$Lisp command)$Lisp)$Lisp -- v = 'restart => ['"error"] ans := string parseAndEvalToStringEqNum$Lisp command SETQ(resultmathml$Lisp,GET_-OUTPUT_-STREAM_-STRING(_$texOutputStream$Lisp)$Lisp)$Lisp SETQ(resultalgebra$Lisp,GET_-OUTPUT_-STREAM_-STRING(_$algebraOutputStream$Lisp)$Lisp)$Lisp SETQ(_$texOutputStream$Lisp,savemathml$Lisp)$Lisp SETQ(_$algebraOutputStream$Lisp,savealgebra$Lisp)$Lisp CLOSE(tmpmathml$Lisp)$Lisp CLOSE(tmpalgebra$Lisp)$Lisp -- Since strings returned from axiom are going to be displayed in html I -- should really check for the characters &,<,> and replace them with -- &,<,>. At present I only check for ampersands in formatMessages. mathml:String := string(resultmathml$Lisp) algebra:String := string(resultalgebra$Lisp) algebra := formatMessages(algebra) -- At this point mathml contains the mathml for the output but does not -- include step number or type information. We should also save the command. -- I get the type and step number from the $internalHistoryTable axans:String := concat ["<div><div class=_"command_">Input: ",command,"</div><div class=_"stepnum_">Step number: ",lastStep(),"</div><div class=_"algebra_">",algebra,"</div><div class=_"mathml_">",mathml,"</div><div class=_"type_">Type: ",lastType(),"</div></div>"] WriteLine$Lisp concat ["mathml answer: ",mathml] WriteLine$Lisp concat ["algebra answer: ",algebra] q:=MAKE_-STRING_-INPUT_-STREAM(axans)$Lisp SiCopyStream(q,s)$Lisp CLOSE(q)$Lisp CLOSE(s)$Lisp lastType():String == -- The last history entry is the first item in the $internalHistoryTable list so -- car(_$internalHistoryTable$Lisp) selects it. Here's an example: -- (3 (x+y)**3 (% (value (Polynomial (Integer)) WRAPPED 1 y (3 0 . 1) (2 1 x (1 0 . 3)) (1 1 x (2 0 . 3)) (0 1 x (3 0 . 1))))) -- This corresponds to the input "(x+y)**3" being issued as the third command after -- starting axiom. The following line selects the type information. string car(cdr(car(cdr(car(cdr(cdr(car(_$internalHistoryTable$Lisp)$Lisp)$Lisp)$Lisp)$Lisp)$Lisp)$Lisp)$Lisp)$Lisp lastStep():String == string car(car(_$internalHistoryTable$Lisp)$Lisp)$Lisp formatMessages(str:String):String == WriteLine("formatMessages")$Lisp -- I need to replace any ampersands with & and may also need to -- replace < and > with < and > strlist:List String WriteLine(str)$Lisp strlist := split(str,char "&") str := "" -- oops, if & is the last character in the string this method -- will eliminate it. Need to redo this. for s in strlist repeat str := concat [str,s,"&"] strlen:Integer := #str str := str.(1..(#str - 5)) WriteLine(str)$Lisp -- Here I split the string into lines and put each line in a "div". strlist := split(str, char string NewlineChar$Lisp) str := "" WriteLine("formatMessages1")$Lisp WriteLine(concat strlist)$Lisp for s in strlist repeat WriteLine(s)$Lisp str := concat [str,"<div>",s,"</div>"] str @ \section{Axiom javascript} The javascript is currently included in a "script" element in the Axiom xml page. <<axiom javascript>>= function init() { } function makeRequest() { // The following instantiation of the XMLHttpRequest object is for // browsers other than IE. IE requires something different. http_request = new XMLHttpRequest(); var command = document.getElementById('comm').value; http_request.open('POST', '127.0.0.1:8085', true); http_request.onreadystatechange = handleResponse; // http_request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); // http_request.send("command="+encodeURIComponent(command)); http_request.setRequestHeader('Content-Type', 'text/plain'); http_request.send("command="+command); } function handleResponse() { if (http_request.readyState == 4) { if (http_request.status == 200) { // stick response in div=mathBox var mathString = http_request.responseText; var mathRange = document.createRange(); var mathBox = document.createElementNS('http://www.w3.org/1999/xhtml','div'); mathRange.selectNodeContents(mathBox); var mathFragment = mathRange.createContextualFragment(mathString); mathBox.appendChild(mathFragment); // set id on mathBox // var stepNum = mathBox.firstChild.firstChild.data; // mathBox.setAttribute('id', 'step'+stepNum); // mathBox.setAttribute('class', 'mathbox'); // remove old mathbox document.getElementById('mathAns').removeChild(document.getElementById('mathAns').firstChild) // insert everything into the document document.getElementById('mathAns').appendChild(mathBox); // delete linenum box // mathBox.removeChild(mathBox.firstChild); } else { alert('There was a problem with the request.'+ http_request.statusText); } } } @ \section{Axiom xml} Extract the Axiom xml interface page with the commmand notangle -RAxiom$\backslash$ xml axserver.pamphlet $>$ axiom.xml or in fact make the file name whatever you like instead of "axiom.xml". <<Axiom xml>>= <?xml version="1.0" encoding="UTF-8"?> <!-- <<license-xml>> --> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/xhtml-math11-f.dtd" [ <!ENTITY mathml "http://www.w3.org/1998/Math/MathML"> <!ENTITY InvisibleTimes " "> ]> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:xlink="http://www.w3.org/1999/xlink"> <head> <title>Axiom Interface</title> <disabled script type="text/javascript"> <<axiom javascript>> <disabled /script> </head> <body id="body"> <form id="commreq" action="javascript:makeRequest();"> <p> Enter command: <input type="text" id="comm" name="command" size="80"/> <input type="submit" value="submit command"/> </p> </form> <div id="mathAns"><div></div></div> </body> </html> @ \section{Running Axiom Server} Put the extracted files in a suitable directory, like the one you started Axiom from, and issue the commands: )set output mathml on )lisp (load "http.lisp") )compile axserver axServer(8085,multiServ\$AXSERV) Of course you need a mathml enabled build of axiom to do this. You may also want to issue the command )set messages autoload off before starting the Axiom server. \section{License} <<license>>= --Copyright (c) 2007 Arthur C. Ralfs --All rights reserved. -- --Redistribution and use in source and binary forms, with or without --modification, are permitted provided that the following conditions are --met: -- -- - Redistributions of source code must retain the above copyright -- notice, this list of conditions and the following disclaimer. -- -- - Redistributions in binary form must reproduce the above copyright -- notice, this list of conditions and the following disclaimer in -- the documentation and/or other materials provided with the -- distribution. -- -- - Neither the name of Arthur C. Ralfs nor the -- names of its contributors may be used to endorse or promote products -- derived from this software without specific prior written permission. -- --THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS --IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED --TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A --PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER --OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, --EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR --PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF --LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING --NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS --SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @ <<license-xml>>= Copyright (c) 2007 Arthur C. Ralfs All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither the name of Arthur C. Ralfs nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @ <<*>>= <<license>> <<package AXSERV AxiomServer>> @ \eject \begin{thebibliography}{99} \bibitem{1} nothing \end{thebibliography} \end{document}