The Stack
The GuruHits engine was a single Apple HyperCard stack acting as a web CGI: each request arrived as an AppleEvent and HyperTalk scripts built the HTML reply. The recovered stack and its scripts are explored here.
GuruHits did not run on a normal web stack. Behind WebSTAR sat a single HyperCard stack acting as a CGI: every request to the quiz arrived as an AppleEvent, and HyperTalk built the reply. The window below is a faithful, CSS-simulated recreation of that control card — the actual "machine room." Click a button on the card, or pick an object from the list, to read its real recovered script in the script editor. The chrome uses the period fonts (Charcoal-style title bars, Geneva fields, Monaco code); nothing here executes — it is the source, preserved.
The WebSTAR ACGI engine: each web request arrives as an AppleEvent and returns the HTTP response. (A sibling quiz on the same stack is anonymized as "OtherQuiz".)
-- GuruHits ACGI router — the recovered stack script, shown in full. A sibling quiz
-- that ran on the same stack has been anonymized (its names renamed to "OtherQuiz" /
-- gOther* / otherquiz.db); nothing is removed. Otherwise verbatim. © Joe Savelberg.
on openstack
global HTTP_10_header,HTTP_ERR_header,gGuruHitsDB,gDBrange,gHighScore,gOtherDB,gOtherDBrange,gOtherHighScore
if there is a menuitem "HyperCard.acgi" of menu "application" then domenu "Hypercard.acgi"
put "HTTP/1.0 200 OK" & numtochar(13) & numtochar(10) & "Server: WebSTAR/4.5 ID/ACGI" ¬
& numtochar(13) & numtochar(10) & "Host: www.guruhits.com" ¬
& numtochar(13) & numtochar(10) & "MIME-Version: 1.0" & numtochar(13) & numtochar(10) ¬
& "Content-type: text/html" & numtochar(13) & numtochar(10) & numtochar(13) & numtochar(10) into HTTP_10_header
put "HTTP/1.0 503 ERR" & numtochar(13) & numtochar(10) & "Server: WebSTAR/4.5 ID/ACGI" ¬
& numtochar(13) & numtochar(10) & "Host: www.guruhits.com" ¬
& numtochar(13) & numtochar(10) & "MIME-Version: 1.0" & numtochar(13) & numtochar(10) ¬
& "Content-type: text/html" & numtochar(13) & numtochar(10) & numtochar(13) & numtochar(10) into HTTP_ERR_header
if there is a menuitem "WebSTAR" of menu "Application" then domenu "WebSTAR"
put "" into gChecksums
set hilite of bg btn id 2 to true
send mouseUp to bg btn id 2
hide msg
LoadDocuments
end openstack
on AppleEvent class, ID, sender
lock screen
set lockRecent to true
if there is a menuitem "HyperCard.acgi" of menu "application" then domenu "Hypercard.acgi"
global FormInformation,customerTCPAddress,partner
put "" into FormInformation
put "" into customerTCPAddress
put "" into partner
put "" into msg
put the ticks into starter
if class & ID is "WWWΩsdoc" then
request appleEvent "data"
put it into whichForm
request appleEvent data with keyword "post"
if it ≠ "" then
put it into FormInformation
else if whichform ≠ "highscore" then
put "HTTP/1.0 503 ERR" & numtochar(13) & numtochar(10) & "Server: WebSTAR/4.5 ID/ACGI" ¬
& numtochar(13) & numtochar(10) &"MIME-Version: 1.0" & numtochar(13) & numtochar(10) ¬
& "Content-type: text/html" & numtochar(13) & numtochar(10) & numtochar(13) & numtochar(10) into HTTP_ERR_header
put HTTP_ERR_Header & return & "<HTML><HEAD><TITLE>GuruHits Error!</TITLE></HEAD>" &¬
"<BODY><H1>GuruHits Error!</H1><HR><H3>You didn't submit a correct GuruHits web form!" &¬
"<BR>Please go back to the <A HREF=http://www.guruhits.com/>GuruHits site</A> and enter the quiz!</H3></BODY></HMTL>" into output
reply output
end if
request appleEvent data with keyword "addr"
put it into customerTCPAddress
request appleEvent data with keyword "DIRE"
put it into partner
-- if "~otherquiz" is in partner then put "3690" into siteid
-- else
if "~demo" is in partner or "~otherquiz" is in partner then
if "category=2" is in FormInformation then
put "3690" into siteid
else if "category=1" is in FormInformation then
put "3019" into siteid
else
put "3019" into siteid
end if
else if "~guruhits" is in partner then put "3019" into siteid
else put "3019" into siteid
if whichForm = "quizresult" then
send quizresult to cd id siteid
else if whichForm = "quizscreen" then
send quizscreen to cd id siteid
else if whichForm = "scoring" then
send savescore to cd id siteid
else if whichForm = "Reload" then
ReloadDocs
else if whichForm = "QuitHC&<redacted>&DoQuit=ok" then
quithc
domenu "quit hypercard"
-- start other-quiz scripts
else if whichForm = "OtherQuiz" then
-- go cd "OtherQuiz"
OtherQuizForm -- FormInformation,customerTCPAddress
else if whichForm = "OtherQuizShort" then
-- go cd "OtherQuizShort"
OtherQuizFormShort -- FormInformation,customerTCPAddress
else if whichForm = "OtherQuizCalc" then
-- go cd "OtherQuizCalc"
OtherQuizFormCalc -- FormInformation,customerTCPAddress
-- end other-quiz scripts
end if
else
pass appleEvent
end if
if there is a menuitem "WebSTAR 4.5" of menu "Application" then domenu "WebSTAR 4.5"
put the ticks - starter after msg
end AppleEvent
on LoadDocuments
global gGuruHitsDB,gDBrange,gHighScore,gOtherDB,gOtherDBrange,gOtherHighScore
-- load guruhits
put "guruhits.db" into dbLoc
open file dbLoc
read from file dbLoc until eof
put it into gGuruHitsDB
close file dbLoc
if last char of gGuruhitsDB is return then delete last char of gGuruHitsDB
put number of lines of gGuruHitsDB into gDBrange
set itemdelimiter to tab
put item 8 of line 1 of cd fld id 7 of cd id 3019 into gHighScore
--
put "otherquiz.db" into dbLoc
open file dbLoc
read from file dbLoc until eof
put it into gOtherDB
close file dbLoc
if last char of gOtherDB is return then delete last char of gOtherDB
put number of lines of gOtherDB into gOtherDBrange
set itemdelimiter to tab
put item 8 of line 1 of cd fld id 7 of cd id 3690 into gOtherHighScore
-- start other-quiz scripts
global gOtherResults,gOtherResults2,gOtherResults3
open file "otherresults.html"
read from file "otherresults.html" until eof
put it into gOtherResults
close file "otherresults.html"
open file "otherresults2.html"
read from file "otherresults2.html" until eof
put it into gOtherResults2
close file "otherresults2.html"
open file "otherresults3.html"
read from file "otherresults3.html" until eof
put it into gOtherResults3
close file "otherresults3.html"
-- end other-quiz scripts
end LoadDocuments
on ReloadDocs
global HTTP_10_header,HTTP_ERR_header
LoadDocuments
put HTTP_10_Header & "<HTML><TITLE>GuruHits DB Reloaded</TITLE>" &¬
"<BODY BGCOLOR=#FFFFFF>The GuruHits DB has been reloaded</BODY></HTML>" into OutPut
reply OutPut
end ReloadDocs
on quithc
global HTTP_10_header,HTTP_ERR_header
put HTTP_10_Header & "<HTML><TITLE>GuruHits Closing Down</TITLE>" &¬
"<BODY BGCOLOR=#FFFFFF>The GuruHits System has closed down.</BODY></HTML>" into OutPut
reply OutPut
end quithc
function encrypt ref
put scramble(ref,"GuruHits") into source
put the length of source into sourcelen
put "" into thedestiny
repeat with x = 1 to sourcelen
put converttoHEX(chartonum(char x of source)) after thedestiny
end repeat
set itemdelimiter to tab
return(thedestiny)
end encrypt
function decrypt source
repeat with x = length(source) down to 1
if x mod 2 ≠ 0 then next repeat
put " " after char x of source
end repeat
put length(source) into sourcelen
put "" into thedestiny
put 1 into x
repeat
if char x to x+1 of source = "0x" then
add 2 to x
next repeat
end if
if char x of source is in " x" then
add 1 to x
next repeat
end if
put char x of source into a
if a is in "abcdef" then put convertHEXtoAB(a) into a
put char x+1 of source into b
if it="" then put 0 into b
if b is in "abcdef" then put convertHEXtoAB(b) into b
put numtochar(a*16+b) after thedestiny
add 2 to x
if x ≥ sourcelen then exit repeat
end repeat
put scramble(thedestiny,"GuruHits",true) into thedestiny
set itemdelimiter to tab
return(thedestiny)
end decrypt
function converttoHEX symbol
set itemdelimiter to ","
put symbol div 16 into a
put symbol - (a*16) into b
if a>9 or b>9 then
put "10,11,12,13,14,15" into them -- not 16 since that's 0x10
put "ABCDEF" into those
repeat with x = 1 to 6
get item x of them
if a < it and b<it then exit repeat
if a is it then put char x of those into a
if b is it then put char x of those into b
end repeat
end if
return (a & b)
end converttoHEX
function convertHEXtoAB a,b
set itemdelimiter to ","
put "10,11,12,13,14,15" into them -- not 16 since that's 0x10
put "ABCDEF" into those
repeat with x = 1 to 6
if a is char x of those then return item x of them
end repeat
end convertHEXtoAB
function webdecode source
if char 1 of source = "+" or source = "%20" then
return (" ")
exit webdecode
end if
if char 1 of source = "%" then delete char 1 of source
repeat with x = length(source) down to 1
if x mod 2 ≠ 0 then next repeat
put " " after char x of source
end repeat
put length(source) into sourcelen
put "" into thedestiny
put 1 into x
repeat
if char x to x+1 of source = "0x" then
add 2 to x
next repeat
end if
if char x of source is in " x" then
add 1 to x
next repeat
end if
put char x of source into a
if a is in "abcdef" then put convertHEXtoAB(a) into a
put char x+1 of source into b
if it="" then put 0 into b
if b is in "abcdef" then put convertHEXtoAB(b) into b
put numtochar(a*16+b) after thedestiny
add 2 to x
if x ≥ sourcelen then exit repeat
end repeat
set itemdelimiter to tab
return(thedestiny)
end webdecode
function webencode source,form
if form = "web" then
put "&#" & chartonum(source) & ";" into thedestiny
return(thedestiny)
else if form = "url" then
put the length of source into sourcelen
put "" into thedestiny
repeat with x = 1 to sourcelen
put converttoHEX(chartonum(char x of source)) after thedestiny
end repeat
set itemdelimiter to tab
put "%" & thedestiny into thedestiny
return(thedestiny)
end if
end webencode
on createEmail output,fromaddress,quizname,quizurl
set itemdelimiter to tab
put "DATA:WebSTAR:NetCloak Files:NetCloak Mail Queue:" into mailqueue
put item 4 of output into email
get offset("@",email)
if it ≠ 0 then put "@" into char it to it+4 of email
put "Server: relay.example.net" & return & "To:" && email & return & "From:" && fromaddress & return & "CC:" & return & "Subject: Your Certificate for playing" && quizname & return & "Message:" & return into outmsg
put quizname && "- Certificate" & numtochar(13) & numtochar(10) & numtochar(13) & numtochar(10) & item 5 of output & ", you participated in the" && quizname && "and achieved a score of" && item 8 of output && "points with an accuracy of" && item 10 of output && "percent attaining the status of a" && item 11 of output && "at quiz level" && item 13 of output & "." & numtochar(13) & numtochar(10) & numtochar(13) & numtochar(10) & "If you'd like to play the" && quizname && "again, then please go to" && quizurl & numtochar(13) & numtochar(10) & numtochar(13) & numtochar(10) & "Don't forget to forward your quiz results to your family and friends." & numtochar(13) & numtochar(10) & numtochar(13) & numtochar(10) & "Have fun!" & numtochar(13) & numtochar(10) & numtochar(13) & numtochar(10) & "Joe Savelberg" & numtochar(13) & numtochar(10) & numtochar(13) & numtochar(10) & "QuizMaster@guruhits.com" & numtochar(13) & numtochar(10) & "http://www.guruhits.com" & numtochar(13) & numtochar(10) & numtochar(13) & numtochar(10) & "--------------------------------------------" & numtochar(13) & numtochar(10) & "X-URL:" && quizurl & numtochar(13) & numtochar(10) & "X-Originating-IP: [" & item 3 of output & "]" & numtochar(13) & numtochar(10) & "X-Address:" && email & numtochar(13) & numtochar(10) after outmsg
put mailqueue & the seconds & "-" & the ticks into mailfile
open file mailfile
write outmsg to file mailfile
close file mailfile
end createEmail
on otherQuizForm -- FormInformation --,customerTCPAddress
global FormInformation,customerTCPAddress
go cd "OtherQuiz"
send otherQuizForm to cd "OtherQuiz"
end otherQuizForm
on otherQuizFormShort -- FormInformation --,customerTCPAddress
global FormInformation,customerTCPAddress
go cd "OtherQuizShort"
send otherQuizForm to cd "OtherQuizShort"
end otherQuizFormShort
on otherQuizFormCalc -- FormInformation --,customerTCPAddress
global FormInformation,customerTCPAddress
go cd "OtherQuizCalc"
send otherQuizForm to cd "OtherQuizCalc"
end otherQuizFormCalc
-- the score record written for each play (item-delimited):
-- 1. the short date
-- 2. the long time
-- 3. CustomerTCPAddress
-- 4. email
-- 5. firstname
-- 6. lastname
-- 7. player
-- 8. score
-- 9. quiznb
-- 10. mypercentage
-- 11. mystatus
-- 12. checksum
-- 13. level
-- 14. category into outputThe quiz engine — quizscreen builds a quiz from the song database and renders the page HTML.
on quizscreen
global gGuruHitsDB,gDBrange,FormInformation,CustomerTCPAddress,partner,gHighScore
put "" into songline
put "" into level
put "" into category
set itemdelimiter to "&"
repeat with x = 1 to number of items of FormInformation
set itemdelimiter to "&"
get item x of FormInformation
if "songline" is in it then
set itemdelimiter to "="
put decrypt(last item of it) into songline
next repeat
end if
if "category" is in it then
set itemdelimiter to "="
put last item of it into category
next repeat
end if
if "level" is in it then
set itemdelimiter to "="
put last item of it into level
next repeat
end if
end repeat
if category = "" then put "1" into category
if level = "" then put "1" into level
set itemdelimiter to "*"
if item 1 of songline = "0000" and item 2 of songline = "0000" and item 3 of songline = "0000" and item 4 of songline = "6823154" then
put 0 into score
put 1 into quiznb
put 0 into goodanswers
else
put item 5 of songline into score
put item 6 of songline + 1 into quiznb
put item 7 of songline into goodanswers
end if
put "<SET_LOCAL score = " & quote & score & quote & ">" & return after output
put "<SET_LOCAL quiznb = " & quote & quiznb & quote & ">" & return after output
put "<SET_LOCAL category = " & quote & category & quote & ">" & return after output
put "<SET_LOCAL level = " & quote & level & quote & ">" & return after output
put "<SET_LOCAL goodanswers = " & quote & goodanswers & quote & ">" & return after output
put "<SET_LOCAL topscore = " & quote & gHighScore & quote & ">" & return after output
set itemdelimiter to tab
put false into test
put "" into randomlist
if level < 3 then
repeat until test
get random(gDBrange)
if it is in randomlist then next repeat
put it & return after randomlist
if number of lines of randomlist = 3 then put true into test
end repeat
else
repeat until test
get random(gDBrange)
if it is in randomlist then next repeat
put false into test2
repeat with x = 1 to the number of lines of randomlist
if item 2 of line it of gGuruHitsDB = item 2 of line (line x of randomlist) of gGuruHitsDB then
put true into test2
exit repeat
end if
end repeat
if test2 then next repeat
put it & return after randomlist
if number of lines of randomlist = 3 then put true into test
end repeat
end if
put line (line 1 of randomlist) of gGuruHitsDB into Choose1
put line (line 2 of randomlist) of gGuruHitsDB into Choose2
put line (line 3 of randomlist) of gGuruHitsDB into Choose3
if level > 1 then
put "00000000.gif" into item 5 of Choose1
put "00000000.gif" into item 5 of Choose2
put "00000000.gif" into item 5 of Choose3
put "http://www.amazon.com/exec/obidos/redirect?tag=theoriginalfreei&path=subst/home/music.html" into item 4 of Choose1
put "http://www.amazon.com/exec/obidos/redirect?tag=theoriginalfreei&path=subst/home/music.html" into item 4 of Choose2
put "http://www.amazon.com/exec/obidos/redirect?tag=theoriginalfreei&path=subst/home/music.html" into item 4 of Choose3
if level = 2 then
put "" into item 2 of Choose1
put "" into item 2 of Choose2
put "" into item 2 of Choose3
else
put "" into item 3 of Choose1
put "" into item 3 of Choose2
put "" into item 3 of Choose3
end if
end if
put item 1 of line (line random(3) of randomlist) of gGuruHitsDB into Song2Play
put "<SET_LOCAL playsong = " & quote & Song2Play & quote & ">" & return after output
put "<SET_LOCAL songline = " & quote & encrypt(line 1 of randomlist & "*" & line 2 of randomlist & "*" & line 3 of randomlist & "*" & the ticks & "*" & score & "*" & quiznb & "*" & goodanswers) & quote & ">" & return after output
put "<SET_LOCAL ref1 = " & quote & encrypt(item 1 of Choose1) & quote & ">" & return after output
put "<SET_LOCAL artist1 = " & quote & item 2 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL song1 = " & quote & item 3 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL url1 = " & quote & item 4 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL cover1 = " & quote & item 5 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL ref2 = " & quote & encrypt(item 1 of Choose2) & quote & ">" & return after output
put "<SET_LOCAL artist2 = " & quote & item 2 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL song2 = " & quote & item 3 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL url2 = " & quote & item 4 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL cover2 = " & quote & item 5 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL ref3 = " & quote & encrypt(item 1 of Choose3) & quote & ">" & return after output
put "<SET_LOCAL artist3 = " & quote & item 2 of Choose3 & quote & ">" & return after output
put "<SET_LOCAL song3 = " & quote & item 3 of Choose3 & quote & ">" & return after output
put "<SET_LOCAL url3 = " & quote & item 4 of Choose3 & quote & ">" & return after output
put "<SET_LOCAL cover3 = " & quote & item 5 of Choose3 & quote & ">" & return after output
if score > 9999 * level then put "<SET_LOCAL mystatus = " & quote & "Guru" & quote & ">" & return after output
else if score > 4999 * level then put "<SET_LOCAL mystatus = " & quote & "Vice Guru" & quote & ">" & return after output
else if score > 2499 * level then put "<SET_LOCAL mystatus = " & quote & "Senior Guru" & quote & ">" & return after output
else if score > 999 * level then put "<SET_LOCAL mystatus = " & quote & "Junior Guru" & quote & ">" & return after output
else if score > 499 * level then put "<SET_LOCAL mystatus = " & quote & "Music Buff" & quote & ">" & return after output
else if score > 199 * level then put "<SET_LOCAL mystatus = " & quote & "Follower" & quote & ">" & return after output
else if score > 99 * level then put "<SET_LOCAL mystatus = " & quote & "Fan" & quote & ">" & return after output
else
put "<SET_LOCAL mystatus = " & quote & "Novice" & quote & ">" & return after output
end if
reply(output)
end quizscreen
on quizresult
global gGuruHitsDB,gDBrange,gChecksums,FormInformation,CustomerTCPAddress,partner,gHighScore
put "" into Song2Play
put "" into songline
put "" into theanswer
put "" into level
put "" into category
set itemdelimiter to "&"
repeat with x = 1 to number of items of FormInformation
set itemdelimiter to "&"
get item x of FormInformation
if "playsong" is in it then
set itemdelimiter to "="
put last item of it into Song2Play
next repeat
end if
if "songline" is in it then
set itemdelimiter to "="
put decrypt(last item of it) into songline
next repeat
end if
if "answer" is in it then
set itemdelimiter to "="
put decrypt(last item of it) into theanswer
next repeat
end if
if "category" is in it then
set itemdelimiter to "="
put last item of it into category
next repeat
end if
if "level" is in it then
set itemdelimiter to "="
put last item of it into level
next repeat
end if
end repeat
if category = "" then put "1" into category
if level = "" then put "1" into level
set itemdelimiter to "*"
put line (item 1 of songline) of gGuruHitsDB into Choose1
put line (item 2 of songline) of gGuruHitsDB into Choose2
put line (item 3 of songline) of gGuruHitsDB into Choose3
put item 4 of songline into checksum
put item 5 of songline into score
put item 6 of songline into quiznb
put item 7 of songline into goodanswers
if offset(checksum,gChecksums) ≠ 0 then
get "<REDIRECT " & quote & "http://www.guruhits.com/login.html" & quote & ">"
reply (it)
exit quizresult
else
put return & checksum after gChecksums
if number of lines of gChecksums > 2000 then delete line 1 - 1000 of gChecksums
end if
set itemdelimiter to tab
if theanswer = Song2play then
put "<SET_LOCAL answer = " & quote & "correct" & quote & ">" & return after output
put score + (10 * level) into score
put goodanswers + 1 into goodanswers
else
put "<SET_LOCAL answer = " & quote & "wrong" & quote & ">" & return after output
if level = "4" then put score - 40 into score
end if
put "<SET_LOCAL score = " & quote & score & quote & ">" & return after output
put "<SET_LOCAL quiznb = " & quote & quiznb & quote & ">" & return after output
put "<SET_LOCAL songline = " & quote & encrypt("0000*0000*0000*" & the ticks & "*" & score & "*" & quiznb & "*" & goodanswers) & quote & ">" & return after output
put "<SET_LOCAL level = " & quote & level & quote & ">" & return after output
put "<SET_LOCAL goodanswers = " & quote & goodanswers & quote & ">" & return after output
put "<SET_LOCAL topscore = " & quote & gHighScore & quote & ">" & return after output
if Song2Play = item 1 of Choose1 then
put "<SET_LOCAL artist1 = " & quote & item 2 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL song1 = " & quote & item 3 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL url1 = " & quote & item 4 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL cover1 = " & quote & item 5 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL audio1 = " & quote & item 6 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL playsong = " & quote & item 1 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL artist2 = " & quote & item 2 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL song2 = " & quote & item 3 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL url2 = " & quote & item 4 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL cover2 = " & quote & item 5 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL audio2 = " & quote & item 6 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL artist3 = " & quote & item 2 of Choose3 & quote & ">" & return after output
put "<SET_LOCAL song3 = " & quote & item 3 of Choose3 & quote & ">" & return after output
put "<SET_LOCAL url3 = " & quote & item 4 of Choose3 & quote & ">" & return after output
put "<SET_LOCAL cover3 = " & quote & item 5 of Choose3 & quote & ">" & return after output
put "<SET_LOCAL audio3 = " & quote & item 6 of Choose3 & quote & ">" & return after output
else if Song2Play = item 1 of Choose2 then
put "<SET_LOCAL artist1 = " & quote & item 2 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL song1 = " & quote & item 3 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL url1 = " & quote & item 4 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL cover1 = " & quote & item 5 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL audio1 = " & quote & item 6 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL playsong = " & quote & item 1 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL artist2 = " & quote & item 2 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL song2 = " & quote & item 3 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL url2 = " & quote & item 4 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL cover2 = " & quote & item 5 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL audio2 = " & quote & item 6 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL artist3 = " & quote & item 2 of Choose3 & quote & ">" & return after output
put "<SET_LOCAL song3 = " & quote & item 3 of Choose3 & quote & ">" & return after output
put "<SET_LOCAL url3 = " & quote & item 4 of Choose3 & quote & ">" & return after output
put "<SET_LOCAL cover3 = " & quote & item 5 of Choose3 & quote & ">" & return after output
put "<SET_LOCAL audio3 = " & quote & item 6 of Choose3 & quote & ">" & return after output
else if Song2Play = item 1 of Choose3 then
put "<SET_LOCAL artist1 = " & quote & item 2 of Choose3 & quote & ">" & return after output
put "<SET_LOCAL song1 = " & quote & item 3 of Choose3 & quote & ">" & return after output
put "<SET_LOCAL url1 = " & quote & item 4 of Choose3 & quote & ">" & return after output
put "<SET_LOCAL cover1 = " & quote & item 5 of Choose3 & quote & ">" & return after output
put "<SET_LOCAL audio1 = " & quote & item 6 of Choose3 & quote & ">" & return after output
put "<SET_LOCAL playsong = " & quote & item 1 of Choose3 & quote & ">" & return after output
put "<SET_LOCAL artist2 = " & quote & item 2 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL song2 = " & quote & item 3 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL url2 = " & quote & item 4 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL cover2 = " & quote & item 5 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL audio2 = " & quote & item 6 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL artist3 = " & quote & item 2 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL song3 = " & quote & item 3 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL url3 = " & quote & item 4 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL cover3 = " & quote & item 5 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL audio3 = " & quote & item 6 of Choose2 & quote & ">" & return after output
end if
if score > 9999 * level then put "<SET_LOCAL mystatus = " & quote & "Guru" & quote & ">" & return after output
else if score > 4999 * level then put "<SET_LOCAL mystatus = " & quote & "Vice Guru" & quote & ">" & return after output
else if score > 2499 * level then put "<SET_LOCAL mystatus = " & quote & "Senior Guru" & quote & ">" & return after output
else if score > 999 * level then put "<SET_LOCAL mystatus = " & quote & "Junior Guru" & quote & ">" & return after output
else if score > 499 * level then put "<SET_LOCAL mystatus = " & quote & "Music Buff" & quote & ">" & return after output
else if score > 199 * level then put "<SET_LOCAL mystatus = " & quote & "Follower" & quote & ">" & return after output
else if score > 99 * level then put "<SET_LOCAL mystatus = " & quote & "Fan" & quote & ">" & return after output
else
put "<SET_LOCAL mystatus = " & quote & "Novice" & quote & ">" & return after output
end if
reply(output)
end quizresult
on savescore
global gGuruHitsDB,gDBrange,FormInformation,CustomerTCPAddress,partner,gHighScore
put partner & ":guruhits.score" into scorefile
put cd fld "highscore" into temp
put "" into firstname
put "" into lastname
put "" into email
put "" into player
put "" into songline
put "" into level
put "" into category
set itemdelimiter to "&"
repeat with x = 1 to number of items of FormInformation
set itemdelimiter to "&"
get item x of FormInformation
if "firstname" is in it then
set itemdelimiter to "="
put casechange(last item of it,"c") into firstname
repeat until offset("+",firstname) = 0
put " " into char offset("+",firstname) of firstname
end repeat
repeat until offset("%",firstname) = 0
get offset("%",firstname)
put webencode(webdecode(char it to it+2 of firstname),"web") into char it to it+2 of firstname
end repeat
next repeat
end if
if "lastname" is in it then
set itemdelimiter to "="
put casechange(last item of it,"c") into lastname
repeat until offset("+",lastname) = 0
put " " into char offset("+",lastname) of lastname
end repeat
repeat until offset("%",lastname) = 0
get offset("%",lastname)
put webencode(webdecode(char it to it+2 of lastname),"web") into char it to it+2 of lastname
end repeat
next repeat
end if
if "email" is in it then
set itemdelimiter to "="
put casechange(last item of it,"l") into email
repeat until offset("%",email) = 0
get offset("%",email)
put webencode(webdecode(char it to it+2 of email),"web") into char it to it+2 of email
end repeat
next repeat
end if
if "player" is in it then
set itemdelimiter to "="
put last item of it into player
next repeat
end if
if "songline" is in it then
set itemdelimiter to "="
put decrypt(last item of it) into songline
next repeat
end if
if "category" is in it then
set itemdelimiter to "="
put last item of it into category
next repeat
end if
if "level" is in it then
set itemdelimiter to "="
put last item of it into level
next repeat
end if
end repeat
if firstname = "" and lastname = "" and player = "" then
reply ("<P>Your score was already saved!</P>")
exit savescore
end if
if category = "" then put "1" into category
if level = "" then put "1" into level
set itemdelimiter to "*"
put item 4 of songline into checksum
put item 5 of songline into score
put item 6 of songline into quiznb
put item 7 of songline into goodanswers
if checksum is in temp then
reply ("<P>Your score was already saved!</P>")
exit savescore
end if
put the numberformat into savenbformat
set the numberformat to 0.##
put goodanswers / quiznb * 100 into mypercentage
if score > 9999 * level then put "Guru" into mystatus
else if score > 4999 * level then put "Vice Guru" into mystatus
else if score > 2499 * level then put "Senior Guru" into mystatus
else if score > 999 * level then put "Junior Guru" into mystatus
else if score > 499 * level then put "Music Buff" into mystatus
else if score > 199 * level then put "Follower" into mystatus
else if score > 99 * level then put "Fan" into mystatus
else
put "Novice" into mystatus
end if
set itemdelimiter to tab
put tab into what
put return & the short date & what & the long time & what & CustomerTCPAddress & what & email & what¬
& firstname & what & lastname & what & player & what & score & what & quiznb & what & mypercentage & what¬
& mystatus & what & checksum & what & level & what & category into output
put temp & return & output into temp
put FullSort(temp,"t=n","d=d","c=item 9") into temp
put FullSort(temp,"t=n","d=d","c=item 10") into temp
put FullSort(temp,"t=n","d=d","c=item 8") into temp
-- put FullSort(temp,"t=n","d=d","c=item 8") into temp
if return is last char of temp then delete last char of temp
if number of lines of temp > 100 then delete line 101 to (number of lines of temp) of temp
put temp into cd fld "highscore"
put item 8 of line 1 of temp into gHighScore
open file scorefile
write output to file scorefile at eof
close file scorefile
set the numberformat to savenbformat
highscore category
if email ≠ "" then
if "@" is in email or "@" is in email then
createEmail output,"webmaster@guruhits.com (Joe Savelberg)","GuruHits Music Quiz","http://www.guruhits.com"
end if
end if
set itemdelimiter to comma
put item 2 of FullFind(temp,output,"m=a") into rank
if rank = "" then put "0" into rank else put rank + 1 into rank
put "<SET_LOCAL rank = " & quote & rank & quote & ">" & return after NCoutput
put "<SET_LOCAL score = " & quote & score & quote & ">" & return after NCoutput
put "<SET_LOCAL quiznb = " & quote & quiznb & quote & ">" & return after NCoutput
put "<SET_LOCAL songline = " & quote & "done" & quote & ">" & return after NCoutput
put "<SET_LOCAL level = " & quote & level & quote & ">" & return after NCoutput
put "<SET_LOCAL goodanswers = " & quote & goodanswers & quote & ">" & return after NCoutput
put "<SET_LOCAL topscore = " & quote & gHighScore & quote & ">" & return after NCoutput
put "<SET_LOCAL mystatus = " & quote & mystatus & quote & ">" & return after NCoutput
-- put "<SET_LOCAL myscore = " & quote & encrypt(firstname & "-" & lastename & "-" & email & "-" & score & "-" & quiznb & "-" & goodanswers) & quote & ">" & return after NCoutput
reply(NCoutput)
end savescore
on highscore category
global gGuruHitsDB,gDBrange,FormInformation,CustomerTCPAddress,partner
put partner & ":temphigh.score." & category into scorefile
put cd fld "highscore" into temp
set itemdelimiter to tab
put "" into output
repeat with x = 1 to the number of lines of temp
put line x of temp into theline
if x mod 2 = 0 then put "#A5CEF7" into bgcolor
else put "#E6EFFF" into bgcolor
put "<TR BGCOLOR=" & quote & bgcolor & quote && "STYLE=" & quote & "font-size: 11px ; font-family: sans-serif" & quote & ">" &¬
"<TD ALIGN=RIGHT>" & x & ".</TD>" &¬
"<TD>" & item 5 of theline && item 6 of theline & "</TD>" &¬
"<TD>" & item 11 of theline & "</TD>" &¬
"<TD ALIGN=RIGHT>" & item 13 of theline & "</TD>" &¬
"<TD ALIGN=RIGHT>" & item 10 of theline & "%</TD>" &¬
"<TD ALIGN=RIGHT>" & item 8 of theline & "</TD>" &¬
"</TR>" & return after output
end repeat
--1 date
--2 time
--3 203.0.113.5
--4 player@example.com
--5 Jochen
--6 Savelberg
--7 mov
--8 1040
--9 109
--10 95.41
--11 Junior Guru
--12 169301
--13 1
open file scorefile
write output to file scorefile
close file scorefile
end highscorePicks three random songs from the database (no repeats) — a manual test run.
on mouseUp
global gGuruHitsDB,gDBrange
put "" into cd fld output
put the ticks into myStart
put false into test
put "" into randomlist
repeat until test
get random(gDBrange)
if it is in randomlist then next repeat
put it & return after randomlist
if number of lines of randomlist = 3 then put true into test
end repeat
set itemdelimiter to tab
put line (line 1 of randomlist) of gGuruHitsDB into Choose1
put line (line 2 of randomlist) of gGuruHitsDB into Choose2
put line (line 3 of randomlist) of gGuruHitsDB into Choose3
put item 1 of line (line random(3) of randomlist) of gGuruHitsDB into Song2Play
put "<SET_LOCAL playsong = " & quote & Song2Play & quote & ">" & return after output
put "<SET_LOCAL songline = " & quote & encrypt(line 1 of randomlist & "-" & line 2 of randomlist & "-" & line 3 of randomlist) & quote & ">" & return after output
put "<SET_LOCAL ref1 = " & quote & encrypt(item 1 of Choose1) & quote & ">" & return after output
put "<SET_LOCAL artist1 = " & quote & item 2 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL song1 = " & quote & item 3 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL url1 = " & quote & item 4 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL cover1 = " & quote & item 5 of Choose1 & quote & ">" & return after output
-- put "<SET_LOCAL audio1 = " & quote & item 6 of Choose1 & quote & ">" & return after output
put "<SET_LOCAL ref2 = " & quote & encrypt(item 1 of Choose2) & quote & ">" & return after output
put "<SET_LOCAL artist2 = " & quote & item 2 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL song2 = " & quote & item 3 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL url2 = " & quote & item 4 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL cover2 = " & quote & item 5 of Choose2 & quote & ">" & return after output
-- put "<SET_LOCAL audio2 = " & quote & item 6 of Choose2 & quote & ">" & return after output
put "<SET_LOCAL ref3 = " & quote & encrypt(item 1 of Choose3) & quote & ">" & return after output
put "<SET_LOCAL artist3 = " & quote & item 2 of Choose3 & quote & ">" & return after output
put "<SET_LOCAL song3 = " & quote & item 3 of Choose3 & quote & ">" & return after output
put "<SET_LOCAL url3 = " & quote & item 4 of Choose3 & quote & ">" & return after output
put "<SET_LOCAL cover3 = " & quote & item 5 of Choose3 & quote & ">" & return after output
-- put "<SET_LOCAL audio3 = " & quote & item 6 of Choose3 & quote & ">" & return after output
put output into cd fld "output"
put the ticks - myStart into msg
end mouseUp
-- on mouseUp
-- global gGuruHitsDB,gDBrange
-- put "" into cd fld output
-- put the ticks into myStart
-- put false into test
-- put "" into randomlist
-- repeat until test
-- get random(gDBrange)
-- if it is in randomlist then next repeat
-- put it & return after randomlist
-- if number of lines of randomlist = 3 then put true into test
-- end repeat
-- set itemdelimiter to tab
-- put line (line 1 of randomlist) of gGuruHitsDB into Choose1
-- put line (line 2 of randomlist) of gGuruHitsDB into Choose2
-- put line (line 3 of randomlist) of gGuruHitsDB into Choose3
-- put item 1 of line (line random(3) of randomlist) of gGuruHitsDB into Song2Play
-- put "<SET_LOCAL playsong = " & quote & Song2Play & quote & ">" & return after output
-- put "<SET_LOCAL songline = " & quote & encrypt(line 1 of randomlist & "-" & line 2 of randomlist & "-" & line 3 of randomlist) & quote & ">" & return after output
-- put "<SET_LOCAL ref1 = " & quote & encrypt(item 1 of Choose1) & quote & ">" & return after output
-- put "<SET_LOCAL artist1 = " & quote & item 2 of Choose1 & quote & ">" & return after output
-- put "<SET_LOCAL song1 = " & quote & item 3 of Choose1 & quote & ">" & return after output
-- put "<SET_LOCAL url1 = " & quote & item 4 of Choose1 & quote & ">" & return after output
-- put "<SET_LOCAL cover1 = " & quote & item 5 of Choose1 & quote & ">" & return after output
-- -- put "<SET_LOCAL audio1 = " & quote & item 6 of Choose1 & quote & ">" & return after output
-- put "<SET_LOCAL ref2 = " & quote & encrypt(item 1 of Choose2) & quote & ">" & return after output
-- put "<SET_LOCAL artist2 = " & quote & item 2 of Choose2 & quote & ">" & return after output
-- put "<SET_LOCAL song2 = " & quote & item 3 of Choose2 & quote & ">" & return after output
-- put "<SET_LOCAL url2 = " & quote & item 4 of Choose2 & quote & ">" & return after output
-- put "<SET_LOCAL cover2 = " & quote & item 5 of Choose2 & quote & ">" & return after output
-- -- put "<SET_LOCAL audio2 = " & quote & item 6 of Choose2 & quote & ">" & return after output
-- put "<SET_LOCAL ref3 = " & quote & encrypt(item 1 of Choose3) & quote & ">" & return after output
-- put "<SET_LOCAL artist3 = " & quote & item 2 of Choose3 & quote & ">" & return after output
-- put "<SET_LOCAL song3 = " & quote & item 3 of Choose3 & quote & ">" & return after output
-- put "<SET_LOCAL url3 = " & quote & item 4 of Choose3 & quote & ">" & return after output
-- put "<SET_LOCAL cover3 = " & quote & item 5 of Choose3 & quote & ">" & return after output
-- -- put "<SET_LOCAL audio3 = " & quote & item 6 of Choose3 & quote & ">" & return after output
-- put output into cd fld "output"
-- put the ticks - myStart into msg
-- end mouseUpA test button: injects a sample quiz form and calls quizscreen.
on mouseUp
global FormInformation
put "3019" into siteid
put "songline=C08103064B183060C06903060C182D6CE09133264D1A2D60B481&firstname=Jochen&lastname=Savelberg&email=player@example.com&category=1&level=1&pi-qt=true&pi-real=true&Player=mov&submit=Set+%26+Play" into FormInformation
send quizscreen to cd id siteid
end mouseUpCollapses the card window to 50×50 (or restores it).
on mouseUp
if hilite of me then
set the height of cd window to 50
set the width of cd window to 50
else
set the height of cd window to 342
set the width of cd window to 512
end if
end mouseUpThe rank ladder: the point thresholds from Novice to Guru.
Novice 0
Fan 100
Follower 200
Music Buff 500
Junior Guru 1000
Senior Guru 2500
Vice Guru 5000
Guru 10000Working high-score buffer (tab-separated rows). Player identifiers shown here are anonymized; the live archive is never published.
22/03/2003 9:19:34 [IP_GRTF_1] [Email_GRTF_1] [Person_GRTF_1] ö[Person_GRTF_2] rpm 38280 1045 95.79 Vice Guru 414578328 4 1
6/09/2002 9:41:39 [IP_GRTF_2] [Email_GRTF_2] [Person_GRTF_3] rpm 35000 1229 85.6 Vice Guru 16273163 4 1
6/08/2002 22:08:17 [IP_GRTF_3] [Email_GRTF_3] rpm 33000 931 94.31 Vice Guru 13770742 4 1
26/02/2002 19:56:08 [IP_GRTF_4] [Email_GRTF_4] [Person_GRTF_4] au 32520 981 91.44 Vice Guru 23028721 4 1
27/04/2003 21:40:17 [IP_GRTF_5] [Email_GRTF_5] [Person_GRTF_5] rpm 30960 986 89.25 Vice Guru 602561598 4 1
2/12/2003 23:19:04 [IP_GRTF_6] [Email_GRTF_6] [Person_GRTF_6] rpm 26960 932 86.16 Vice Guru 220083783 4 1
12/05/2002 13:28:19 [IP_GRTF_7] [Email_GRTF_7] [Person_GRTF_7] au 22950 1094 69.93 Vice Guru 25923559 3 1
25/02/2003 4:46:13 [IP_GRTF_8] [Person_GRTF_8] au 19860 1041 63.59 Vice Guru 283640982 3 1
26/05/2003 15:39:25 [IP_GRTF_9] [Email_GRTF_8] [Account_GRTF_1] aif 16440 455 95.16 Senior Guru 753604411 4 1
5/11/2002 21:08:52 [IP_GRTF_10] [Person_GRTF_9] rpm 16410 605 90.41 Vice Guru 27080264 3 1
4/09/2003 17:12:04 [IP_GRTF_11] [Email_GRTF_9] [Person_GRTF_10] rpm 15980 928 86.1 Vice Guru 509632157 2 1
1/04/2002 1:48:29 [IP_GRTF_12] [Person_GRTF_11][Email_GRTF_10] [Person_GRTF_12] au 15680 540 86.3 Senior Guru 12309108 4 1
30/12/2001 21:59:33 [IP_GRTF_13] [Email_GRTF_11] [Person_GRTF_13] rpm 15520 388 100 Senior Guru 18403771 4 1
12/07/2001 9:16:50 [IP_GRTF_14] [Email_GRTF_12] [Person_GRTF_14] rpm 15320 503 88.07 Senior Guru 3614146 4 1
14/11/2001 20:40:29 [IP_GRTF_15] [Email_GRTF_13] [Person_GRTF_15] au 15200 742 75.61 Senior Guru 37502262 4 1
18/08/2002 1:00:24 [IP_GRTF_16] [Email_GRTF_14] [Person_GRTF_16] au 14000 480 86.46 Senior Guru 3505539 4 1
4/04/2003 12:08:22 [IP_GRTF_17] [Person_GRTF_17] rpm 13800 627 77.51 Senior Guru 482762224 4 1
11/10/2001 17:38:38 [IP_GRTF_18] [Email_GRTF_15] [Person_GRTF_18] rpm 13300 925 71.89 Vice Guru 16053461 2 1
28/04/2003 19:37:04 [IP_GRTF_19] [Email_GRTF_16] rpm 12520 387 90.44 Senior Guru 608917588 4 1
11/10/2001 16:51:43 [IP_GRTF_20] [Email_GRTF_17] [Person_GRTF_19] rpm 12060 825 73.09 Vice Guru 15884464 2 1The two fields on the card hold data rather than scripts: level is the rank ladder, and
highscore is the working high-score buffer. The original buffer held players' names, email
addresses and IPs, so the sample shown here has every identifier swapped for a typed placeholder
([Person_…], [Email_…], [IP_…]) — anonymized data produced with
Privatim, a privacy-first tool that detects and redacts personal information before anything is
published.
The same stack still runs today under the SheepShaver emulator:

