Here is a page I found which illustrates how web programming is done using Dyalog APL. Some people may think that APL is only good for writing the shortest code snippets possible or that it is only for solving puzzles, but, it seems to me that it can also be used for real world things; like creating actual web based psychological tests etc.
Link to the page is here :
MiServer: click orange see APL
Anyone who can write APL should be able to host it on the web.™
Home
:Class AdVocab : MiPage
:Include #.HTMLInput ⍝ Useful functions for creating HTML pages
:Field Public Action←'' ⍝ All action buttons have this name
⍝ All Buttons will have this name Action. Value will tell which one was pressed.
:Field Public FName←'First' ⍝ Name of edit field
:Field Public LName←'Last' ⍝ Name of edit field
:Field Public TName←'Teacher' ⍝ Name of edit field
:Field Public WorkF←'DadWork' ⍝ Name of edit field
:Field Public WorkM←'MomWork' ⍝ Name of edit field
:Field Public DOBm←'1' ⍝ Name of dropdown field
:Field Public DOBd←'1' ⍝ Name of dropdown field
:Field Public DOBy←'2013' ⍝ Name of dropdown field
:Field Public Sex←'Male' ⍝ Name of dropdown field
:Field Public Test←'' ⍝ Name of dropdown field Test: Dunn or Dolch or SH40
:Field Public Word←'' ⍝ Name of Edit field Vocabulary word
:Field Public DebugOn←'1' ⍝ turns logging 1=on 0=off
:Field Public State←⎕NS '' ⍝ holds all vars not avail from fields above
Initialized←0 ⍝ set to zero
⎕RL←1000⊥¯2↑⎕TS ⍝ random start from Steven Taylor ⍝ RandStart ⍬
gvars←'INIT badword yes2bad WordTie CurMinMaxJmpLev cLev cLevs cnt yescnt Trys DATA ShLine ShScore' ⍝ global vars to save
∇ GetState
⍎gvars,'←State.(',gvars,')' ⍝ Extract saved state
∇
∇ PutState ⍝ Save State for next post
⍎'State.(',gvars,')←',gvars ⍝ "State" is public and will be saved in page
Initialized←1
∇
lbl←{⍺,(⊃,/' Cur=' ' Min=' ' Max=' ' Jmp=' ' Lev=',¨⍕¨⍵)} ⍝ utility fns used in testselect & nxtword
∇ DEBUG
:Access Public
⍝ DEBUG SECTION. writes data every time a button is pushed.
bob←{⊃,/(⍕¨⍵),¨' '} ⍝ turns nested num vec into min char vector
logfile←'ts=',(bob ⎕TS),' LName=',LName,' Test=',Test,' Action=',Action,' Word=',Word
:If Initialized
logfile,←' CurMinMaxJmpLev=',(bob CurMinMaxJmpLev),' yescnt=',(⍕yescnt),' Trys=',(⍕Trys)
logfile,←' cnt=',(⍕cnt),' cLev=',cLev
:End
logfile←⊂logfile
'DEBUG.txt'writedata logfile
∇
∇ Render req;html;BR
:Access Public
:If Initialized ⋄ GetState
:Else ⋄ yes2bad←0
:If 0=⎕NC'ShLine'
ShLine←'LARGE' 'Red' 'Big' 'Silent' 'Wet' '2' ⋄ ShScore←0
:EndIf
:EndIf
:If DebugOn≡'1' ⋄ DEBUG ⋄ :EndIf ⍝ call DEBUG program ⍝ writes data for every button push.
DoAction ⍝ If a button was pressed, deal with it
BR←'<br>' ⍝ ⋄ NL←'<br>',CRLF
req.Title'Adaptive Vocabulary Test' ⍝ Page title
html←('a href="/"'Enclose'Home') ⍝ A link back to the index page
html,←'h2'Enclose'Adaptive Vocabulary Test: 3 Short Tests: Dunn, Dolch, SH40' ⍝ Header in page
html,←'Your help is very much appreciated. Please do the best you can. Your honest effort will'
html,←' contribute to developing more accurate and concise tests.'
html,←' Please enter your name, sex and birthdate once so 3 different test results may be linked together.'
html,←BR,BR,'If you prefer to remain anonymous, please enter a unique fictious name, correct sex and a'
html,←' birthdate that gives the correct year so that your data will still be useful to me. Thanks!'
html,←BR,BR,'If AFTER doing the 3 tests and making your contribution to my science project you want to do it again or just'
html,←' play you may, but please enter your first and last names as: "play" "play" so that this'
html,←' data is not entered into my research database. Thank you, thank you, thank you!'
html,←BR,BR,'Ok, FIRST enter ALL your information, and THEN click the "Dunn" test.'
html,←' When you finish the "Dunn" test choose the "Dolch" test.'
html,←' When you finish the "Dolch" test choose the "SH40" test. Thanks!'
html,←BR,BR,'First Name=',('FName'Edit FName)
html,←' Last Name=',('LName'Edit LName)
html,←' Sex=',('Sex'DropDown('Male' 'Female')(,Sex))
html,←BR,' Birth Month=',('DOBm'DropDown(⍕¨⍳12)(,DOBm))
html,←' Birth Day=',('DOBd'DropDown(⍕¨⍳31)(,DOBd))
html,←' Birth Year=',('DOBy'DropDown(⍕¨⌽1+(1↑⎕TS)-⍳100)(,DOBy))
html,←' Teacher Name=',('TName'Edit TName)
html,←BR,' Father''s Work=',('WorkF'Edit WorkF)
html,←' Mother''s Work=',('WorkM'Edit WorkM)
html,←BR,'NOW choose and complete the 3 tests in order -->',('Action'Submit'Dunn'),('Action'Submit'Dolch'),('Action'Submit'SH40')
:If Test≡'SH40'
html,←BR,BR,'Choose the one word that means the same thing, or most nearly the same thing as the first word'
html,←BR,'(For example if I showed you--> LARGE: Red Big Silent Wet [You should choose Big])'
html,←BR,'For this test only make your best guess. There is no penalty for guessing.'
:If 1≠⍴,ShLine ⋄ html,←BR,BR,('Word'Edit 1⊃ShLine),(⊃,/'Action'∘Submit¨¯1↓1↓ShLine)
:Else ⋄ html,←BR,BR,('Word'Edit(⊃ShLine)65) ⍝ show results
:EndIf
:ElseIf (Test≡'Dunn')∨(Test≡'Dolch')
html,←BR,BR,'Do you know the meaning of this word?'
html,←BR,BR,('Word'Edit Word 65)
:If ~∨/'DONE'⍷Word ⍝ If not done show some more buttons.
html,←BR,BR,'Action'Submit'Yes' ⍝ A button named 'Action' with Caption 'Yes'
html,←'Action'Submit'No' ⍝ ... another button named 'Action' with Caption 'No'
:End
:End
html←req('post'Form)html ⍝ Put a 'submit' form around it
req.Return html
∇
∇ DoAction
:Select Action
:Case 'Dunn' ⋄ testselect,⊂Test←Action
:Case 'Dolch' ⋄ testselect,⊂Test←Action
:Case 'SH40' ⋄ testselect,⊂Test←Action
:CaseList 'Yes' 'No' ⋄ nxtword Action ⍝ ⍝ check word, prep next word
:CaseList ShLine ⋄ nxtword Action ⍝ Do SH40
:EndSelect
∇
∇ testselect msg;c;m;x;j;Lev;dtbl;tst;files;tday
⍝ select test parameters and find first word. from .DXV file
⎕FUNTIE ⎕FNUMS
files←(⊂(⌽((⌽⎕WSID)⍳'\')↓⌽⎕WSID)),¨'\Intro\jbgames\AdVocab\DolchV' '\Intro\jbgames\AdVocab\DunnrV' '\Intro\jbgames\AdVocab\SH40'
:If 'Dolch'≡tst←¯5↑1⊃msg ⍝ Dolch test
CurMinMaxJmpLev←2 1 14 1 1 ⋄ Trys←15
cLevs←'DPP' 'DP','D',¨⍕¨⍳12 ⍝ data in DPP DP D1 to D12. DBAD is bad words
WordTie←(1⊃files)⎕FTIE 0 ⍝ tie DolchV file.
Word←(?⍴words)⊃words←⎕FREAD WordTie(1⊃CurMinMaxJmpLev) ⍝ new word
cLev←(1⊃CurMinMaxJmpLev)⊃cLevs ⍝ level label for this word
:ElseIf 'SH40'≡tst←¯4↑1⊃msg ⍝ Shipley 1st 40 test
cLevs←,' '
cLev←1⊃CurMinMaxJmpLev←1 1 40 0 1 ⋄ Trys←40 ⍝ if jmp=0 just give test in order
WordTie←(3⊃files)⎕FTIE 0 ⍝ tie SH40 file.
ShLine←cLev⊃⎕FREAD WordTie 1 ⍝ Shline looks like TALK Draw Eat Speak Sleep 3
ShLine←{⎕ML←3 ⋄ (⍵≠' ')⊂⍵}ShLine
ShScore←0
:Else ⍝ DEFAULT ⍝ Dunn-Rankin
CurMinMaxJmpLev←8 1 32 4 1 ⋄ Trys←15
cLevs←'L',¨⍕¨⍳32 ⍝ data in L0 to L32. LBAD is bad words
WordTie←(2⊃files)⎕FTIE 0 ⍝ tie DunnRV file.
Word←(?⍴words)⊃words←⎕FREAD WordTie(1⊃CurMinMaxJmpLev) ⍝ new word
cLev←(1⊃CurMinMaxJmpLev)⊃cLevs ⍝ level label for this word
:End
cnt←1 ⋄ yes2bad←yescnt←0 ⋄ badword←DATA←⍬ ⋄ INIT←CurMinMaxJmpLev,Trys,cnt,yescnt ⍝ set initial parameters
PutState ⍝ Store State
∇
∇ nxtword msg;c;m;x;j;Lev;dtbl;ans;name;sp;DolDun
⍝ get next word from FILE tied with WordTie in fns:testselect
:If Initialized ⋄ GetState ⋄ :Else ⋄ testselect Test ⋄ :EndIf
dtbl←{(-+/∧\⌽⍵∊' ')↓⍵} ⍝ delete trailing blanks
sp←' ' ⋄ tday←⊃,/(4 ¯3 ¯3↑¨⍕¨3↑⎕TS)
c m x j Lev←CurMinMaxJmpLev ⍝ ⋄ ⍎(⊃msg),'.State←0'
:If (⊂msg)∊¯1↓1↓ShLine ⍝ its a Score shipley answer
ShScore+←msg≡{(⍎(⍴⍵)⊃⍵)⊃1↓⍵}ShLine
cnt←cnt+1
:If Trys≥cnt
ShLine←cnt⊃⎕FREAD WordTie 1 ⍝ Shline looks like TALK Draw Eat Speak Sleep 3
ShLine←{⎕ML←3 ⋄ (⍵≠' ')⊂⍵}ShLine
→Pau
:ElseIf Trys<cnt
ShLine←⊂'SH40 DONE Correct=',(⍕ShScore),' of 40 If all 3 tests done Thanks so much.' ⋄ yescnt←0
DATA←⊂(⊂20↑'SH40'),(⊂2↑⍕CurMinMaxJmpLev[1]),('0 '),(2↑⍕cnt-1),(⊂4↑⍕ShScore),sp,(2↑⍕yes2bad),sp,tday,sp,DOBy,sp,(¯2↑DOBm),sp,(¯2↑DOBd),sp,(⊂1↑Sex),sp,(⊂20↑LName),sp,(⊂20↑FName),sp,(⊂20↑TName),sp,(⊂20↑WorkF),sp,(⊂20↑WorkM)
writedata DATA ⍝ writes data to .txt file same name as workspace see above comment for order
CurMinMaxJmpLev←¯3↓INIT ⋄ Trys cnt yescnt←¯3↑INIT ⋄ badword←DATA←⍬ ⍝ set initial parameters for program
⍝ testselect ,⊂Test
→Pau
:EndIf
:EndIf
ans←'Yes'≡msg
:If yescnt=4
:If 'e.'≡¯2↑Word ⋄ yescnt←0 ⍝ done w badword move on
Word←(?⍴words)⊃words←⎕FREAD WordTie(1⊃CurMinMaxJmpLev) ⍝ new word
cLev←(1↑CurMinMaxJmpLev)⊃cLevs ⍝ problem line ********************************************************************
→Pau
:ElseIf ans ⋄ yes2bad+←1 ⋄ Word,←' CAREFUL NOT REAL WORD. Click Yes to Continue.'
⍝ following lines used if starting over if said yes to fake word
Initialized←0 ⋄ cnt←1 ⋄ yes2bad←yescnt←0
DolDun←(1+Action≡'Dunn')⊃(2 1 14 1 1)(8 1 32 4 1) ⍝ start parameters for Dolch and Dunn
INIT←(CurMinMaxJmpLev←DolDun),Trys,cnt,yescnt
→Pau
⍝ following code used if punishing saying yes to fake word
⍝ Lev←Lev⌊c ⋄ c←m⌈c-j←1⌈j-1 ⍝ bad so down level
⍝ CurMinMaxJmpLev←c m x j Lev
⍝ L.curr.Caption←('current :',(⍕cnt),' of ',⍕Trys)lbl CurMinMaxJmpLev
→Pau
:ElseIf ~ans ⋄ Word,←' GOOD NOT REAL WORD. Click Yes to Continue.'
→Pau
:End
:End
:If ans ⋄ Lev←c ⋄ c←x⌊c+j←4⌊j+1 ⍝ yes so up level
:Else ⋄ Lev←Lev⌊m⌈c-1 ⋄ cLev←Lev⊃cLevs ⋄ c←m⌈c-j←1⌈j-1 ⍝ no so down level
:End
⍝ DATA for each trial: word wordlevel ans(0/1) trial personslevel yes2bad today(y m d) dob(y m d) male(0/1) name
⍝ name←{⊂(⍵≠' ')/⍵}{¯1↓⊃,/⍵,¨','}{0=⍴,⍵:'XX' ⋄ ⍵}¨L.(lnam fnam).Text ⍝ lastname,firstmiddle use XX,XX if nothing entered
⍝ DATA,←⊂(⊂20↑Word),(⊂2↑⍕CurMinMaxJmpLev[1]),(2↑⍕ans),(2↑⍕cnt),(⊂4↑cLev),(3↑⎕TS),(3↑L.Date.IDNToDate 1↑L.Date.DateTime),L.grp.male.State,name
DATA,←⊂(⊂20↑Word),(⊂2↑⍕CurMinMaxJmpLev[1]),(2↑⍕ans),(2↑⍕cnt),(⊂4↑cLev),sp,(2↑⍕yes2bad),sp,tday,sp,DOBy,sp,(¯2↑DOBm),sp,(¯2↑DOBd),sp,(⊂1↑Sex),sp,(⊂20↑LName),sp,(⊂20↑FName),sp,(⊂20↑TName),sp,(⊂20↑WorkF),sp,(⊂20↑WorkM)
⍝ L.data.Text←⍕↑⍕¨DATA
Jump:⍝ L.prev.Caption←('previous:',(⍕cnt),' of ',⍕Trys)lbl CurMinMaxJmpLev
cnt←cnt+1 ⋄ yescnt←ans×yescnt+1 ⋄ CurMinMaxJmpLev←c m x j Lev
⍝ L.curr.Caption←('current :',(⍕cnt),' of ',⍕Trys)lbl CurMinMaxJmpLev
:If cnt≤Trys ⍝ This is main loop
:If yescnt=4 ⍝ if said yes 4 times in a row check with a bad word
⍝ badword,←⊂L.word.Caption←(?⍴words)⊃words←⍎(1↑1⊃cLev),'BAD' ⍝ new bad word from new level no dups
badword,←⊂Word←(?⍴words)⊃words←(⎕FREAD WordTie(¯1+2⊃⎕FSIZE WordTie))~badword ⍝ new bad word from last component no dups
:Else
⍝ L.word.Caption←(?⍴words)⊃words←(⍎cLev←⍎'c⊃cLevs')~dtbl¨1⊃¨DATA ⍝ new word from new level no dups from WS
Word←(?⍴words)⊃words←(⎕FREAD WordTie c)~dtbl¨1⊃¨DATA ⍝ new word from new level FILE. no repeats from DATA
cLev←c⊃cLevs ⍝ level label for this word
:End
:ElseIf 'DONE'≡4↑Word
:If ans ⍝ yes to Try Again reset screen for new testing
CurMinMaxJmpLev←¯3↓INIT ⋄ Trys cnt yescnt←¯3↑INIT ⋄ badword←DATA←⍬ ⍝ set initial parameters for program
⍝ L.word.Caption←word←(?⍴words)⊃words←⍎cLev←⍎'(1↑CurMinMaxJmpLev)⊃cLevs' ⍝ new word from WS
Word←(?⍴words)⊃words←⎕FREAD WordTie(1⊃CurMinMaxJmpLev) ⍝ new word from FILE
cLev←(1⊃CurMinMaxJmpLev)⊃cLevs ⍝ level label for this word
⍝ L.(curr prev).Caption←('current :1 of ',cap)('previous :0 of ',cap←(⍕Trys)lbl CurMinMaxJmpLev)
:Else
:If 'R'=1↑4⊃'.'⎕WG'APLVersion' ⋄ ⎕OFF ⋄ :Else ⋄ ⎕EX'L' ⋄ :End ⍝ if runtime shutoff otherwise just end program
:End
:Else ⍝ finish up and write DATA to file and ask if want to try again
Word←Test,' DONE Level=',cLev,' Choose Next Test' ⋄ yescnt←0
writedata DATA ⍝ writes data to .txt file same name as workspace see above comment for order
:End
Pau:PutState ⍝ Store State
∇
∇ {f}writedata x;tie;file;lf;nl
⍝ also used for Debugging MildServer on the server see Boot.Demo
⍝ file←⎕WSID,'.txt'
:If 0=⎕NC'f' ⋄ f←'AdVocab.txt' ⋄ :End
file←(⌽((⌽⎕WSID)⍳'\')↓⌽⎕WSID),'\Intro\jbgames\AdVocab\',f
lf←⎕AV[3] ⋄ nl←⎕AV[4] ⍝ 2=linefeed 3=newline
:Trap 0 ⋄ tie←file ⎕NCREATE 0
:Else ⋄ tie←file ⎕NTIE 0 2
:EndTrap
(1↓¨⍕¨(x,¨nl),¨lf)⎕NAPPEND¨tie
⎕NUNTIE tie
∇
:EndClass
MiServer v2.1Introduction to MiServer