;"HyperMOO 1.0 by Matthew Campbell (mattcamp@feist.com)" ;"Copyright 1998 by Matthew Campbell" ;"You may freely use, distribute, and modify this code, as long as this copyrig ht notice and permission statement are preserved. It is also requested, but no t required, that you let Matt know you are using this code, and it would be gre atly appreciated if you contribute any ideas or modifications you have for this server." @create $generic_utils named HTML utilities,htmlu @prop #0.html_utils ;$html_utils = player:my_match_object("htmlu") @prop $html_utils."dtd" {} rc ;;$html_utils.("dtd") = {"-//W3C//DTD HTML 4.0 Transitional//EN", "http://www.w 3.org/TR/REC-html40/loose.dtd"} @prop $html_utils."generator" "HyperMOO/1.0" rc @prop $html_utils."footer" {} rc @prop $html_utils."body_attr_names" {} rc ;;$html_utils.("body_attr_names") = {"background", "bgcolor", "text", "link", " vlink", "alink"} ;;$html_utils.("aliases") = {"HTML utilities"} @chmod $html_utils r @verb $html_utils:"maketag" this none this @program $html_utils:maketag {element, attributes, ?content = 0} = args; starttag = tostr("<", $string_utils:uppercase(element)); for attr in (attributes) {name, value} = attr; value = tostr(value); starttag = tostr(starttag, " ", $string_utils:lowercase(name), "=\"", value, "\""); endfor starttag = tostr(starttag, ">"); $command_utils:suspend_if_needed(0); if (content == 0) "No ending tag, might as well return what we've got now."; return starttag; else endtag = tostr(""); if (typeof(content) == LIST) return {starttag, @content, endtag}; else return tostr(starttag, content, endtag); endif endif . @verb $html_utils:"dtd" this none this @program $html_utils:dtd return {tostr("")}; . @verb $html_utils:"make_document" this none this @program $html_utils:make_document {body_content, head_content, ?body_attrs = {}} = args; body_content = {@body_content, @this:footer()}; out = this:dtd(); head = this:maketag("head", {}, head_content); body = this:maketag("body", body_attrs, $list_utils:flatten(body_content)); out = {@out, @this:maketag("html", {{"lang", $www_utils.lang}}, {@head, @body}) }; return out; . @verb $html_utils:"head_content" this none this @program $html_utils:head_content {title, ?extra_metas = {}, ?links = {}, ?rlinks = {}} = args; out = {this:maketag("title", {}, this:fixtext(title))}; metas = {{"Content-Type", $www_utils:content_type()}, {"GENERATOR", tostr(this. generator, " [", $network.MOO_name, "]")}}; "More as the need arises."; for meta in (extra_metas) if (i = $list_utils:iassoc(meta[1], metas)) metas[i] = meta; else metas = {@metas, meta}; endif endfor headstuff = {{"meta", metas}, {"link", links}, {"rlink", rlinks}}; for type in (headstuff) for thing in (type[2]) out = {@out, this:(type[1])(@thing)}; endfor endfor return out; . @verb $html_utils:"meta" this none this @program $html_utils:meta {name, content} = args; return this:maketag("meta", {{"name", name}, {"content", content}}); . @verb $html_utils:"fixtext" this none this @program $html_utils:fixtext {text} = args; if (typeof(text) == LIST) for i in [1..length(text)] text[i] = this:fixtext(text[i]); endfor else text = strsub(text, "&", "&"); text = strsub(text, "<", "<"); text = strsub(text, ">", ">"); endif return text; . @verb $html_utils:"h1 h2 h3 h4 h5 h6 p em strong address li kbd samp var" this none this @program $html_utils:h1 {content, ?attributes = {}} = args; return this:maketag(verb, attributes, content); . @verb $html_utils:"moo2html" this none this @program $html_utils:moo2html {text} = args; out = {}; if (typeof(text) != LIST) text = {text}; endif text = this:fixtext(text); hasblanks = 0; "Attempt to guess the author's style so we know where to put P tags and where t o put BR tags."; for line in (text) if (!$string_utils:trim(line)) hasblanks = 1; break; endif endfor if (hasblanks) paragraph = {}; for i in [1..length(text)] line = text[i]; if ($string_utils:trim(line)) paragraph = {@paragraph, line}; endif if (paragraph && ((!$string_utils:trim(line)) || (i == length(text)))) for j in [1..length(paragraph) - 1] paragraph[j] = tostr(paragraph[j], this:br()); endfor out = {@out, this:p((length(paragraph) == 1) ? paragraph[1] | paragraph)} ; paragraph = {}; endif endfor else for line in (text) out = {@out, this:p(line)}; endfor endif return $list_utils:flatten(out); . @verb $html_utils:"br hr" this none this @program $html_utils:br return this:maketag(verb, {}); . @verb $html_utils:"a" this none this @program $html_utils:a {href, text} = args; return this:maketag("a", {{"href", href}}, text); . @verb $html_utils:"ul ol" this none this @program $html_utils:ul {items, ?attributes = {}} = args; itemlines = {}; for item in (items) itemlines = {@itemlines, this:li(item)}; endfor return this:maketag(verb, attributes, itemlines); . @verb $html_utils:"objlink" this none this @program $html_utils:objlink {object, ?linktext = this:fixtext(object.name)} = args; if (object:allow_objlink()) return this:a($www_utils:objurl(object), linktext); else return linktext; endif . @verb $html_utils:"title_list*c list_title*c" this none this rxd #36 @program $html_utils:title_listc "wr_utils:title_list/title_listc([, @)"; "Creates an english list out of the titles of the objects in . Optio nal are passed on to $string_utils:english_list."; "title_listc uses :titlec() for the first item."; titles = $list_utils:map_verb(args[1], "title"); if (verb[length(verb)] == "c") if (titles) titles[1] = args[1][1]:titlec(); elseif (length(args) > 1) args[2] = $string_utils:capitalize(args[2]); else args = listappend(args, "Nothing"); endif endif for i in [1..length(titles)] titles[i] = this:objlink(args[1][i], this:fixtext(titles[i])); endfor return $string_utils:english_list(titles, @args[2..length(args)]); . @verb $html_utils:"img" this none this @program $html_utils:img {src, alt, ?align = "", ?width = 0, ?height = 0, ?extra_attrs = {}} = args; attrs = {{"src", src}, {"alt", alt}}; if (align) attrs = {@attrs, {"align", align}}; endif if (width) attrs = {@attrs, {"width", width}}; endif if (height) attrs = {@attrs, {"height", height}}; endif attrs = {@attrs, @extra_attrs}; return this:maketag(verb, attrs); . @verb $html_utils:"footer" this none this @program $html_utils:footer "Currently just returns pre-written HTML, but I'm adding this verb to provide f or the possibility of on-the-fly footer creation in the future."; return this.(verb); . @verb $html_utils:"link rlink" this none this @program $html_utils:link {rel, href, ?extra_attrs = {}} = args; if (verb[1] == "r") attrs = {{"rev", rel}}; else attrs = {{"rel", rel}}; endif attrs = {@attrs, {"href", href}}; attrs = {@attrs, @extra_attrs}; return this:maketag("link", attrs); . @create $root_class named HTTP Server,httpd @prop #0.httpd ;$httpd = player:my_match_object("httpd") @prop $httpd."error_404" {} rc ;;$httpd.("error_404") = {"Not Found", "The information you requested cannot be found on this server."} @prop $httpd."supported_methods" {} rc ;;$httpd.("supported_methods") = {"GET"} @prop $httpd."server_name" "HyperMOO/1.0" rc @prop $httpd."http_version" "HTTP/1.0" rc @prop $httpd."names" #-1 rc @prop $httpd."error_400" {} rc ;;$httpd.("error_400") = {"Bad Request", "Your browser has sent a message which this server cannot understand. Please contact a MOO administrator."} @prop $httpd."redirector" #-1 rc @prop $httpd."offmoo_home_url" "" rc @prop $httpd."errors_to" #-1 rc ;$httpd.errors_to = player @prop $httpd."port" 8000 rc @prop $httpd."has_static_ip" 0 rc @prop $httpd."error_403" {} rc ;;$httpd.("error_403") = {"Forbidden", "You do not have permission to access th e information you requested."} ;;$httpd.("aliases") = {"HTTP Server"} @chmod $Httpd r @verb $httpd:"error" this none this @program $httpd:error if (!caller_perms().wizard) return E_PERM; endif {number} = args; errdata = this.(tostr("error_", number)); errtitle = errdata[1]; errbody = {$html_utils:h1(errtitle), $html_utils:p(errdata[2])}; doc = $html_utils:make_document(errbody, $html_utils:head_content(errtitle)); status = tostr(number, " ", errtitle); return {doc, status}; . @verb $httpd:"do_login_command" this none this @program $httpd:do_login_command try set_connection_option(player, "hold-input", 1); cmdline = read(player); if (!cmdline) this:errsend(400); endif cmdparts = $string_utils:words(cmdline); method = cmdparts[1]; args = cmdparts[2..$]; if (method in this.supported_methods) this:(method)(@args); else this:errsend(400); endif except e (ANY) this:handle_tb(@e); endtry . @verb $httpd:"send" this none this @program $httpd:send if (!caller_perms().wizard) return E_PERM; endif {doc, ?status = "200 OK", ?extra_headers = {}} = args; headers = {{"Content-length", $www_utils:content_length(doc)}, @extra_headers}; out = {@this:headers_to_send(status, headers), @doc}; for line in (out) notify(player, line); endfor suspend(0); boot_player(player); . @verb $httpd:"GET" this none this @program $httpd:GET if (caller != this) return E_PERM; elseif (!args) this:errsend(400); return; endif {url, @junk} = args; {object, url} = $www_utils:parse_url(url); if (!valid(object)) this:errsend(404); else this:send(@object:http_request(url)); endif . @verb $httpd:"headers_to_send" this none this @program $httpd:headers_to_send {status, ?extra_headers = {}} = args; out = {tostr(this.http_version, " ", status)}; headers = {{"Server", tostr(this.server_name, " [", $network.MOO_name, "]")}, { "Content-Type", $www_utils:content_type()}}; for header in (extra_headers) if (i = $list_utils:iassoc(header[1], headers)) "replace the header"; headers[i] = header; else headers = {@headers, header}; endif endfor for header in (headers) out = {@out, tostr(header[1], ": ", header[2])}; endfor return {@out, ""}; . @verb $httpd:"errsend" this none this @program $httpd:errsend set_task_perms(caller_perms()); this:send(@this:error(@args)); . @program $httpd:handle_tb {error, message, value, stack} = args; formatted = $code_utils:traceback(error, message, value, stack); body = {$html_utils:h1("Server Error")}; body = {@body, $html_utils:p("An error occurred while trying to send the page y ou requested. It has been reported to an administrator.")}; for line in (formatted) body = {@body, tostr(line, $html_utils:br())}; endfor fork (0) $mail_agent:send_message(this, this.errors_to, "Traceback report", formatted) ; endfork doc = $html_utils:make_document(body, $html_utils:head_content("Server Error")) ; this:send(doc, 500); return 1; . @verb $httpd:"start" this none this @program $httpd:start set_task_perms(caller_perms()); listen(this, this.port); . @verb $httpd:"url_prefix" this none this @program $httpd:url_prefix if (this.has_static_ip) return tostr("http://", $network.site, ":", this.port); else "We don't know the address, return empty string."; return ""; endif . @create $root_class named Generic Web-Enabled Object,webroot @prop #0.webroot ;$webroot = player:my_match_object("webroot") @prop $webroot."img_url" "" rc @prop $webroot."img_desc" "" rc @prop $webroot."img_width" "" rc @prop $webroot."img_height" "" rc @prop $webroot."www_background" "" rc @prop $webroot."www_bgcolor" "" rc @prop $webroot."www_text" "" rc @prop $webroot."www_link" "" rc @prop $webroot."www_vlink" "" rc @prop $webroot."www_alink" "" rc ;;$webroot.("aliases") = {"Generic Web-Enabled Object"} @chmod $webroot rf @verb $webroot:"html_description" this none this @program $webroot:html_description desc = this:description(); desc = desc ? desc | "You see nothing special."; return $html_utils:moo2html(desc); . @verb $webroot:"html_body" this none this @program $webroot:html_body out = {$html_utils:h1(this:title())}; if (this.img_url) out = {@out, $html_utils:img(this.img_url, tostr("[", this.img_desc, "]"), "r ight", this.img_width, this.img_height)}; endif out = {@out, this:html_description()}; if (!$object_utils:isa(this, $room) && valid(this.location)) out = {@out, $html_utils:p(tostr($gender_utils:pronoun_sub("%{:He} %{!is} in ", this), $html_utils:objlink(this.location), "."))}; endif return $list_utils:flatten(out); . @verb $webroot:"html_head" this none this @program $webroot:html_head return $html_utils:head_content(tostr($network.MOO_name, ": ", this:title())); . @verb $webroot:"html" this none this @program $webroot:html return $html_utils:make_document(this:html_body(@args), this:html_head(@args), this:html_body_attributes()); . @verb $webroot:"http_request" this none this @program $webroot:http_request {url} = args; return {this:html(url)}; . @verb $webroot:"html_body_attributes" this none this @program $webroot:html_body_attributes attrs = {}; for attr in ($html_utils.body_attr_names) if (value = this.(tostr("www_", attr))) attrs = {@attrs, {attr, value}}; endif endfor return attrs; . @verb $webroot:"@setimage @set-image" this none none @program $webroot:@setimage player:tell("Please enter the URL (Web address) of the image you want to place on the Web page for this object. To cancel this command, or if you want to rem ove an image that you have already set, just press Enter."); url = $command_utils:read("the URL"); if (!url) if (this.img_url) player:tell("Image removed."); else player:tell("Command canceled."); endif for prop in ({"img_url", "img_desc", "img_width", "img_height"}) clear_property(this, prop); endfor return; endif desc = ""; while (!$string_utils:trim(desc)) player:tell("Some people cannot view images, and some choose not to in order to save time while browsing the Web. For this reason, you need to enter a shor t description for this image."); desc = $command_utils:read("the description"); endwhile this.img_url = url; this.img_desc = desc; clear_property(this, "img_width"); clear_property(this, "img_height"); player:tell("You can also specify the width and height of the image, so that th e text of the object's web page will appear sooner, even if the image hasn't lo aded yet. You should be able to find the image's width and height by using a g raphics program, such as Paint Shop Pro, or by opening the image in your browse r and looking at its properties. If you are not sure how to do this, skip this step; you can ask a more experienced user or administrator for help and then r eset the image, including its width and height, later."); if ($command_utils:yes_or_no("Do you want to specify the image's width and heig ht?")) results = {}; for thing in ({"width", "height"}) done = 0; while (!done) player:tell("Enter the ", thing, " of this image, or press Enter to quit this procedure."); answer = $command_utils:read(tostr("the ", thing)); if (!answer) num_ans = 0; done = 1; elseif (!$string_utils:is_numeric(answer)) player:tell("You must enter a number."); else num_ans = toint(answer); done = 1; endif endwhile results = {@results, num_ans}; endfor {width, height} = results; if (width && height) this.img_width = width; this.img_height = height; endif endif player:tell("Image set."); . @verb $webroot:"@set-www-background" this none none rxd @program $webroot:@set-www-background player:tell("Enter the URL (Web address) of the background image you wish to ad d to this object's Web page. If you don't want a background image, just press Enter."); url = $command_utils:read("the URL"); if (!url) if (this.www_background) player:tell("Background image removed."); else player:tell("Command canceled."); endif this.www_background = ""; else player:tell("Background image set."); endif this.www_background = url; . @verb $webroot:"@set-www-colors" this none none rxd @program $webroot:@set-www-colors color_types = {{"bgcolor", "background"}, {"text", "text"}, {"link", "link"}, { "vlink", "visited link"}, {"alink", "active link"}}; colors = {}; clearall = 0; for type in (color_types) inputdesc = tostr("the ", type[2], " color"); player:tell("Please enter ", inputdesc, ", or if you want to reset all the co lors to the normal settings, just press Enter."); color = $command_utils:read(inputdesc); if (!color) clearall = 1; break; else colors = {@colors, {type[1], color}}; endif endfor for type in ($list_utils:slice(color_types, 1)) propname = tostr("www_", type); if (clearall) this.(propname) = ""; else i = $list_utils:iassoc(type, colors); this.(propname) = colors[i][2]; endif endfor player:tell("Colors ", clearall ? "cleared." | "set."); . @verb $webroot:allow_objlink tnt @program $webroot:allow_objlink "Some objects, such as locked rooms, should not be findable on the Web. That's why I am writing this verb."; return 1; . @create $generic_utils named WWW Utilities,wwwu @prop #0.www_utils ;$www_utils = player:my_match_object("wwwu") @prop $www_utils."lang" "en" rc @prop $www_utils."charset" "iso-8859-1" rc @prop $www_utils."other_valid_url_chars" ".-_" rc @prop $www_utils."newline_chars" 2 rc ;;$www_utils.("aliases") = {"WWW Utilities"} @chmod $www_utils r @verb $www_utils:"content_type" this none this @program $www_utils:content_type return tostr("text/html; charset=", this.charset); . @verb $www_utils:"parse_cgi_args" this none this @program $www_utils:parse_cgi_args {url} = args; if (!(cgistr = this:extract_cgi_args(url))) return {}; endif argstrs = $string_utils:explode(cgistr[2..$], "&"); cgiargs = {}; for argstr in (argstrs) if (i = index(argstr, "=")) cgiarg = {argstr[1..i - 1], argstr[i + 1..$]}; else cgiarg = {argstr}; endif for i in [1..length(cgiarg)] cgiarg[i] = this:decode_from_url(cgiarg[i]); endfor cgiargs = {@cgiargs, cgiarg}; endfor return cgiargs; . @verb $www_utils:"encode_cgi_args" this none this @program $www_utils:encode_cgi_args {cgiargs} = args; if (!cgiargs) return ""; endif cgistr = "?"; for a in [1..length(cgiargs)] cgiarg = cgiargs[a]; for i in [1..length(cgiarg)] cgiarg[i] = this:encode_for_url(cgiarg[i]); endfor cgistr = tostr(cgistr, cgiarg[1]); if (length(cgiarg) > 1) cgistr = tostr(cgistr, "=", cgiarg[2]); endif if (a != length(cgiargs)) cgistr = tostr(cgistr, "&"); endif endfor return cgistr; . @verb $www_utils:"objurl" this none this @program $www_utils:objurl "Essentially the reverse of :parse_url. Attempts to arrive at the URL a lazy p erson would type, to keep the number of redirects down (since each one causes a pause in Lynx, for one thing), while allowing for best use of cached pages."; {object} = args; for prop in ($object_utils:all_properties($httpd.names)) if ($httpd.names.(prop) == object) return tostr("/", this:encode_for_url($string_utils:lowercase(prop))); endif endfor if (is_player(object) && $object_utils:isa(object, $player)) shortest = object.name; for alias in (object.aliases) if (length(alias) < length(shortest)) shortest = alias; endif endfor return tostr("/~", this:encode_for_url($string_utils:lowercase(shortest))); endif return tostr("/", tonum(object)); . @verb $www_utils:"extract_cgi_args" this none this @program $www_utils:extract_cgi_args {url} = args; if (!(i = index(url, "?"))) return ""; else return url[i..$]; endif . @verb $www_utils:"parse_url" this none this @program $www_utils:parse_url {url} = args; if (url[1] != "/") url = "/" + url; endif if (!index(url, "?") && url[$] == "/") "I often put a slash at the end of any URL that doesn't have a conventional ' file extension', so I'm putting this check in here. --Matt"; url = url[1..$ - 1]; endif i = index(url, "?"); name = url[2..i ? i - 1 | $]; name = this:decode_from_url(name); if (typeof(`result = $httpd.names.(name) ! ANY') == OBJ && valid(result)) return this:canonical_parse_result(result, url); elseif (!name && $httpd.offmoo_home_url) return {$httpd.redirector, $httpd.offmoo_home_url}; elseif (`name[1] ! ANY' == "~" && valid(result = $string_utils:match_player(nam e[2..$]))) return this:canonical_parse_result(result, url); elseif ($string_utils:is_numeric(name) && $object_utils:isa(result = toobj(name ), $webroot)) return this:canonical_parse_result(result, url); else return {$failed_match, url}; endif . @verb $www_utils:"canonical_parse_result" this none this @program $www_utils:canonical_parse_result "Used internally by :parse_url."; "The point of this verb is to be sure that the browser is always directed to th e same URL for any given object, for greatest efficiency when caching."; {object, url} = args; canonical_url = tostr(this:objurl(object), this:encode_cgi_args(this:parse_cgi_ args(url))); if (!strcmp(url, canonical_url)) "why redirect?"; return {object, url}; else return {$httpd.redirector, canonical_url}; endif . @verb $www_utils:"decode_from_url" this none this @program $www_utils:decode_from_url {text} = args; text = strsub(text, "+", " "); ind = lastind = 0; while ((ind = index(text, "%")) && (ind != lastind)) hex = text[ind + 1..ind + 2]; text[ind..ind + 2] = encode_binary(tonum($math_utils:base_conversion(hex, 16, 10))); lastind = ind; endwhile return text; . @verb $www_utils:"encode_for_url" this none this @program $www_utils:encode_for_url {text} = args; newtext = ""; for j in [1..length(text)] c = text[j]; if (c == " ") c = "+"; elseif (!index(tostr($string_utils.alphabet, $string_utils.digits, this.other _valid_url_chars), c)) c = "%" + $math_utils:base_conversion(decode_binary(c, 1)[1], 10, 16); endif newtext = tostr(newtext, c); endfor return newtext; . @verb $www_utils:"content_length" this none this @program $www_utils:content_length {doc} = args; length = 0; for line in (doc) length = (length + length(line)) + this.newline_chars; endfor return length; . @create $webroot named HTTP Redirector:HTTP Redirector,wwwredir ;$httpd.redirector = player:my_match_object("wwwredir") @chmod wwwredir r @verb wwwredir:"http_request" this none this @program wwwredir:http_request {url} = args; if (url[1] == "/") url = tostr($httpd:url_prefix(), url); endif title = "Document Moved"; body = {$html_utils:h1(title)}; body = {@body, $html_utils:p("The document you requested has moved to the follo wing address:")}; body = {@body, $Html_utils:a(url, url)}; return {$html_utils:make_document(body, $html_utils:head_content(title)), tostr ("301 ", title), {{"Location", url}}}; . @create $webroot named Web Object Names:Web Object Names,wwwnames ;$httpd.names = player:my_match_object("wwwnames") @chmod wwwnames r @verb $room:html_contents tnt @program $room:html_contents contents = args[1]; out = {}; if (!this.dark && contents != {}) players = things = {}; for x in (contents) if (is_player(x)) players = {@players, x}; else things = {@things, x}; endif endfor if (things) out = {@out, $html_utils:p(tostr("You see ", $html_utils:title_list(things) , " here."))}; endif if (players) out = {@out, $html_utils:p(tostr($html_utils:title_listc(players), length(p layers) == 1 ? " " + $gender_utils:get_conj("is", players[1]) | " are", " here. "))}; endif endif return out; . @verb $room:html_exits tnt @program $room:html_exits if (this:obvious_exits()) out = {$html_utils:h2("Exits")}; exitlist = {}; for exit in (this:obvious_exits()) if (exit:is_unlocked_for($no_one)) exitlist = {@exitlist, tostr($html_utils:fixtext(exit.name), " to ", $htm l_utils:objlink(exit.dest))}; else exitlist = {@exitlist, tostr($html_utils:fixtext(exit.name), " to ", $htm l_utils:fixtext(exit.dest.name))}; endif endfor out = {@out, @$html_utils:ul(exitlist)}; return out; endif return {}; . @verb $room:html_body tnt @program $room:html_body body = pass(@args); body = {@body, @this:html_contents(this:contents(), this.ctype)}; body = {@body, @this:html_exits()}; return body; . @verb $room:allow_objlink tnt @program $room:allow_objlink return pass(@args) && this:acceptable($no_one); . @verb $player:html_body tnt @program $player:html_body out = pass(@args); if (!(this in connected_players())) out = {@out, $html_utils:p($gender_utils:pronoun_sub("%{:He} %{!is} sleeping. ", this))}; elseif ((idle = idle_seconds(this)) < 60) out = {@out, $html_utils:p($gender_utils:pronoun_sub("%{:He} %{!is} awake and %{!looks} alert.", this))}; else time = $string_utils:from_seconds(idle); out = {@out, $html_utils:p(tostr($gender_utils:pronoun_sub("%{:He} %{!is} awa ke, but %{!has} been staring off into space for ", this), time, "."))}; endif return out; "took out the contents JL 4-4-97"; "Content list isn't web-enabled since it is not being used on GR. --Matt, 20 De c 1998"; if (c = this:contents()) this:tell_contents(c); endif . @verb $note:http_request tnt @program $note:http_request if (this:is_readable_by($no_one)) return pass(@args); else return $httpd:error(403); endif . @verb $note:html_body tnt @program $note:html_body out = pass(@args); out = {@out, $html_utils:h2("Text"), @$html_utils:moo2html(this:text())}; return out; . @verb $code_utils:traceback tnt @program $code_utils:traceback {error, msg, value, stack} = args; out = {tostr(this:traceback_frame(@stack[1]), ": ", msg)}; for i in [2..length(stack)] out = {@out, tostr("...called by ", this:traceback_frame(@stack[i]))}; endfor return {@out, "(end of traceback)"}; . @verb $code_utils:traceback_frame tnt @program $code_utils:traceback_frame {thisobj, vname, proger, vloc, plyr, line} = args; if (!valid(thisobj) && vname) return tostr("built-in function ", vname, "()"); endif if (!valid(thisobj) && !vname) vname = "Input to EVAL"; endif if (vloc != thisobj) thisstr = tostr(" (this == ", thisobj, ")"); else thisstr = ""; endif return tostr(vloc, ":", vname, thisstr, ", line ", line); . ;chparent($room, $webroot) ;chparent($thing, $webroot) ;chparent(#6, $webroot) ;"Finished!"