2 #// The bot to ketchup frames from the bsta viewer
5 #// Copyright (C) 2019 Balthasar SzczepaĆski
7 #// This program is free software: you can redistribute it and/or modify
8 #// it under the terms of the GNU Affero General Public License as
9 #// published by the Free Software Foundation, either version 3 of the
10 #// License, or (at your option) any later version.
12 #// This program is distributed in the hope that it will be useful,
13 #// but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 #// GNU Affero General Public License for more details.
17 #// You should have received a copy of the GNU Affero General Public License
18 #// along with this program. If not, see <http://www.gnu.org/licenses/>.
23 framepath="/eizm/www/time/"
24 datapath="/eizm/data/aftertime/"
25 temppath="/eizm/tmp/aftertime/"
26 passpath="/eizm/mem/aftertime/pass/"
28 bstapath="/eizm/data/bsta/"
29 bstaviewpath="/eizm/www/time/bsta/"
31 timecmd="date -u +%Y%m%d%H%s"
32 timecmd2="date -u +\"%Y-%m-%d %H:%M:%S\""
33 ongtimecmd1="date -u -d@"
34 ongtimecmd2=" +\"%Y-%m-%d %H:%M:%S\""
36 botcastleurl="http://1190.bicyclesonthemoon.info"
42 # wget="/usr/bin/wget"
43 # remap="/eizm/pro/aftertime/remapt-1"
44 npb="/eizm/pro/ong1/npb"
45 # bot4awk="/eizm/pro/aftertime/bot4.awk"
46 # uploadawk="/eizm/pro/aftertime/upload.awk"
48 timecmd2 | getline thistime2
62 gsub(/[\r\n]/, "", $0)
65 argtab[substr($0, 1, eq-1)]=substr($0, eq+1)
69 print thistime2" "argtab ["story"]
77 if(argtab["ongoing"]!="2")
79 print "Story is not externally onged."
83 framedir = "aftertime/"argtab["story"]"/"
86 statefile= datapath argtab["story"]"/ongstate"
87 getline temp < statefile
88 getline alt < statefile
91 split(temp, temptab, " ")
94 nextong=int(temptab[3])
95 ongfailcount=int(temptab[4])
99 print "Time to start onging."
100 f=int(argtab["first"])
102 else if (state==2 || state==1)
106 print "Onging not avtive."
110 bstasettingsfile = bstapath "settings"
111 bstastatefile = bstapath "state"
112 bstadefaultfile = bstapath "default"
118 timefile= datapath argtab["story"]"/ongtime"
122 bstaspecialfile = bstapath f
123 specialfile = datapath argtab["story"]"/"sprintf(argtab["special"],f)
125 for (i in bstaargtab)
128 readdatafile(bstasettingsfile,bstaargtab)
129 readdatafile(bstastatefile,bstaargtab)
130 readdatafile(bstadefaultfile,bstaargtab)
131 readdatafile(bstaspecialfile,bstaargtab)
133 # for (i in bstaargtab)
134 # print i": "bstaargtab[i]
136 if (f > int(bstaargtab["last"])) {
137 print "Wait for frame "f"."
141 print "ONG frame "f"."
143 for (i in specialtab)
148 specialtab["title"]=bstaargtab["title"]
149 # specialtab["alt"]=bstaargtab["title"]
150 specialtab["frame"]=sprintf(bstaargtab["frame"],f,bstaargtab["ext"])
151 specialtab["text"]=bstaargtab["content"]
153 inframe = bstaviewpath specialtab["frame"]
154 frame= framepath framedir specialtab["frame"]
159 text=specialtab["text"]
163 eq=match(text,/(###([^#;]*);)/)
167 text_HTML=text_HTML substr(text, 1, RSTART - 1)
168 text_BB = text_BB substr(text, 1, RSTART - 1)
169 tag = substr(text, RSTART +3, RLENGTH -4)
170 text= substr(text, RSTART + RLENGTH)
172 if (match(tag,/^fr&([0-9]+)$/))
174 id=int(substr(tag,4))
176 tag="/aftertime/frame?story="arrtab["story"]"&f="id
177 text_HTML=text_HTML tag
178 text_BB=text_BB botcastleurl tag
180 else if (match(tag,/^vw&([0-9]+)$/))
182 id=int(substr(tag,4))
184 tag="/aftertime/viewer?story="arrtab["story"]"&f="id
185 text_HTML=text_HTML tag
186 text_BB=text_BB botcastleurl tag
189 else if (match(tag,/^att&([0-9]+)$/))
191 id=int(substr(tag,5))
193 print "ONG attachment "id"."
195 attachfile=bstapath"a"id
198 readdatafile(attachfile, attachtab)
200 outfile=framepath framedir attachtab["filename"]
201 infile= bstapath attachtab["filename"]
203 cpcmd = cp" "infile" "outfile
204 chmodcmd = chmod" +r "outfile
206 if (attachtab["content"]!="")
208 printf("%s",attachtab["content"]) > outfile
211 else if(system(cpcmd)!=0)
213 print "Attachment upload failed."
217 if(system(chmodcmd)!=0)
219 print "Attachment chmod failed."
223 tag="/aftertime/"argtab["story"]"/"attachtab["filename"]
224 text_HTML=text_HTML tag
225 text_BB=text_BB botcastleurl tag
236 text_HTML = text_HTML text
237 text_BB = text_BB text
247 specialtab["HTML"]=bb2html(text_HTML)
248 specialtab["BBHTML"]=bb2bb(text_BB)
250 cpcmd = cp" "inframe" "frame
251 chmodcmd = chmod" +r "frame
253 ongtimecmd= ongtimecmd1 bstaargtab["ongtime"] ongtimecmd2
254 ongtimecmd | getline ongtime
260 print sprintf("%04u ",f)ongtime > timefile
262 print sprintf("%04u ",f)ongtime >> timefile
267 print "Frame upload failed."
271 if(system(chmodcmd)!=0)
273 print "Frame chmod failed."
279 for (i in specialtab)
282 print i"="specialtab[i] > specialfile
284 print "" > specialfile
285 if (specialtab["text"]!="")
286 printf("%s",specialtab["text"]) > specialfile
290 print sprintf("%u %u %u %u",2,f,0,0) > statefile
300 #limited compatibility with bsta data file format
301 function readdatafile (datafile, argtab, line,undertext,eq)
304 while((getline line < datafile)>0)
306 \r gsub(/[\r\n]/, "", line)
308 if (line == "" && !undertext)
315 argtab["content"] = argtab["content"] line "\n"
319 eq = match(line, /(: |=)/)
322 argtab[substr(line, 1, RSTART - 1)]=substr(line, RSTART + RLENGTH)
331 function bb2bb (text)
333 gsub(/\[(fq|tq)\]/, "[quote]", text)
334 gsub(/\[\/(fq|tq)\]/, "[/quote]", text)
335 gsub(/\[br\]/, "[color=#BB6622]", text)
336 gsub(/\[ni\]/, "[color=#0057AF]", text)
337 gsub(/\[po\]/, "[color=#FF8800]", text)
338 gsub(/\[\/(br|ni|po)\]/, "[/color]", text)
340 return htmlescape(text,"","br")
343 function bb2html(text, depth,count,bbtree,html,tag,tagstart,taglength,elm,tagv,tagname,tagvalue,matchname)
350 bbtree["0.v"]=argtab["subject"]
352 # gsub(/=/,"=",text)
353 debug = debug "\n\nBuild BBcode tree:"
354 while(length(text)!=0)
356 tag=match(text, /\[\/?[a-z0-9\*]+(=(([^\[<>\"\]]*)|(\"[^\"<>]*\")))?\]/)
360 debug = debug "\ntext: " text
361 bbtree[ind(count,depth)]=text
362 bbtree[indt(count,depth)".n"]=count[depth]
371 elm=substr(text,1,tagstart-1)
372 debug = debug "\ntext: " elm
373 bbtree[ind(count,depth)]=elm
374 bbtree[indt(count,depth)".n"]=count[depth]
377 tag=substr(text,tagstart,taglength)
378 text=substr(text,tagstart+taglength)
379 debug = debug "\ntag: " tag
385 tagname=substr(tag,2,length(tag)-2)
390 tagname=substr(tag,2,tagv-2)
391 tagvalue=substr(tag,tagv+1,length(tag)-tagv-1)
393 if(tagname !~ /^((fq)|(tq)|(ni)|(po)|(quote)|b|i|u|(code)|(img)|(url)|(size)|(color)|(center)|(right)|(sub)|(sup)|(s)|(spoiler)|(list)|(br)|(\*))$/)
395 debug = debug "\nunknown tag"
396 bbtree[ind(count,depth)]=tag
397 bbtree[indt(count,depth)".n"]=count[depth]
401 if((bbtree[indt(count,depth)".t"] == "code" && tagname!="code")||bbtree[indt(count,depth)".t"] == "img"||(bbtree[indt(count,depth)".t"] == "spoiler" && tagname=="spoiler")||(bbtree[indt(count,depth)".t"] == "size" && tagname=="size"))
403 debug = debug "\nthis tag forbidden here"
404 bbtree[ind(count,depth)]=tag
405 bbtree[indt(count,depth)".n"]=count[depth]
411 if(bbtree[indt(count,depth)".t"]==tagname)
413 debug = debug "\nimplied tag: [/"tagname"]"
414 debug = debug "\nmatched"
415 bbtree[ind(count,depth)]="[/"tagname"]"
416 bbtree[ind(count,depth)".k"]="e"
417 bbtree[ind(count,depth)".m"]=1
418 bbtree[ind(count,depth)".t"]=tagname
419 bbtree[ind(count,depth)".v"]=bbtree[indt(count,depth)".v"]
420 bbtree[indt(count,depth)".n"]=count[depth]
421 bbtree[indt(count,depth)".m"]=1
426 else if(bbtree[indt(count,depth)".t"]!="list")
428 debug = debug "\nthis tag forbidden here"
429 bbtree[ind(count,depth)]=tag
430 bbtree[indt(count,depth)".n"]=count[depth]
435 debug = debug "\nname: " tagname " value: " tagvalue
436 bbtree[ind(count,depth)]=tagname" "tagvalue
437 bbtree[ind(count,depth)".k"]="s"
438 bbtree[indt(count,depth)".n"]=count[depth]
441 bbtree[indt(count,depth)]=tag
442 bbtree[indt(count,depth)".n"]=0
443 bbtree[indt(count,depth)".t"]=tagname
444 bbtree[indt(count,depth)".v"]=tagvalue
446 # if(tagname=="br") #or other single tags in the future
448 # debug = debug "\nmatched"
449 # bbtree[ind(count,depth)]=tag
450 # bbtree[ind(count,depth)".k"]="e"
451 # bbtree[ind(count,depth)".m"]=1
452 # bbtree[ind(count,depth)".t"]=tagname
453 # bbtree[ind(count,depth)".v"]=bbtree[indt(count,depth)".v"]
454 # bbtree[indt(count,depth)".n"]=count[depth]
455 # bbtree[indt(count,depth)".m"]=1
465 debug = debug "\n""unmatched"
466 bbtree[ind(count,depth)]=tag
467 bbtree[indt(count,depth)".n"]=count[depth]
471 tagname=substr(tag,3,length(tag)-3)
472 if(tagname=="list"&&bbtree[indt(count,depth)".t"]=="*")
474 debug = debug "\nimplied tag: [/*]"
475 debug = debug "\nmatched"
476 bbtree[ind(count,depth)]="[/*]"
477 bbtree[ind(count,depth)".k"]="e"
478 bbtree[ind(count,depth)".m"]=1
479 bbtree[ind(count,depth)".t"]="*"
480 bbtree[ind(count,depth)".v"]=bbtree[indt(count,depth)".v"]
481 bbtree[indt(count,depth)".n"]=count[depth]
482 bbtree[indt(count,depth)".m"]=1
487 debug = debug "\nname: " tagname
488 matchname=bbtree[indt(count,depth)".t"]
489 if((bbtree[indt(count,depth)".t"] == "code" && tagname!="code")||(bbtree[indt(count,depth)".t"] == "img" && tagname != "img"))
491 debug = debug "\nthis tag forbidden here"
492 bbtree[ind(count,depth)]=tag
493 bbtree[indt(count,depth)".n"]=count[depth]
497 if(tagname!=matchname)
499 debug = debug "\nmismatched: " matchname
500 # bbtree[ind(count,depth)]=tag
501 # bbtree[indt(count,depth)".n"]=count[depth]
504 bbtree[ind(count,depth)]=tag
505 bbtree[ind(count,depth)".k"]="e"
506 bbtree[ind(count,depth)".t"]=bbtree[indt(count,depth)".t"]
507 bbtree[ind(count,depth)".v"]=bbtree[indt(count,depth)".v"]
508 bbtree[indt(count,depth)".n"]=count[depth]
514 debug = debug "\nmatched"
515 bbtree[ind(count,depth)]=tag
516 bbtree[ind(count,depth)".k"]="e"
517 bbtree[ind(count,depth)".m"]=1
518 bbtree[ind(count,depth)".t"]=tagname
519 bbtree[ind(count,depth)".v"]=bbtree[indt(count,depth)".v"]
520 bbtree[indt(count,depth)".n"]=count[depth]
521 bbtree[indt(count,depth)".m"]=1
528 debug = debug "\nunclosed tags: " depth
530 debug = debug "\n\n""generate HTML:"
533 while(count[0]<=bbtree["0.n"]&&depth>=0)
537 tag=bbtree[indt(count,depth)]
538 tagname=bbtree[indt(count,depth)".t"]
539 tagvalue=bbtree[indt(count,depth)".v"]
540 debug = debug "\nname: "tagname" value: "tagvalue" elements: "bbtree[indt(count,depth)".n"]
541 if(tagname == "post")
544 else if(bbtree[indt(count,depth)".m"]=="")
546 debug = debug "\nunmatched"
547 html = html htmlescape(tag)
549 else if(tagname == "quote")
553 html = html "<blockquote class=\"pq\"><div>"
557 if(tagvalue !~ /^\".*\"$/)
559 tagvalue="You forgot about the quote marks, "htmlescape(tagvalue)
561 tagvalue=bb2html(substr(tagvalue,2,length(tagvalue)-2))
562 html = html "<blockquote class=\"pq\"><div><cite class=\"pq\"><b class=\"br\">"tagvalue"</b> wrote:</cite><br>"
565 else if (tagname == "fq")
567 html = html"<div class=\"fq\">"
569 html=html"This tag shouldn't have any value. "
571 else if (tagname == "tq")
573 html = html"<div class=\"tq\">"
575 html=html"This tag shouldn't have any value. "
577 else if (tagname == "br")
579 html = html"<span class=\"br\">"
581 html=html"This tag shouldn't have any value. "
583 else if (tagname == "ni")
585 html = html"<span class=\"ni\">"
587 html=html"This tag shouldn't have any value. "
589 else if (tagname == "po")
591 html = html"<span class=\"po\">"
593 html=html"This tag shouldn't have any value. "
595 else if (tagname == "b")
597 html = html"<span style=\"font-weight: bold\">"
599 html=html"This tag shouldn't have any value. "
601 else if (tagname == "i")
603 html = html"<span style=\"font-style: italic\">"
605 html=html"This tag shouldn't have any value. "
607 else if (tagname == "u")
609 html = html"<span style=\"text-decoration: underline\">"
611 html=html"This tag shouldn't have any value. "
613 else if (tagname == "code")
615 if(bbtree[indtu(count,depth)".t"] == "code")
617 html=html htmlescape(tag)
618 debug = debug "\nnot a tag, actually"
622 html=html"<dl class=\"pq\"><dt class=\"pq\">Code: <a href=\"#\" onclick=\"selectCode(this); return false;\">Select all</a></dt><dd><code class=\"pq\">"
624 html=html"This tag shouldn't have any value. "
627 else if (tagname == "img")
628 html=html"<img src=\""
629 else if (tagname == "url")
634 tagvalue=bbtree[ind(count,depth)]
636 debug = debug "\nimplied value: " tagvalue
638 html=html"<a href=\""htmlescape(tagvalue)"\" class=\"postlink\">"
640 else if (tagname == "size")
642 if (tagvalue==""||(tagvalue !~ /^[0-9]+$/)||(tagvalue+0)>200)
643 html=html"<span style=\"font-size: 130%; line-height: 116%;\"> This tag should have a correct value. "
645 html=html"<span style=\"font-size: "htmlescape(tagvalue)"%; line-height: 116%;\">"
647 else if (tagname == "color")
649 if (tagvalue==""||tagvalue !~ /^#[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F]$/) #for some reason /^([0-9A-F]{6})$/ doesn't work.
650 html=html"<span style=\"color: #EE0000\"> This tag should have a correct value. "
652 html=html"<span style=\"color: "htmlescape(tagvalue)"\">"
654 else if (tagname ~ /^((center)|(right))$/)
656 html=html"<div align=\""tagname"\">"
658 html=html"This tag shouldn't have any value. "
660 else if (tagname =="s")
664 html=html"This tag shouldn't have any value. "
666 else if (tagname =="sub")
670 html=html"This tag shouldn't have any value. "
672 else if (tagname =="sup")
676 html=html"This tag shouldn't have any value. "
678 else if (tagname=="spoiler")
680 html=html"<div style=\"margin:20px; margin-top:5px\"><div class=\"quotetitle\"><b>Spoiler:</b> <input type=\"button\" class=\"pk\" value=\"Show\" style=\"width:45px;font-size:10px;margin:0px;padding:0px;\" onclick=\"if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = ''; this.innerText = ''; this.value = 'Hide'; } else { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none'; this.innerText = ''; this.value = 'Show'; }\" /></div><div class=\"quotecontent\"><div style=\"display: none;\">"
682 html=html"This tag shouldn't have any value. "
684 else if (tagname=="list")
692 else if (tagvalue=="i")
693 tagvalue="lower-roman"
694 else if (tagvalue=="I")
695 tagvalue="upper-roman"
696 else if (tagvalue=="a")
697 tagvalue="lower-alpha"
698 else if (tagvalue=="A")
699 tagvalue="upper-alpha"
702 html=html"This tag should have a correct value. "
705 html=html"<ol style=\"list-style-type: "tagvalue"\">"
708 else if (tagname=="*")
712 html=html"This tag shouldn't have any value. "
714 # else if (tagname == "br")
718 # html=html"This tag shouldn't have any value. "
722 debug = debug "\nunknown tag"
723 html = html htmlescape(tag)
727 else if(bbtree[ind(count,depth)".k"]=="s")
729 debug = debug "\nentering tag:"
733 else if(bbtree[ind(count,depth)".k"]=="e")
735 debug = debug "\nleaving tag:"
736 tag=bbtree[ind(count,depth)]
737 tagname=bbtree[ind(count,depth)".t"]
738 tagvalue=bbtree[ind(count,depth)".v"]
739 debug = debug "\nname: "tagname" value: "tagvalue
740 if (tagname == "post")
743 else if(bbtree[ind(count,depth)".m"]=="")
745 debug = debug "\nunmatched"
746 html = html htmlescape(tag)
748 else if(tagname == "quote")
749 html = html "</div></blockquote>"
750 else if (tagname ~/^(b|i|u|(size)|(color)|(br)|(ni)|(po))$/)
752 else if (tagname == "code")
754 if(bbtree[indtu(count,depth)".t"] == "code")
756 html=html htmlescape(tag)
757 debug = debug "\nnot a tag, actually"
760 html = html"</code></dd></dl>"
762 else if (tagname == "img")
764 html = html"\" alt=\"Image\" />"
766 html=html"This tag shouldn't have any value. "
768 else if(tagname=="url")
770 else if (tagname ~ /^((center)|(right)|(fq)|(tq))$/)
772 else if (tagname =="s")
774 else if (tagname =="sub")
776 else if (tagname =="sup")
778 else if (tagname=="spoiler")
779 html=html"</div></div></div>"
780 else if (tagname=="list")
787 else if (tagname=="*")
789 # else if (tagname == "br") #
795 debug = debug "\nunknown tag"
796 html = html htmlescape(tag)
802 else if(count[depth]>bbtree[indt(count,depth)".n"])
804 debug = debug "\nrun out of elements in this tag; leaving"
811 tag=bbtree[ind(count,depth)]
812 debug = debug "\ntext: "tag
814 tag=htmlescape(tag,"","br")
816 if(bbtree[indt(count,depth)".t"] == "code")
818 gsub(/ /,"\\ ",tag)
819 gsub(/\t/,"\\ \\ ",tag)
822 gsub(/ /,"\\ ",tag)
823 gsub(/ /," \\ ",tag)
824 # gsub(/<br> /,"<br>\\ ",tag)
828 if(nourl==""&& bbtree[indt(count,depth)".t"] !~ /^((code)|(img)|(url))$/)
829 gsub(/https?:\/\/[^\n\r\t<> ]+/,"<a href=\"&\" class=\"postlink\">&</a>",tag)
830 # if(nosmil=="" && bbtree[indt(count,depth)".t"] !~ /^((code)|(img))$/)
832 # gsub(/(^|[\n\r\t ]):D($|[\n\r\t ])/," <img title=\"Very Happy\" alt=\":D\" src=\"http://forums.xkcd.com/images/smilies/icon_biggrin.gif\" /> ",tag)
833 # gsub(/(^|[\n\r\t ]):\)($|[\n\r\t ])/," <img title=\"Smile\" alt=\":)\" src=\"http://forums.xkcd.com/images/smilies/icon_smile.gif\" /> ",tag)
834 # gsub(/(^|[\n\r\t ]):\(($|[\n\r\t ])/," <img title=\"Sad\" alt=\":(\" src=\"http://forums.xkcd.com/images/smilies/icon_sad.gif\" /> ",tag)
835 # gsub(/(^|[\n\r\t ]):o($|[\n\r\t ])/," <img title=\"Surprised\" alt=\":o\" src=\"http://forums.xkcd.com/images/smilies/icon_surprised.gif\" /> ",tag)
836 # gsub(/(^|[\n\r\t ]):shock:($|[\n\r\t ])/," <img title=\"Shocked\" alt=\":shock:\" src=\"http://forums.xkcd.com/images/smilies/icon_eek.gif\" /> ",tag)
837 # gsub(/(^|[\n\r\t ]):\?($|[\n\r\t ])/," <img title=\"Confused\" alt=\":?\" src=\"http://forums.xkcd.com/images/smilies/icon_confused.gif\" /> ",tag)
838 # gsub(/(^|[\n\r\t ])8-\)($|[\n\r\t ])/," <img title=\"Cool\" alt=\"8-)\" src=\"http://forums.xkcd.com/images/smilies/icon_cool.gif\" /> ",tag)
839 # gsub(/(^|[\n\r\t ]):lol:($|[\n\r\t ])/," <img title=\"Laughing\" alt=\":lol:\" src=\"http://forums.xkcd.com/images/smilies/icon_lol.gif\" /> ",tag)
840 # gsub(/(^|[\n\r\t ]):x($|[\n\r\t ])/," <img title=\"Mad\" alt=\":x\" src=\"http://forums.xkcd.com/images/smilies/icon_mad.gif\" /> ",tag)
841 # gsub(/(^|[\n\r\t ]):P($|[\n\r\t ])/," <img title=\"Razz\" alt=\":P\" src=\"http://forums.xkcd.com/images/smilies/icon_razz.gif\" /> ",tag)
842 # gsub(/(^|[\n\r\t ]):oops:($|[\n\r\t ])/," <img title=\"Embarassed\" alt=\":oops:\" src=\"http://forums.xkcd.com/images/smilies/icon_redface.gif\" /> ",tag)
843 # gsub(/(^|[\n\r\t ]):cry:($|[\n\r\t ])/," <img title=\"Crying or Very Sad\" alt=\":cry:\" src=\"http://forums.xkcd.com/images/smilies/icon_cry.gif\" /> ",tag)
844 # gsub(/(^|[\n\r\t ]):evil:($|[\n\r\t ])/," <img title=\"Evil or Very Mad\" alt=\":evil:\" src=\"http://forums.xkcd.com/images/smilies/icon_evil.gif\" /> ",tag)
845 # gsub(/(^|[\n\r\t ]):twisted:($|[\n\r\t ])/," <img title=\"Twisted Evil\" alt=\":twisted:\" src=\"http://forums.xkcd.com/images/smilies/icon_twisted.gif\" /> ",tag)
846 # gsub(/(^|[\n\r\t ]):roll:($|[\n\r\t ])/," <img title=\"Rolling Eyes\" alt=\":roll:\" src=\"http://forums.xkcd.com/images/smilies/icon_rolleyes.gif\" /> ",tag)
847 # gsub(/(^|[\n\r\t ]):wink:($|[\n\r\t ])/," <img title=\"Wink\" alt=\":wink:\" src=\"http://forums.xkcd.com/images/smilies/icon_wink.gif\" /> ",tag)
848 # gsub(/(^|[\n\r\t ]);\)($|[\n\r\t ])/," <img title=\"Wink\" alt=\":wink:\" src=\"http://forums.xkcd.com/images/smilies/icon_wink.gif\" /> ",tag)
849 # gsub(/(^|[\n\r\t ]):!:($|[\n\r\t ])/," <img title=\"Exclamation\" alt=\":!:\" src=\"http://forums.xkcd.com/images/smilies/icon_exclaim.gif\" /> ",tag)
850 # gsub(/(^|[\n\r\t ]):\?:($|[\n\r\t ])/," <img title=\"Question\" alt=\":?:\" src=\"http://forums.xkcd.com/images/smilies/icon_question.gif\" /> ",tag)
851 # gsub(/(^|[\n\r\t ]):idea:($|[\n\r\t ])/," <img title=\"Idea\" alt=\":idea:\" src=\"http://forums.xkcd.com/images/smilies/icon_idea.gif\" /> ",tag)
852 # gsub(/(^|[\n\r\t ]):arrow:($|[\n\r\t ])/," <img title=\"Arrow\" alt=\":arrow:\" src=\"http://forums.xkcd.com/images/smilies/icon_arrow.gif\" /> ",tag)
853 # gsub(/(^|[\n\r\t ]):\|($|[\n\r\t ])/," <img title=\"Neutral\" alt=\":|\" src=\"http://forums.xkcd.com/images/smilies/icon_neutral.gif\" /> ",tag)
854 # gsub(/(^|[\n\r\t ]):mrgreen:($|[\n\r\t ])/," <img title=\"Mr. Green\" alt=\":mrgreen:\" src=\"http://forums.xkcd.com/images/smilies/icon_mrgreen.gif\" /> ",tag)
861 debug = debug "\ndone\n"
865 function ind(count,depth, ii,iindex)
868 for(ii=0;ii<=depth;++ii)
872 iindex = iindex count[ii]
874 # debug = debug "\n" iindex
877 function indt(count,depth, ii,iindex)
880 for(ii=0;ii<depth;++ii)
884 iindex = iindex count[ii]
889 # debug = debug "\n" iindex
892 function indtu(count,depth, ii,iindex)
895 for(ii=0;ii<depth-1;++ii)
899 iindex = iindex count[ii]
904 # debug = debug "\n" iindex
907 function htmlescape(name,less,br, len,iii,escaped,ch)
911 for(iii=1;iii<=len;++iii)
913 ch=substr(name,iii,1);
915 escaped = escaped ((br!="")?"<br>":"&#"ch2dec[ch]";")
917 escaped = escaped ((br!="")?"":"&#"ch2dec[ch]";")
918 else if(ch == "\"" && less=="")
919 escaped = escaped "&#"ch2dec[ch]";"
920 else if(ch ~ /[=<>&]/)
921 escaped = escaped "&#"ch2dec[ch]";"
927 function hexencode(name, len,iii,escaped,ch)
931 for(iii=1;iii<=len;++iii)
933 ch=substr(name,iii,1)
934 escaped = escaped ch2hex[ch]