/
CDC-1.0/
name integer 45
name file 8788
name parse 44
name buffer 1408
name gender_first_person_plural 2034
name false_lock_class 5
name http_interface 7969
name gender_plural 2036
name finger_daemon 7810
name event_handler 1139
name wrap_filter 1094
name note_editor 747
name logic_class 2485
name heap_class 1165
name connection 7792
name utilities 12
name http_file 8789
name messaged 1178
name user_db 3779
name filters 1093
name no_one 936
name daemon 7794
name place 2679
name exit 26
name body 28
name sys 0
name or 2489
name conference_parser 1432
name base_evaluator 9615
name and_lock_class 7
name or_lock_class 8
name login_watcher 888
name network_root 7791
name has_commands 16
name user_data 4309
name place_db 3778
name mail_db 3777
name world 2742
name false 2487
name user 30
name news 592
name log 2250
name programmer_interface 7459
name slate_connection 9508
name input_parser 2001
name has_settings 9398
name bad_commands 1140
name gender_male 1183
name environment 2786
name code_editor 758
name public 7261
name gender 40
name admin 33
name set 740
name not 2491
name realm_of_creation 2717
name notice_interface 9440
name not_lock_class 9
name generic_editor 1162
name command_parser 2000
name gender_neuter 1182
name verb_parser 2321
name programmer 32
name location 19
name arg_opts 310
name parsers 1431
name network 9153
name builder 31
name web_ui 9291
name login 4348
name guest 134
name note 7248
name http 8019
name dict 46
name code 51
name xor 2490
name db 790
name string 43
name data 7245
name small_first_heap_class 1166
name utility_objects 1170
name command_aliases 922
name contains_lock 2494
name lock_parser 10
name inside_lock 2495
name housekeeper 246
name event_class 1138
name verb_cache 35
name lock_class 3
name foundation 1377
name body_cave 247
name physical 1387
name http_log 8598
name gendered 1179
name editors 1388
name reaper 7232
name object 2451
name robot 5203
name named 2787
name true 2486
name text 1032
name root 1
name motd 4348
name and 2488
name gender_first_person 2032
name true_lock_class 4
name http_root_file 9292
name disk_readable 185
name login_daemon 7799
name display_opts 720
name settings_ui 9399
name interaction 86
name frob_class 2
name has_verbs 15
name dark_time 334
name nothing 984
name places 7523
name thing 24
name list 13
name time 333
name command_aliases_parser 2294
name connection_interface 7801
name located_location 25
name login_interface 7800
name wearable_class 1142
name old_connection 27
name movement_event 5205
name gender_female 1184
name http_daemon 7968
name antisocial 6099
name described 17
name registry 3775
name located 23
name english 48
name finger_interface 7811
name realms_class 1204
name object_lock 6
name null_parser 2622
name epic_filter 1095
name reaper_log 7292
name interfaces 664
name time_root 49
name scheduler 282
name eng_time 333
name creation 140
name channels 465
name nowhere 21
name slate 9552
name notes 522
name input 2337
name heart 5264
name void 22
name misc 675
name user_testperson 9688
object #1

var 1 manager #1
var 1 owners [#47]
var 1 writable [#1]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 1 child_index 3
var 1 fertile 0
var 1 inited 0
var 1 info ["The root object is the ultimate parent of all objects. It defines beahvior of all objects. It controls initialization, deinitialization, creation, destruction, and identification of objects, as well as permission checking, and ownership."]
var 1 quota 0
var 1 dbref 'root

method init_root
    (> .perms(caller(), $root) <);
    child_index = 0;
    fertile = 0;
    
    // for now set all the ownership stuff as this(), it can be reset later.
    manager = this();
    owned = [this()];
    owners = [this()];
    writable = [];
    readable = ['parameters, 'methods, 'code];
.

method uninit_root
    var obj, x, objs;
    
    (> .perms(caller(), $root) <);
    objs = [];
    catch any {
        for obj in (owned) {
            if (obj == this())
                continue;
            catch any {
                if ((obj.manager()) == this()) {
                    for x in (obj.owners()) {
                        if (valid(x) && (x != this()))
                            objs = [@objs, x];
                    }
                    obj.chown([$reaper, @objs]);
                    obj.set_manager($reaper);
                }
            } with handler {
                // this is getting redundant, but there is a reason for it.
                (| obj.chown([$reaper]) |);
                (| obj.del_owner(this()) |);
                $reaper_log.log(("$root.uninit_root(): Unable to give " + (obj.dbref())) + " an owner.");
            }
        }
        for obj in (owners)
            (| obj.del_owned_obj(this()) |);
    } with handler {
        $brandon.tell("Traceback from $root.uninit_root()");
        $brandon.tell_traceback(traceback());
    }
.

method initialize
    disallow_overrides;
    var ancestors, ancestor, method_name, pos;
    
    if ((caller() != $sys) && (sender() != this()))
        throw(~perm, "Caller is not $sys and sender is not this.");
    if (inited)
        throw(~perm, "Already initialized.");
    ancestors = ancestors();
    for pos in [0 .. listlen(ancestors) - 1] {
        ancestor = ancestors[listlen(ancestors) - pos];
        method_name = tosym("init_" + tostr(ancestor.dbref('symbol)));
        catch ~methodnf {
            if (find_method(method_name) != ancestor)
                throw(~perm, ((("Initialization method for " + (ancestor.namef('ref))) + " in wrong place. Found on ") + (find_method(method_name).namef('ref))) + ".");
            .(method_name)();
        }
    }
    inited = 1;
.

method uninitialize
    disallow_overrides;
    var ancestor, owner, obj;
    
    .perms(caller(), $root, $sys);
    for ancestor in (ancestors())
        (| .(tosym("uninit_" + tostr(ancestor.dbref('symbol))))() |);
.

method perms
    disallow_overrides;
    arg what, [args];
    var obj, flag, second;
    
    if (type(what) == 'dbref)
        what = [what];
    if (!args)
        args = ['writer];
    if (type(args[1]) == 'symbol) {
        for flag in (args) {
            switch (flag) {
                case 'this:
                    for obj in (what) {
                        if ((obj != this()) && (!($sys.is_system(obj))))
                            throw(~perm, ("Permission Denied: " + (obj.dbref())) + " is not this.", obj);
                    }
                case 'system:
                    for obj in (what) {
                        if (!($sys.is_system(obj)))
                            throw(~perm, ("Permission Denied: " + (obj.dbref())) + " is not of the system.", obj);
                    }
                case 'manager:
                    for obj in (what) {
                        if (((.manager()) != obj) && (!($sys.is_system(obj))))
                            throw(~perm, ("Permission Denied: " + (obj.dbref())) + " is not the manager.", obj);
                    }
                case 'trusts:
                    for obj in (what) {
                        if (!(.trusts(obj)))
                            throw(~perm, ("Permission Denied: " + (obj.dbref())) + " is not a trustee.", obj);
                    }
                case 'parser:
                    // This should be removed sometime.
                    for obj in (what) {
                        if ((!(obj.has_ancestor($parsers))) && (obj != this()))
                            throw(~perm, ("Permission Denied: " + (obj.dbref())) + " is not a parser.", obj);
                    }
                default:
                    for obj in (what) {
                        if (!(.is_writable_by(obj)))
                            throw(~perm, ("Permission Denied: " + (obj.dbref())) + " is not a writer.", obj);
                    }
            }
        }
    } else {
        for obj in (what) {
            if (!(obj in args))
                throw(~perm, ((obj.dbref()) + " is not one of: ") + ($list.to_english($list.map(args, 'namef, 'ref))), obj);
        }
    }
.

method _change_parents
    disallow_overrides;
    arg parents;
    var old, init, uninit, ancestor, pos;
    
    (> .perms(caller(), $root) <);
    if (!parents)
        throw(~noparents, "Objects must have at least 1 parent");
    
    // Perform the actual change.
    old = ancestors();
    (> $sys.change_sender_parents(parents) <);
    
    // Figure out new ancestors to initialize, and old ones to uninitialize.
    init = [];
    uninit = old;
    for ancestor in (ancestors()) {
        uninit = setremove(uninit, ancestor);
        if (!(ancestor in old))
            init = [@init, ancestor];
    }
    
    // Initialize the new ancestors.
    catch any {
        for ancestor in (init) {
            catch ~methodnf {
                .(tosym("init_" + tostr(ancestor.dbref('symbol))))();
            }
        }
    } with handler {
        // Initialization error; deinitialize parents we initialized, and fall
        // back to old parents.
        pos = ancestor in init;
        for ancestor in (sublist(init, 1, pos))
            (| .(tosym("uninit_" + tostr(ancestor.dbref('symbol))))() |);
        $sys.change_sender_parents(old);
        throw(~init, "Failed to initialize new ancestors.");
    }
    
    // Uninitialize the old ancestors.
    $sys.change_sender_parents(setremove(old, this()));
    for ancestor in (uninit)
        (| .(tosym("uninit_" + tostr(ancestor.dbref('symbol))))() |);
    $sys.change_sender_parents(parents);
.

method chparents
    arg parents;
    var parent;
    
    if (!(| .perms(sender(), 'manager) |))
        (> .perms(caller(), $root, $sys) <);
    if (!parents)
        throw(~noparents, "There must be at least 1 parent for each object.");
    
    // Notify parents of impending change.
    for parent in (parents)
        (> parent.will_inherit(sender()) <);
    
    // Everything's okay, go ahead and try it.
    ._change_parents(parents);
.

method will_inherit
    arg obj;
    
    // Throw an error if it's not okay for obj to inherit from us.
    if ((!fertile) && ((!(.trusts(obj))) && (!(obj.has_ancestor(this())))))
        throw(~perm, "Refuse to be parent of prospective child.");
.

method manager
    disallow_overrides;
    
    return manager;
.

method owners
    disallow_overrides;
    
    return owners;
.

method writers
    disallow_overrides;
    
    return writable + [manager, this()];
.

method trusted
    return (trusted ? trusted | []) + [this()];
.

method is_writable_by
    disallow_overrides;
    arg obj;
    
    return (| obj in (.writers()) |) || ($sys.is_system(obj));
.

method is_readable_by
    disallow_overrides;
    arg obj;
    
    // will eventually get this working with lock frobs, for now
    // ,readable is a simple list of what everyone can read:
    // 'methods, 'parameters, 'code
    if (.trusts(obj))
        return ['methods, 'parameters, 'code];
    else
        return readable;
.

method trusts
    arg obj;
    
    return (| obj in (.trusted()) |) || ((.is_writable_by(obj)) || ($sys.is_system(obj)));
.

method fertile
    disallow_overrides;
    
    return fertile;
.

method set_fertile
    arg val;
    
    (> .perms(sender(), 'manager) <);
    fertile = val ? 1 | 0;
.

method set_manager
    disallow_overrides;
    arg obj;
    
    (> .perms(sender(), 'manager) <);
    if (type(obj) != 'dbref)
        throw(~type, "Managers must be given as a single dbref.");
    manager = obj;
.

method set_writable
    disallow_overrides;
    arg what;
    
    .perms(sender(), 'manager);
    writable = what;
.

method add_writer
    disallow_overrides;
    arg what;
    
    (> .perms(sender(), 'manager) <);
    writable = [@writable, what];
.

method del_writer
    disallow_overrides;
    arg what;
    
    (> .perms(sender(), 'manager) <);
    writable = setremove(writable, what);
.

method set_readable
    disallow_overrides;
    arg what;
    
    (> .perms(sender(), 'manager) <);
    readable = what;
.

method set_trusted
    disallow_overrides;
    arg what;
    
    (> .perms(sender(), 'manager) <);
    trusted = what;
.

method add_trusted
    disallow_overrides;
    arg what;
    
    (> .perms(sender(), 'manager) <);
    trusted = [@trusted, what];
.

method del_trusted
    disallow_overrides;
    arg what;
    
    (> .perms(sender(), 'manager) <);
    trusted = setremove(trusted, what);
.

method as_this_run
    arg obj, method, [args];
    
    // run with this()'s perms -- unless they have changed .trusts,
    // it should just check against writers.
    if (!(.trusts(sender())))
        throw(~perm, "Sender not allowed to gain access to object perms.");
    return (> obj.(method)(@args) <);
.

method add_parent
    arg parent;
    
    (> .perms(sender(), 'manager) <);
    if (parent in (.parents()))
        throw(~parent, (((.dbref()) + " already has ") + (parent.namef('ref))) + " as a parent");
    if (!valid(parent))
        throw(~type, "Not a valid parent, must send a dbref or pointer");
    .chparents((.parents()) + [parent]);
.

method del_parent
    arg parent;
    var parents;
    
    (> .perms(sender(), 'manager) <);
    if (!valid(parent))
        throw(~type, "Not a valid parent, must send a dbref or pointer");
    parents = .parents();
    if (!(parent in parents))
        throw(~parentnf, "No such parent as " + ($data.unparse(parent)));
    parents = setremove(parents, parent);
    (> .chparents(parents) <);
.

method spawn
    arg [suffix];
    var obj, tmp, dbref, owner, mngr, na;
    
    // will later adjust this for .is_readable_by()
    // use this rather than $string.non_alphanumeric because it doesn't
    // have '_'
    na = "!@#$%^&*()+-=~`'{}[]|/?\"\\,.<>;: ";
    if ((!fertile) && (((.is_readable_by(sender())) != ['methods, 'parameters, 'code]) && (!($sys.is_system(sender())))))
        throw(~perm, "Not fertile or readable.");
    owner = sender();
    
    // Figure out the suffix from the arguments and child index.
    if (!(owner.quota_valid()))
        throw(~quota, "Sender does not have the available quota");
    if (suffix) {
        suffix = suffix[1];
    
        // so they dont confuse child_index:
        if ($string.is_numeric(suffix))
            throw(~perm, "Can't specify a numeric suffix.");
    
        // so we get correct symbols & it is always lowercase:
        suffix = $string.strip(suffix, na);
    } else {
        // make sure it doesn't exist already:
        dbref = tostr(.dbref('symbol));
        tmp = .dbref('symbol);
        while ((| get_name(tmp) |)) {
            child_index = child_index + 1;
            tmp = tosym((dbref + "_") + tostr(child_index));
        }
        suffix = tostr(child_index);
    }
    
    // Ask the system object for a child.
    obj = $sys.spawn_sender(suffix, owner);
    return obj;
.

method destroy
    disallow_overrides;
    
    // This doesn't actually destroy us immediately, but we will go away when
    // nothing is holding onto us any more.
    (> .perms(sender(), 'manager) <);
    (| .uninitialize() |);
    $sys.destroy_sender();
.

method add_parameter
    arg name, [args];
    var tmp, kid;
    
    // .add_parameter('name[, default-value, 'inherit])
    // Add the given parameter to this object.
    // if 'default-value' is included, initialize the variable to that value
    // if 'inherit is given the value is initialized on all descendents
    (> .perms(sender()) <);
    (> add_parameter(name) <);
    
    // The following code is a kludge as we can't send a default value to the
    // primitive.
    if (args) {
        tmp = tosym((("__set_" + tostr(name)) + "_") + tostr(random(1000)));
        catch any {
            compile([((tostr(name) + " = ") + toliteral(args[1])) + ";"], tmp);
            .(tmp)();
            if ((listlen(args) > 1) && ((args[2]) == 'inherit)) {
                for kid in (.descendants())
                    kid.(tmp)();
            }
            del_method(tmp);
        } with handler {
            del_method(tmp);
            rethrow(error());
        }
    }
.

method parameters
    (> .perms(sender(), 'this) <);
    return parameters();
.

method del_parameter
    arg name;
    
    (> .perms(sender()) <);
    (> del_parameter(name) <);
.

method del_method
    arg name;
    
    (> .perms(sender()) <);
    (> del_method(name) <);
.

method methods
    disallow_overrides;
    
    if (!('methods in (.is_readable_by(sender()))))
        throw(~perm, ((sender().dbref()) + " doesn't have permission to find methods on ") + (.dbref()));
    return methods();
.

method parents
    disallow_overrides;
    
    return parents();
.

method children
    disallow_overrides;
    
    return children();
.

method ancestors
    disallow_overrides;
    
    return ancestors();
.

method find_method
    disallow_overrides;
    arg name;
    
    if (!('methods in (.is_readable_by(sender()))))
        throw(~perm, ((sender().dbref()) + " doesn't have permission to find methods on ") + (.dbref()));
    return (> find_method(name) <);
.

method find_next_method
    disallow_overrides;
    arg name, after;
    
    if (!('methods in (.is_readable_by(sender()))))
        throw(~perm, ((sender().dbref()) + " doesn't have permission to find methods on ") + (.dbref()));
    return (> find_next_method(name, after) <);
.

method list_method
    arg [args];
    
    if (!('code in (.is_readable_by(sender()))))
        throw(~perm, (("Method code on " + (.namef('ref))) + " is not readable by ") + (sender().namef('ref)));
    return (> list_method(@args) <);
.

method compile
    arg code, name;
    
    // allow overrides -- may be a problem...
    (> .perms(sender()) <);
    return compile(code, name);
.

method show
    disallow_overrides;
    var output, actor, data, parent, readable, m, p, x, line;
    
    actor = sender();
    readable = .is_readable_by(actor);
    data = $sys.sender_data();
    
    // the beginning.
    output = ((("Object: " + (.namef('ref))) + " [") + tostr(.size())) + " bytes]";
    output = [output, "Parents: " + ($data.unparse(parents()))];
    
    // Methods
    if ('methods in readable) {
        output = output + ["Methods:"];
        for m in (.method_info())
            output = output + [((("  " + tostr(m[2])) + "(") + (m[3])) + ")"];
    } else {
        output = output + ["  ** No permission to list Methods **"];
    }
    
    // Parameters
    if ('parameters in readable) {
        for parent in (data) {
            // because the server is FKD we have to make sure your params
            // all have valid parents:
            if (valid(parent[1])) {
                output = output + [((parent[1]).namef('xref)) + " Parameters:"];
                if ('parameters in ((parent[1]).is_readable_by(actor))) {
                    for p in (parent[2]) {
                        line = (("  " + tostr(p[1])) + ": ") + ($data.unparse(p[2]));
                        output = output + [line];
                    }
                } else {
                    output = output + ["  ** Permission Denied **"];
                }
            } else {
                output = output + ["(Invalid parent-object You cannot reference because  it's broke) Parameters:"];
                for p in (parent[2]) {
                    line = (("  " + tostr(p[1])) + ": ") + ($data.unparse(p[2]));
                    output = output + [line];
                }
            }
        }
    } else {
        output = output + ["  ** No permission to list Parameters **"];
    }
    
    // Return what we've got.
    return output;
.

method has_ancestor
    disallow_overrides;
    arg obj;
    
    return has_ancestor(obj);
.

method eval
    disallow_overrides;
    arg code, [dest];
    var errors, result;
    
    dest = dest ? dest[1] | this();
    (> .perms(sender()) <);
    
    // Compile the code.
    errors = .compile(code, 'tmp_eval);
    if (errors)
        return ['errors, errors, 0, 0];
    
    // Evaluate the expression.  Be sure to remove it afterwards, so that no
    // one else can call it.
    catch any {
        result = dest.tmp_eval();
    } with handler {
        del_method('tmp_eval);
        rethrow(~methoderr);
    }
    del_method('tmp_eval);
    return ['result, result];
.

method method_info
    arg [args];
    var filter, maxp, anc, ancs, method, methods_found;
    
    // lists methods on objects which are ancestors of this and parents of args[1]
    // method info items are of the form:
    // [$definer, 'method, "args", "flags", "first comment/return value"]
    if (!('methods in (.is_readable_by(sender()))))
        throw(~perm, (("Method code on " + (.namef('ref))) + " is not readable by ") + (sender().namef('ref)));
    if (args) {
        maxp = args[1];
        args = delete(args, 1);
    }
    if (listlen(args) >= 2) {
        filter = sublist(args, 1, 2);
        args = delete(delete(args, 1), 1);
    } else {
        filter = [$misc, '_null_method_filter];
    }
    methods_found = [];
    ancs = .ancestors();
    if (!(maxp in ancs)) {
        maxp = this();
        ancs = [this()];
    }
    for anc in (ancs) {
        if (anc.has_ancestor(maxp)) {
            for method in (anc.methods()) {
                if ((filter[1]).(filter[2])(anc, method, @args))
                    methods_found = [@methods_found, ._get_method_info(anc, method)];
            }
        }
    }
    return methods_found;
.

method parameter_info
    arg [args];
    var data, pattern, max_parent, pparams, param;
    
    // data() reformated as
    // [[$parent,'param,val],...]
    if (!('parameters in (.is_readable_by(sender()))))
        throw(~perm, (("Parameters on " + (.dbref())) + " are not readable by ") + (sender().dbref()));
    max_parent = [@args, this()][1];
    data = [];
    for pparams in ($list.reverse($sys.sender_data())) {
        if (valid(pparams[1]) && ((pparams[1]).has_ancestor(max_parent))) {
            for param in (pparams[2])
                data = [@data, [pparams[1], @param]];
        }
    }
    return data;
.

method data
    var par, data, out;
    
    if (!('parameters in (.is_readable_by(sender()))))
        throw(~perm, ((sender().namef('ref)) + " is not allowed to read parameters on ") + (.namef('ref)));
    data = $sys.sender_data();
    out = #[];
    for par in (data) {
        // if the parent doesn't exist anymore, just let them see the data.
        if ((!valid(par[1])) || ('parameters in ((par[1]).is_readable_by(sender()))))
            out = dict_add(out, par[1], par[2]);
        else
            out = dict_add(out, par[1], ["*** Permission Denied ***"]);
    }
    return out;
.

method size
    disallow_overrides;
    arg [args];
    
    args = [@args, 'int][1];
    switch (args) {
        case 'string:
            return tostr(size());
        case 'english:
            return $int.to_english(size());
        default:
            return size();
    }
.

method descendants
    disallow_overrides;
    var kid, kids;
    
    // .descendants()
    // -> Recursive list of all children of this object -- try not to use
    kids = children();
    for kid in (kids)
        kids = union(kids, kid.descendants());
    return kids;
.

method get_quota
    disallow_overrides;
    
    return quota;
.

method owned
    disallow_overrides;
    
    return owned;
.

method quota_valid
    disallow_overrides;
    
    // if (!.has_ancestor($user) && !$sys.is_admin(this()))
    //  return 0;
    // will put quota checking in here
    return 1;
.

method del_owned_obj
    disallow_overrides;
    arg obj;
    
    (> .perms(caller(), $root) <);
    owned = setremove(owned, obj);
.

method add_owned_obj
    disallow_overrides;
    arg obj;
    
    (> .perms(caller(), $root, $sys) <);
    if (obj in owned)
        throw(~addowned, ((.namef('ref)) + " already owns ") + (obj.namef('ref)));
    owned = [@owned, obj];
.

method match_children
    arg string;
    var children, child_names, c;
    
    children = .children();
    child_names = $list.map(children, 'namef);
    
    // direct matches first.
    for c in (child_names) {
        if (c == string)
            return children[c in child_names];
    }
    
    // ok, try partial matches
    for c in (child_names) {
        if (match_begin(c, string))
            return children[c in child_names];
    }
    return 0;
.

method set_info
    arg text;
    
    (> .perms(sender(), 'manager) <);
    info = text;
.

method info
    return info;
.

method _display_descendants
    arg [args];
    var space, checked, c, anc, biguglylist, id, perms;
    
    space = args ? args[1] | "";
    checked = (listlen(args) > 1) ? args[2] | [];
    perms = "";
    if (fertile)
        perms = "F";
    for c in (.readable())
        perms = perms + (tostr(c)[1]);
    id = (space + (.namef(['dbref], " (", ['name], ")"))) + (perms ? (" [" + perms) + "]" | perms);
    for anc in (checked) {
        if (.has_ancestor(anc))
            return [id + "  (above)"];
    }
    if (listlen(.parents()) > 1)
        id = id + " (MI)";
    else
        id = id + "";
    biguglylist = [id];
    space = space + "   ";
    
    // check children
    for c in (.children()) {
        biguglylist = biguglylist + (c._display_descendants(space, checked));
        checked = setadd(checked, c);
        pause();
    }
    return biguglylist;
.

method _display_ancestors
    arg [args];
    var space, checked, c, anc, biguglylist, id, perms;
    
    space = args ? args[1] | "";
    checked = (listlen(args) > 1) ? args[2] | [];
    perms = "";
    if (fertile)
        perms = "F";
    for c in (.readable())
        perms = perms + (tostr(c)[1]);
    id = (space + (.namef('ref))) + (perms ? (" [" + perms) + "]" | perms);
    for anc in (checked) {
        if (.has_ancestor(anc))
            return [id + "  (above)"];
    }
    if (listlen(.parents()) > 1)
        id = id + " (MI)";
    else
        id = id + "";
    biguglylist = [id];
    space = space + "  ";
    
    // check children
    for c in (.parents()) {
        biguglylist = biguglylist + (c._display_ancestors(space, checked));
        checked = setadd(checked, c);
        pause();
    }
    return biguglylist;
.

method _get_method_info
    disallow_overrides;
    arg anc, method;
    var code, lines, dis_flag, meth_args, first_comment;
    
    code = anc.list_method(method);
    lines = listlen(code);
    if (lines > 5)
        code = sublist(code, 1, 5);
    dis_flag = 0;
    if (code) {
        if ("disallow_overrides;" == (code[1])) {
            dis_flag = 1;
            code = delete(code, 1);
        }
        if (code && ((code[1]) && (((code[1])[1]) == "a"))) {
            meth_args = match_pattern("arg *;", code[1])[1];
            code = delete(code, 1);
        } else {
            meth_args = "";
        }
        if (code && ((!(code[1])) || (((code[1])[1]) == "v")))
            code = delete(code, 1);
        if (code && ((!(code[1])) || (((code[1])[1]) == "v")))
            code = delete(code, 1);
        first_comment = code ? (code[1]) + " " | " ";
        first_comment = (((first_comment[1]) == "/") || ((first_comment[1]) == "r")) ? first_comment | "";
    } else {
        meth_args = "";
        first_comment = "";
    }
    return [anc, method, meth_args, dis_flag, lines, first_comment];
.

method namef
    arg [args];
    var output, type, part;
    
    if (!args)
        args = [['dbref]];
    if (((args[1]) == 'ref) || ((args[1]) == 'xref))
        args = [['dbref]];
    
    // the actual switch, punctuation is treated oddly (parens specifically)
    output = "";
    for part in (args) {
        type = type(part);
        if (type == 'list)
            output = output + ((| .(part[1])(@sublist(part, 2)) |) || "");
        else if (type == 'string)
            output = output + part;
    }
    return output;
.

method match_descendants
    arg string;
    var match, child;
    
    match = .match_children(string);
    if (match)
        return match;
    for child in (.children()) {
        match = child.match_descendants(string);
        if (match)
            return match;
    }
    return 0;
.

method readable
    return readable;
.

method chown
    disallow_overrides;
    arg new_owners;
    var old_owners, obj, sofar, this;
    
    // must be called to add/del/change any ownership.
    (> .perms(sender(), .manager(), @$sys.system()) <);
    
    // make sure the new owners list is legit.
    if (type(new_owners) != 'list)
        throw(~type, "New owners must be given as a list of objects");
    if (!($sys.is_system(sender()))) {
        for obj in (new_owners) {
            if (!(obj.has_ancestor($user)))
                throw(~perm, (obj.namef('ref)) + " is not a user object.");
        }
    }
    
    // few basic (re)settings
    old_owners = $list.flatten(owners);
    new_owners = $list.flatten(new_owners);
    owners = [];
    this = this();
    sofar = [];
    
    // first make it so nobody owns it.
    for obj in (old_owners)
        (| obj.del_owned_obj(this) |);
    
    // set all the new owners
    for obj in (new_owners) {
        catch any {
            obj.add_owned_obj(this);
        } with handler {
            if (error() == ~addowned)
                continue;
    
            // didn't work out, set it back the way it was.
            for obj in (sofar)
                (| obj.del_owned_obj(this) |);
            for obj in (old_owners) {
                if ((| obj.add_owned_obj(this) |))
                    owners = [@owners, obj];
            }
            throw(~chown, "Unable to add %O as an owner, chown unsuccessful.", obj);
        }
        sofar = [@sofar, obj];
    }
    owners = new_owners;
.

method debug
    arg [stuff];
    var x, line, mngr;
    
    line = (sender().namef(['id])) + " debug:";
    for x in (stuff)
        line = (line + " ") + ((type(x) == 'string) ? x | ($data.unparse(x)));
    (| (.manager()).tell(line) |);
.

method set_quota
    arg value;
    
    (> .perms(caller(), $user, @$sys.system(), $root) <);
    quota = value;
.

method dbref
    arg [args];
    
    args = [@args, 'string][1];
    switch (args) {
        case 'string:
            return "$" + tostr(dbref);
        case 'symbol:
            return dbref;
        default:
            throw(~type, "args must be 'string or 'symbol.");
    }
.

method set_dbref
    arg new_dbref;
    var old_dbref;
    
    // Only accept calls from owners or admins.
    if (!(.is_writable_by(sender())))
        throw(~perm, "Sender not an owner.");
    
    // Make sure first argument is a symbol.
    if (type(new_dbref) != 'symbol)
        throw(~type, "New dbref is not a symbol.");
    
    // Do nothing if new_dbref isn't different.
    if (new_dbref == dbref)
        return;
    
    // Make sure everything is lowercase.
    new_dbref = tosym(lowercase(tostr(new_dbref)));
    
    // Grab the new dbref
    catch any {
        $sys.assign_dbref(new_dbref);
        old_dbref = dbref;
        dbref = new_dbref;
    
        // If we already had a dbref, get rid of the old one.
        if (old_dbref)
            $sys.deassign_dbref(old_dbref);
    } with handler {
        $brandon.tell_traceback(traceback(), "");
    }
.

method name
    arg [args];
    
    return .dbref();
.

method del_owner
    disallow_overrides;
    arg owner;
    
    (> .perms(caller(), $root) <);
    if (listlen(owners) != 1)
        owners = setremove(owners, owner);
    else
        .chown([$no_one]);
.

method add_owner
    disallow_overrides;
    arg owner;
    
    (> .perms(caller(), $root) <);
    owners = [@owners, owner];
.

method generate_html
    arg [args];
    var actor, readable, name, out, line, obj, col, colx, objs, x;
    
    actor = sender();
    readable = .is_readable_by(actor);
    name = .namef('ref);
    out = ["<head>", ("<title>" + name) + "</title>", "<center>"];
    out = [@out, ("<h1>" + name) + "</h1>", "</center>"];
    out = [@out, "<hr width=50% align=middle>", "<body>"];
    line = ("<a href=\"/bin/show?" + tostr(.dbref('symbol))) + "\">";
    out = [@out, ("<center>" + line) + "show this object.</a></center>"];
    line = [];
    for obj in (.parents())
        line = [@line, $http.make_href_string(obj)];
    out = [@out, "<P>Parent(s): " + ($list.to_english(line)), "<pre>"];
    
    // duplicate the $code.generate_family_listing code because we
    // want to put in hrefs.
    objs = .children();
    if (objs) {
        out = [@out, "Children:"];
        col = ((| sender().linelen() |) || 79) / 8;
        colx = col * 3;
        line = pad("Name", colx + 2) + pad(" Perms", col - 2);
        out = [@out, (line + pad("Size ", -col)) + "Manager"];
        for obj in (objs) {
            name = obj.namef('xref);
            line = $http.make_href_string(obj, pad(name, colx + 2));
            line = line + pad($object.see_perms(obj), col - 2);
            line = line + pad(tostr(obj.size()) + " ", -col);
            x = obj.manager();
            if (!valid(x))
                name = pad(("** invalid object *(" + tostr(x)) + ") **", colx);
            else
                name = $http.make_href_string(x, pad(x.namef('xref), colx));
            line = line + name;
            out = [@out, line];
        }
    }
    out = [@out, "</pre>"];
    if (info) {
        if (type(info) == 'frob)
            out = [@out, info.translate_to("text/html")];
        else
            out = [@out, "<hr width=50% align=middle>", @info];
    }
    return out;
.

method show_in_html
    disallow_overrides;
    var out, actor, data, parent, readable, m, p, x, line;
    
    // duplicating code in .show because I want it to be htmlified
    actor = sender();
    readable = .is_readable_by(actor);
    data = $sys.sender_data();
    
    // the beginning.
    out = "Object: " + ($http.make_object_href(this(), .namef('ref)));
    out = ((out + " [") + tostr(.size())) + " bytes]";
    line = [];
    for x in (.parents())
        line = [@line, $http.make_object_href(x)];
    out = [out, "Parent(s): " + ($list.to_english(line)), "<pre>"];
    
    // Methods
    if ('methods in readable) {
        out = out + ["Methods:"];
        for m in (.method_info())
            out = out + ["  " + ($http.make_method_href(m))];
    } else {
        out = out + ["  ** No permission to list Methods **"];
    }
    
    // Parameters
    if ('parameters in readable) {
        for parent in (data) {
            // because the server is FKD we have to make sure your params
            // all have valid parents:
            if (valid(parent[1])) {
                out = out + [((parent[1]).namef('xref)) + " Parameters:"];
                if ('parameters in ((parent[1]).is_readable_by(actor))) {
                    for p in (parent[2]) {
                        line = (("  " + tostr(p[1])) + ": ") + (($http.filter_text([$data.unparse(p[2])]))[1]);
                        out = out + [line];
                    }
                } else {
                    out = out + ["  ** Permission Denied **"];
                }
            } else {
                out = out + ["(Invalid parent-object You cannot reference because  it's broke) Parameters:"];
                for p in (parent[2]) {
                    line = (("  " + tostr(p[1])) + ": ") + (($http.filter_text([$data.unparse(p[2])]))[1]);
                    out = out + [line];
                }
            }
        }
    } else {
        out = out + ["  ** No permission to list Parameters **"];
    }
    
    // Return what we've got.
    return out;
.

parent #1
object #675

var 1 child_index 16
var 1 owners [#936]
var 1 owned []
var 1 fertile 1
var 1 inited 1
var 1 manager #675
var 1 writable [#675]
var 1 readable ['parameters, 'methods, 'code]
var 1 info ["$misc is the parent for all objects which do not fit anywhere else on the herarchy. It serves as a means of keeping $root from having too many children."]
var 1 dbref 'misc

method _null_method_filter
    arg [args];
    
    return 1;
.

method _display_filter
    arg anc, method, includes, excludes;
    var pat, ret, name;
    
    name = tostr(method);
    while (includes) {
        if (match_pattern(includes[1], name) == 0)
            return 0;
        includes = delete(includes, 1);
    }
    while (excludes) {
        if (match_pattern(excludes[1], name) != 0)
            return 0;
        excludes = delete(excludes, 1);
    }
    return 1;
.

parent #675
object #7791

var 1 dbref 'network_root
var 1 child_index 4
var 1 fertile 0
var 1 manager #7791
var 1 owned []
var 1 owners [#936]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 1 inited 1
var 7791 buffer `[]
var 7791 ip ""
var 7791 hostname ""
var 7791 socket 0
var 7791 port 0
var 7791 active 0

method init_network_root
    (> .perms(caller(), $root) <);
    (> .reset_connection() <);
.

method uninit_network_root
    (> .perms(caller(), $root) <);
    (> .reset_connection() <);
.

method reset_connection
    // reset parameters to their default values
    (> .perms(caller(), $network_root) <);
    disconnect();
    buffer = `[];
    ip = "";
    hostname = "";
    port = 0;
    socket = 0;
    active = 0;
.

method failed
    arg socket;
    
    // called by the server when unable to make a connection.
    if ((sender() != 0) || (sender() != this()))
        throw(~perm, "Sender is not the server");
    .receive("CONNECTION FAILED; socket: " + tostr(socket), 'connection_failed);
    
    // we weren't ever connected, but this will reset us.
    (| .close() |);
.

method open
    arg addr, port;
    
    // open a connection to <addr> on <port>
    (> .perms(sender()) <);
    if (active)
        throw(~engaged, (.namef('ref)) + " is currently engaged.");
    
    // reset for good measure
    (> .reset_connection() <);
    
    // set the active bit.
    .set_active(1);
    
    // set the ip or addr, if children want they can redefine .set_*
    // to check for hostname() or whatever.
    if (toint(addr))
        .set_ip(addr);
    else
        .set_hostname(addr);
    .set_port(port);
    
    // try to open it
    (> $sys.connect(addr, port, this()) <);
.

method close
    // close the connection
    (> .perms(sender()) <);
    (> .reset_connection() <);
    .receive("Connection Closed.", 'connection_closed);
.

method connect
    arg [args];
    
    // called by the server when a successful connection is made
    if (sender() != 0)
        throw(~perm, "Sender is not the server");
    .receive("CONNECTION ESTABLISHED; " + ($data.unparse(args)), 'connection_established);
    
    // This is ugly, will be fixed when networking is fixed in the driver
    if (type(args[1]) == 'integer) {
        socket = args[1];
    } else {
        ip = args[1];
        socket = args[2];
        hostname = hostname(ip);
    }
.

method disconnect
    arg [args];
    
    $brandon.debug(this(), args);
    if ((sender() != 0) || (sender() != this()))
        throw(~perm, "Sender is not the server");
    (> .close() <);
.

method receive
    arg line, status;
    
    // receive a string, called by .parse()
.

method parse
    arg incoming;
    var lines, line;
    
    // called by the server with an incoming buffer
    if (sender() != 0)
        throw(~perm, "Sender and caller are not the server");
    lines = buffer_to_strings(buffer_append(buffer, incoming));
    buffer = lines[listlen(lines)];
    lines = sublist(lines, 1, listlen(lines) - 1);
    for line in (lines)
        .receive(line, 'external);
.

method send
    arg what;
    var line;
    
    // send off a string or list of strings.  Calls .echo()
    if (type(what) == 'list) {
        for line in (what)
            .send(line);
    } else {
        .echo(what, 'string);
    }
.

method echo
    arg what, type;
    
    // send off a string or buffer
    (> .perms(sender()) <);
    switch (type) {
        case 'string:
            (> echo(buffer_from_strings([what])) <);
        case 'buffer:
            (> echo(what) <);
    }
.

method bind
    arg port, receiver;
    
    // bind to a port
    (> .perms(sender(), 'this) <);
    (> $sys.bind(port, receiver) <);
.

method unbind
    arg port;
    
    // unbind from a port
    (> .perms(sender(), 'this) <);
    (> $sys.unbind(port) <);
.

method ip
    (> .perms(sender(), 'trusts) <);
    return ip;
.

method hostname
    (> .perms(sender(), 'trusts) <);
    return hostname;
.

method port
    (> .perms(sender(), 'trusts) <);
    return port;
.

method socket
    (> .perms(sender(), 'trusts) <);
    return socket;
.

method active
    (> .perms(sender(), 'trusts) <);
    return active;
.

method set_ip
    arg str;
    
    (> .perms(sender(), 'this) <);
    ip = str;
.

method set_hostname
    arg str;
    
    (> .perms(sender(), 'this) <);
    hostname = str;
.

method set_port
    arg int;
    
    (> .perms(sender(), 'this) <);
    port = int;
.

method set_socket
    arg int;
    
    (> .perms(sender(), 'this) <);
    socket = int;
.

method set_active
    arg bit;
    
    (> .perms(sender(), 'this) <);
    active = bit;
.

parent #7791
object #9508

var 1 dbref 'slate_connection
var 1 child_index 5
var 1 fertile 0
var 1 manager #37
var 1 owned []
var 1 owners [#37]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 7791 buffer `[]
var 7791 ip ""
var 7791 hostname ""
var 7791 port 0
var 7791 socket 0
var 7791 active 0
var 1 inited 1
var 9508 receiver 0

method receive
    arg line, status;
    
    if (receiver)
        receiver.receive(line, status);
.

method uninit_slate
    (> .perms(caller(), $root) <);
    (| receiver.slate_going_away() |);
.

method init_slate
    (> .perms(caller(), $root) <);
    receiver = 0;
.

method open
    arg addr, port;
    
    (> pass(addr, port) <);
    receiver = sender();
.

method trusts
    arg obj;
    
    if (obj in ($network.valid_slate_callers()))
        return 1;
    return pass(obj);
.

method new_slate_connection
    var new_obj;
    
    (> .perms(caller(), 'trusts) <);
    new_obj = .spawn();
    new_obj.add_writer(sender());
    new_obj.chown([sender()]);
    new_obj.set_manager(sender());
    return new_obj;
.

method close
    (> pass() <);
    (| slate.connection_ending() |);
    (> .destroy() <);
.

parent #1
object #2

var 1 child_index 8
var 1 owners [#936]
var 1 fertile 1
var 1 inited 1
var 1 owned []
var 1 manager #2
var 1 writable [#2]
var 1 readable ['parameters, 'methods, 'code]
var 1 info ["$frob_class is the root of all frob objects. It defines .unparse, for displaying frobs (.unparse may be overriddent, but defaults to <$class, [rep] | #[rep]>."]
var 1 dbref 'frob_class

method unparse
    arg rep;
    
    return ((("<" + ($data.unparse(this()))) + ", ") + ($data.unparse(rep))) + ">";
.

method new
    arg value;
    
    return <this(), value>;
.

parent #2
object #2485

var 1 child_index 6
var 1 fertile 0
var 1 manager #2485
var 1 owners [#936]
var 1 writable [#2485]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 1 inited 1
var 1 dbref 'logic_class

method test
    arg [args];
    
    return 0;
.

parent #2485
object #3

var 1 owners [#936]
var 1 owned []
var 1 manager #3
var 1 writable [#3]
var 1 readable ['parameters, 'methods, 'code]
var 1 child_index 2
var 1 dbref 'lock_class

parent #3
object #2494

var 1 child_index 0
var 1 fertile 0
var 1 manager #2494
var 1 owners [#936]
var 1 writable [#2494]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 1 inited 1
var 1 dbref 'contains_lock

method test
    arg objlist, testee, [args];
    var x;
    
    for x in (objlist) {
        if (testee.contains(x))
            return 1;
    }
    return 0;
.

parent #1
object #1170

var 1 child_index 7
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 1 inited 1
var 1 manager #1170
var 1 writable [#1170]
var 1 readable ['parameters, 'methods, 'code]
var 1 info ["$utility_objects is the parent for all objects which are themsleves utilities, such as $scheduler. It does not define anything."]
var 1 dbref 'utility_objects

parent #1170
object #8019

var 1 dbref 'http
var 1 child_index 0
var 1 fertile 0
var 1 manager #8019
var 1 owned []
var 1 owners [#936]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 1 inited 1
var 8019 errors #[[400, ["<head><title>400 Bad Request</title></head>", "<body>", "<center><h1>400 Bad Request</h1></center>", "%s", "</body>"]], [403, ["<head><title>403 Permission Denied</title></head>", "<body>", "<center><h1>403 Permission Denied</h1></center>", "%s", "</body>"]], [404, ["<head><title>404 Not Found</title></head>", "<center><h1>404 Not Found</h1></center>", "%s", "</body>"]]]

method set_error
    arg error, lines;
    
    (> .perms(sender(), 'manager) <);
    errors = dict_add(errors, error, lines);
.

method del_error
    arg error, lines;
    
    (> .perms(sender(), 'manager) <);
    errors = dict_del(errors, error);
.

method get_error
    arg error, str;
    var lines, x;
    
    lines = (| errors[error] |) || ["Oops, server just broke."];
    for x in [1 .. listlen(lines)]
        lines = replace(lines, x, strsub(lines[x], "%s", str));
    return lines;
.

method make_href_string
    arg obj, [name];
    var line;
    
    if (!name)
        name = [obj.dbref()];
    line = ("<tt><a href=\"/objects/" + tostr(obj.dbref('symbol))) + "/\">";
    return (line + (name[1])) + "</a></tt>";
.

method bin_show
    arg [args];
    var out, obj;
    
    if (!args)
        return .get_error(400, "Must specify an object");
    obj = (| $object.to_dbref(args[1]) |);
    if (!obj)
        return .get_error(404, ("Unable to find object \"" + (args[1])) + "\"");
    return ["<pre>", @obj.show_in_html(), "</pre>"];
.

method make_method_href
    arg m;
    
    return ((((((("<a href=\"/bin/list_method?" + ((m[1]).dbref())) + ".") + tostr(m[2])) + "()\">") + tostr(m[2])) + "(") + (m[3])) + ")</a>";
.

method make_object_href
    arg obj, [name];
    var line;
    
    if (!name)
        name = [obj.dbref()];
    line = ("<tt><a href=\"/objects/" + tostr(obj.dbref('symbol))) + "/\">";
    return (line + (name[1])) + "</a></tt>";
.

method bin_list_method
    arg [args];
    var ref, str_ref, name, obj, code, anc, out, line, x;
    
    if (!args)
        return .get_error(400, "Must specify a method reference");
    catch any {
        ref = $parse.reference(args[1]);
        name = tosym(ref[2]);
        obj = $object.to_dbref(ref[1]);
        anc = obj.find_method(name);
        code = anc.list_method(name);
        code = .filter_text(code);
        for x in [1 .. listlen(code)]
            line = "    " + (code[x]);
        str_ref = (((obj.dbref()) + ".") + tostr(name)) + "()";
        out = [("<head><title>" + str_ref) + "</title></head>"];
        out = [@out, ("<body><center><h1>" + str_ref) + "</h1></center>"];
        out = [@out, "<hr>", "<pre><code>", "@program " + str_ref];
        out = [@out, @code, ".", "</code></pre>"];
    } with handler {
        switch (error()) {
            case ~methodnf:
                line = (((obj.dbref()) + ".") + tostr(name)) + "()";
                out = $http.get_error(400, line + " not found.");
            default:
                out = $http.get_error(400, (traceback()[1])[2]);
        }
    }
    return out;
.

method bin_who
    arg [args];
    var out, obj;
    
    // will have to spiff this up later.
    out = ["<head><title>Who is connected to the Cold Dark?</title></head>"];
    out = [@out, "<body><pre>", @$code.generate_listing($user_db.connected())];
    return out + ["</pre>"];
.

method filter_text
    arg text;
    var x, line;
    
    // embed's characters ('>' becomes '&gt;' etc)
    for x in [1 .. listlen(text)] {
        line = strsub(text[x], "&", "&amp;");
        line = strsub(line, "<", "&lt;");
        line = strsub(line, ">", "&gt;");
        text = replace(text, x, line);
    }
    return text;
.

parent #1
object #1377

var 1 child_index 4
var 1 fertile 0
var 1 manager #1377
var 1 owners [#1377]
var 1 writable [#1377, #47]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 1 inited 1
var 1 info ["$foundation is the root object of the world building blocks. All 'vr' objects are ultimately derived from the foundation object, as well as some of the non-vr helper objects."]
var 1 dbref 'foundation

parent #1377
object #1178

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 1
var 1 inited 1
var 1 manager #1178
var 1 writable [#1178]
var 1 readable ['parameters, 'methods, 'code]
var 1178 messages 0
var 1 info ["$messaged stores messages for various objects. For example, $exit messages such as would be displayed when a being attempts to travers an exit, but fails would be stored in a $messaged parameter, but could be overridden on a particular exit."]
var 1 dbref 'messaged

method messages
    .perms(sender(), 'this);
    return messages || #[];
.

method all_messages
    var msg, all;
    
    // For message to call when inheriting, or something
    .perms(sender(), 'this);
    all = (| pass() |) || #[];
    for msg in (.messages()) {
        if (msg in dict_keys(all))
            all = $dict.replace(all, msg, (.messages())[msg]);
        else
            all = dict_add(all, msg, (.messages())[msg]);
    }
    return all;
.

method message
    arg id;
    var ret;
    
    ret = (| (.all_messages())[id] |);
    if (type(ret) == 'error)
        throw(~msgnf, "Message not found.");
    return ret;
.

method add_message
    arg id, msg;
    
    .perms(sender());
    if (.has_message(id))
        throw(~msgexists, "Message already defined.");
    messages = dict_add(messages, id, msg);
.

method set_message
    arg id, msg;
    
    .perms(sender());
    if (.defines_msg(id))
        messages = $dict.replace(messages, id, msg);
    else
        .add_message(id, msg);
.

method has_message
    arg id;
    
    return id in dict_keys(.all_messages());
.

method defines_msg
    arg id;
    
    return id in dict_keys(.messages());
.

method init_messaged
    .perms(caller(), $root);
    messages = #[];
.

parent #2
parent #1178
object #1138

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 1 inited 1
var 1 manager #1138
var 1 writable [#1138]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'event_class
var 1138 type 'generic
var 1178 messages #[]

method new
    arg [args];
    
    .perms(caller(), $event_handler);
    
    // we still don't know what we want
    //  if (type(location) != 'dbref)
    //    throw(~type, "The location must be given as a dbref");
    // return <this(), #[['actor, sender()], ['action, action], ['what, what], ['where, location], ['direction, direction]]>;
    return <this(), [sender(), @args]>;
.

method dispatch
    arg dict;
    
    .has_object_perms($event_handler, caller());
    (dict['where]).event(<this(), dict>);
.

method set_event_type
    arg newtype;
    
    .perms(sender());
    if (type(newtype) != 'symbol)
        throw(~type, "New event types must be symbols.");
    type = newtype;
.

method type
    arg [args];
    
    return type;
.

parent #1138
object #5205

var 1 dbref 'movement_event
var 1 child_index 0
var 1 fertile 0
var 1 manager #7232
var 1 owned []
var 1 owners [#7232, #1387, #1388]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 1 inited 1
var 1138 type 'movement

method exit
    arg rep;
    
    return rep[2];
.

method new
    arg which, who, [args];
    
    (> .perms(caller(), $exit) <);
    return <this(), [which, who, sender()]>;
.

method dest
    arg args;
    
    return (args[3]).dest();
.

method source
    arg args;
    
    return (args[3]).source();
.

parent #1377
object #16

var 16 commands []
var 16 shortcuts []
var 1 child_index 2
var 1 owners [#936]
var 1 fertile 0
var 1 inited 1
var 1 owned []
var 1 manager #16
var 1 writable [#16]
var 1 readable ['parameters, 'methods, 'code]
var 533 title "untitled"
var 533 brief ""
var 533 help_name ""
var 533 text []
var 533 footnotes []
var 533 references #[]
var 533 upnode #534
var 533 subnodes []
var 533 menu 0
var 1 dbref 'has_commands

method init_has_commands
    if (caller() != $root)
        throw(~perm, "Caller is not $root.");
    commands = [];
    shortcuts = [];
.

method uninit_has_commands
    if (caller() != $root)
        throw(~perm, "Caller is not $root.");
    commands = 0;
    shortcuts = 0;
.

method add_command
    arg template, method;
    
    if (!(.is_writable_by(sender())))
        throw(~perm, "Sender is not an owner.");
    if ((type(template) != 'string) || (type(method) != 'symbol))
        throw(~type, "Template and method are not a string and symbol.");
    commands = [@commands, [template, method]];
.

method del_command
    arg match;
    var command, x;
    
    .perms(sender());
    
    // so you can do both template or method
    if (type(match) == 'symbol)
        x = 2;
    else if (type(match) == 'string)
        x = 1;
    else
        throw(~type, "Type must either be a string or symbol (template or method).");
    for command in (commands) {
        if ((command[x]) == match) {
            commands = setremove(commands, command);
            return;
        }
    }
    throw(~commandnf, "No command with match " + toliteral(match));
.

method add_shortcut
    arg pattern, method, subs;
    
    if (!(.is_writable_by(sender())))
        throw(~perm, "Sender is not an owner.");
    if ((type(pattern) != 'string) || ((type(method) != 'symbol) || (type(subs) != 'list)))
        throw(~type, "Pattern, method, and subs are not a string, symbol, and list.");
    shortcuts = [@shortcuts, [pattern, method, subs]];
.

method del_shortcut
    arg method;
    var shortcut;
    
    if (!(.is_writable_by(sender())))
        throw(~perm, "Sender is not an owner.");
    for shortcut in (shortcuts) {
        if ((shortcut[2]) == method) {
            shortcuts = setremove(shortcuts, shortcut);
            return;
        }
    }
    throw(~shortcutnf, "No shortcut with method " + tostr(method));
.

method match_command
    arg str;
    var shortcut, cmd, fields;
    
    // Try shortcuts.
    for shortcut in (.all_shortcuts()) {
        fields = match_pattern(shortcut[1], str);
        if (fields)
            return [shortcut[2], .sub_shortcut_fields(shortcut[3], fields)];
    }
    
    // Try commands.
    for cmd in (.all_commands()) {
        fields = match_template(cmd[1], str);
        if (fields)
            return [cmd[2], fields];
    }
    
    // Give up.
    return 0;
.

method commands
    return commands;
.

method all_commands
    var p, cmdlist, pc;
    
    // Collect complete command list from ancestors.  Ancestors may not be
    // command-handling objects, in which case (| p.commands() |) is
    // ~methodnf.
    cmdlist = [];
    for p in (ancestors()) {
        pc = (| p.commands() |);
        if (pc)
            cmdlist = cmdlist + pc;
        if (p == definer())
            break;
    }
    return cmdlist;
.

method shortcuts
    return shortcuts;
.

method all_shortcuts
    var ancestor, list, ancestor_shortcuts;
    
    // Collect complete command list from ancestors.  Ancestors may not be
    // command-handling objects, in which case (| p.shortcuts() |) is
    // ~methodnf.
    list = [];
    for ancestor in (ancestors()) {
        ancestor_shortcuts = (| ancestor.shortcuts() |);
        if (ancestor_shortcuts)
            list = list + ancestor_shortcuts;
        if (ancestor == definer())
            break;
    }
    return list;
.

method sub_shortcut_fields
    arg subs, fields;
    var subbed_list, elem;
    
    subbed_list = [];
    for elem in (subs) {
        if (type(elem) == 'string)
            subbed_list = [@subbed_list, elem];
        else if (type(elem) == 'integer)
            subbed_list = [@subbed_list, (> fields[elem] <)];
        else
            throw(~type, "Substitution element is of wrong type.");
    }
    return subbed_list;
.

parent #16
object #664

var 1 child_index 11
var 1 owners [#936]
var 1 owned []
var 1 fertile 1
var 16 commands []
var 16 shortcuts []
var 1 inited 1
var 1 manager #664
var 1 writable [#664]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'interfaces

parent #664
object #7801

var 1 dbref 'connection_interface
var 1 child_index 3
var 1 fertile 0
var 1 manager #37
var 1 owned []
var 1 owners [#37]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 16 commands []
var 16 shortcuts []
var 1 inited 1
var 7801 connection 0

method timeout
    // the connection is asking the interface if it should timeout
    // and close the connection.
    return 1;
.

method parse_line
    arg line;
    var cmd;
    
    // don't use the normal parsing system because it involves
    // a bit of overhead.
    catch any {
        while (line && ((line[1]) == " "))
            line = substr(line, 2);
        if (!line) {
            return .null_cmd(line);
        } else {
            cmd = .match_command(line);
            if (cmd)
                return .(cmd[1])(@cmd[2]);
            else
                return .invalid_cmd(line);
        }
    } with handler {
        .send($parse.traceback(traceback()));
        return 'disconnect;
    }
.

method init_connection_interface
    (> .perms(caller(), $root) <);
    connection = 0;
.

method uninit_connection_interface
    (> .perms(caller(), $root) <);
    connection = 0;
.

method connection_going_away
    (> .perms(caller(), $connection) <);
    (> .perms(sender(), connection) <);
    (> .destroy() <);
.

method linelen
    return 79;
.

method new_connection
    arg addr;
    
    (> .perms(caller(), $connection) <);
    connection = sender();
.

method send
    arg what;
    
    connection.send(what);
.

method null_cmd
    arg line;
    
    return 'disconnect;
.

method invalid_cmd
    arg line;
    
    return 'disconnect;
.

method connection
    return connection;
.

method connection_starting
    // called by connection.connect()
.

parent #7801
object #7969

var 1 dbref 'http_interface
var 1 child_index 696
var 1 fertile 1
var 1 manager #37
var 1 owned []
var 1 owners [#37]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 16 commands [["GET *", 'get_cmd]]
var 16 shortcuts []
var 7801 connection 0
var 1 inited 1
var 7969 uri ""
var 7969 header #[]
var 7969 http_version ""
var 7969 method ""
var 7969 status 0

method init_http_interface
    (> .perms(caller(), $root) <);
    status = 0;
    uri = "";
    header = #[];
    http_version = "";
    method = "";
.

method get_cmd
    arg cmd, line;
    
    if (status == 0) {
        if (!line) {
            line = "Invalid use of method GET.";
            .send_response($http.get_error(403, line));
            return 'disconnect;
        }
        line = explode(line);
        if (listlen(line) > 1)
            http_version = line[2];
        else
            http_version = "HTTP/1.0";
        uri = line[1];
        method = "GET";
        status = 1;
    } else {
        line = "Method GET already received!";
        .send_response($http.get_error(400, line));
        return 'disconnect;
    }
.

method invalid_cmd
    arg line;
    var lines;
    
    if (status == 1) {
        // I had it set to be just ":" but I think spaces should be in them.
        line = explode(line, ": ");
        if (listlen(line) == 1)
            line = [@line, ""];
        else if (listlen(line) > 2)
            line = [line[1], $list.to_string(sublist(line, 2))];
        header = $dict.add_elem(header, line[1], line[2]);
    } else {
        line = ("Invalid method: \"" + line) + "\".";
        .send_response($http.get_error(400, line));
        return 'disconnect;
    }
.

method send_response
    arg body, [args];
    var types, buffer, c;
    
    types = [@args, "text/html"][1];
    switch (type(body)) {
        case 'list:
            buffer = $list.to_buffer(body);
        case 'buffer:
            buffer = body;
    }
    c = .connection();
    c.send("HTTP/1.0 200 OK");
    c.send("Server: ColdWeb/0.1");
    c.send("Content-type: " + types);
    c.send("Content-length: " + tostr(buffer_len(buffer)));
    c.send("");
    c.echo(buffer, 'buffer);
    .log_request(buffer_len(buffer));
.

method error
    arg error, str;
    var lines, x;
    
    lines = (| errors[error] |) || ["Oops, server just broke."];
    for x in (lines)
        strsub(x, "%s", str).send_response(lines);
.

method uninit_http_interface
    (> .perms(caller(), $root) <);
    uri = "";
    header = #[];
    http_version = "";
    method = "";
.

method null_cmd
    arg line;
    
    .process_http_method();
    return (> pass(line) <);
.

method log_request
    arg content_length;
    var line, c, agent;
    
    // was going to have this be like the standard logfile, but decided
    // I didn't like that
    c = .connection();
    line = c.address();
    agent = (| ((.header())["User-Agent"])[1] |) || "";
    line = (((((((line + " \"") + method) + " ") + uri) + " ") + http_version) + "\" ") + agent;
    $http_log.log(line);
.

method process_GET
    var path, output, object, line, bin;
    
    (> .perms(sender(), 'this) <);
    
    // Ok, we are going to interpret the URI in funky ways.
    path = explode(uri, "/");
    if (!path) {
        output = ($login.build_html()) + ($http_root_file.retrieve_html());
    } else if (((path[1])[1]) == "~") {
        object = (| $user_db.find(substr(path[1], 2)) |);
        output = (| object.http_request(method, sublist(path, 2)) |);
    } else if ((path[1]) == "objects") {
        object = (| $object.to_dbref(path[2]) |);
        output = (| object.generate_html(@sublist(path, 3)) |);
    } else if (match_begin("bin", path[1])) {
        if (listlen(path) > 2)
            line = $list.to_string(sublist(path, 3));
        if ("?" in (path[2])) {
            line = substr(path[2], ("?" in (path[2])) + 1) + (line || "");
            bin = substr(path[2], 1, ("?" in (path[2])) - 1);
        } else {
            bin = path[2];
        }
        output = (| $http.(tosym("bin_" + bin))(line) |);
    } else {
        object = $http_root_file.find_file([$http_root_file.filename(), @path]);
        output = (| object.retrieve_html() |);
    }
    if (!output) {
        line = ("Unable to find " + uri) + ".";
        output = $http.get_error(404, line);
    }
    
    // intentionally add the tail here, we can slap tCD comments
    // at the end.
    output = output + ["<hr size=4><a href=\"/\"><b>the Cold Dark</b></a></body>"];
    .send_response(output);
.

method process_http_method
    (> .perms(sender(), 'this) <);
    .(tosym("process_" + method))();
.

method header
    return header;
.

parent #1377
object #2786

var 1 child_index 0
var 1 fertile 0
var 1 manager #2786
var 1 owned []
var 1 owners [#47]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 1 inited 1
var 1 dbref 'environment

method environment
    return [];
.

method match_environment
    arg str;
    var obj, env, found, match;
    
    if (!str)
        throw(~objnf, "No \"\" in environment.", str);
    
    // Handle special cases.
    if (str == "me") {
        return this();
    } else if ((str[1]) == "$") {
        obj = (| get_name(tosym(substr(str, 2))) |);
        if (!valid(obj))
            throw(~objnf, "No such object " + str, str);
        return obj;
    } else {
        env = .environment();
        found = [];
        if (str in ["it", "him", "her"]) {
            match = (| sender().match_context(str) |);
            if (!match) {
                for obj in (env) {
                    if ((| obj.gender_context() |) == str)
                        found = [@found, [obj, 1]];
                }
            } else {
                found = [[match, 1]];
            }
        } else {
            for obj in (env) {
                match = obj.match_name(str);
                if (match)
                    found = found + [[obj, match]];
            }
            if (!found) {
                for obj in (env) {
                    match = obj.match_name_aliases(str);
                    if (match)
                        found = found + [[obj, match]];
                }
            }
        }
        if (!found)
            throw(~objnf, ("No \"" + str) + "\" in environment.", str);
        if (listlen(found) == 1) {
            return (found[1])[1];
        } else {
            match = $list.min(@$list.slice(found, 2));
            if (($list.count(match, $list.slice(found, 2))) == 1)
                return (found[match in ($list.slice(found, 2))])[1];
            else
                throw(~ambig, ("\"" + str) + "\" can match more than one object", [$list.slice(found, 1), str]);
        }
    }
.

method local_to_environment
    arg obj;
    
    return obj in (.environment());
.

parent #1
object #12

var 1 child_index 22
var 1 owners [#936]
var 1 fertile 1
var 1 inited 1
var 1 owned [#49, #45, #51, #48, #46, #47]
var 1 manager #12
var 1 writable [#12]
var 1 readable ['parameters, 'methods, 'code]
var 1 info ["$utilities is the parent of all utility objects storing classes of data-minimulating methods, such as $string and $list. It does not define anything, but merely serves as the parent to these objects."]
var 1 dbref 'utilities

parent #12
object #43

var 1 child_index 0
var 1 owners [#43, #0]
var 1 fertile 0
var 1 inited 1
var 43 alphabet "abcdefghijklmnopqrstuvwxyz"
var 43 numbers "1234567890"
var 43 non_alphanumeric "!@#$%^&*()_+-=~`'{}[]|/?\"\\,.<>;: "
var 1 owned [#43]
var 1 manager #43
var 1 writable [#43]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'string

method left
    arg str, width, [fchar];
    
    // will NOT chop off 'str' if it is longer than width, use pad() for that.
    if (fchar)
        return str + ((strlen(str) < width) ? pad("", width - strlen(str), fchar[1]) | "");
    else
        return str + ((strlen(str) < width) ? pad("", width - strlen(str)) | "");
.

method fill
    arg n, [args];
    var fill, x;
    
    // same as pad("", n, [args]);
    fill = [@args, " "][1];
    return pad("", n, fill);
.

method center
    arg text, len, [args];
    var lfill, rfill, textlen, padlen;
    
    // args[1] == string to center
    // args[2] == integer of width to center in
    // args[3] <op> == what to fill the left|right side with.
    // args[4] <op> == what to fill the right side with.
    lfill = ((listlen(args) >= 1) && (args[1])) || " ";
    rfill = (listlen(args) >= 2) ? args[2] | ((lfill == " ") ? "" | lfill);
    textlen = strlen(text);
    padlen = (len - textlen) / 2;
    if (textlen < len)
        return ((.fill(padlen, lfill)) + text) + (rfill ? .fill(padlen, rfill) | "");
    else
        return (len > 0) ? text | pad(text, len);
.

method trim
    arg string, [args];
    var rl, chars, type;
    
    // remove leading and trailing characters.
    // if args includes a string, it takes that as the strip string.
    // args can also include symbols of what edge to trim: 'left 'right (or both)
    // left and right defaults on.
    rl = [];
    while (args) {
        type = type(args[1]);
        if (type == 'string)
            chars = args[1];
        else if (type == 'symbol)
            rl = [@rl, args[1]];
        args = sublist(args, 2);
    }
    if (!chars)
        chars = " ";
    if (!rl)
        rl = ['left, 'right];
    if ('left in rl) {
        // strip from left
        while (string && ((string[1]) in chars))
            string = substr(string, 2);
    }
    if ('right in rl) {
        // strip from right
        while (string && ((string[strlen(string)]) in chars))
            string = substr(string, 1, strlen(string) - 1);
    }
    return string;
.

method to_list
    arg str, [sep];
    var result, list;
    
    // separate a string into a list of strings, breaking wherever 'sep' appears.
    // if not provided, sep defaults to a comma.
    // One word of warning.  sep should not contain an asterisk.  If it does,
    // this routine will separate the string oddly, most likely losing bits.
    if (!str)
        return [];
    sep = ("*" + (sep ? sep[1] | ",")) + "*";
    list = [];
    while (1) {
        result = match_pattern(sep, str);
        if (result) {
            list = list + [result[1]];
            str = result[2];
        } else {
            return list + [str];
        }
    }
.

method right
    arg str, width, [fchar];
    
    // will not chop off 'str' if it is longer than width (unlike pad())
    if (fchar)
        return pad("", width - strlen(str), fill_char[1]) + str;
    else
        return pad("", width - strlen(str)) + str;
.

method alphabet
    return alphabet;
.

method numbers
    return numbers;
.

method capitalize
    arg string;
    
    // Capitalizes the first character of a word.
    return uppercase(string[1]) + substr(string, 2);
.

method is_numeric
    arg string;
    
    return toint(string) || (string == "0");
.

method a_or_an
    arg string;
    
    if (lowercase(string[1]) in "aeiou")
        return "an";
    return "a";
.

method strip
    arg string, strip;
    var new_str, char;
    
    // strips all of "strip" characters from the string
    // if "strip" is -1 it will use .non_alphanumeric()
    if ((type(string) != 'string) || ((type(strip) != 'string) && (strip != (-1))))
        throw(~type, "First argument must be a string, second can be -1");
    new_str = "";
    if (strip == (-1))
        new_str = non_alphanumeric;
    for char in [1 .. strlen(string)] {
        if (!((string[char]) in strip))
            new_str = new_str + (string[char]);
    }
    return new_str;
.

method non_alphanumeric
    return non_alphanumeric;
.

method chop
    arg str, len, [end];
    
    // chops string off strlen(end) characters before len and appends len
    end = [@end, "..."][1];
    if (strlen(str) < len)
        return str;
    if (strlen(str) < strlen(end))
        return str;
    return pad(str, len - strlen(end)) + end;
.

method replace
    arg string, replace, [char];
    var new_str, character;
    
    // replaces 'replace' with the character in 'char'
    // if 'replace' is -1 will use .non_alphanumeric();
    if ((type(string) != 'string) || ((type(replace) != 'string) && (strip != (-1))))
        throw(~type, "First argument must be a string, second can be -1");
    char = [@char, " "][1];
    new_str = "";
    if (replace == (-1))
        new_str = non_alphanumeric;
    for character in [1 .. strlen(string)] {
        if (!((string[character]) in replace))
            new_str = new_str + (string[character]);
        else
            new_str = new_str + char;
    }
    return new_str;
.

method explode_english_list
    arg line, [opts];
    var x, output, tmp;
    
    // explodes an english list ("foo, bar and zoo").
    line = explode(line, ",");
    output = [];
    for x in (line) {
        x = .trim(x);
        if ((| substr(x, 1, 3) |) == "and")
            output = [@output, .trim(substr(x, 4))];
        else
            output = [@output, x];
    }
    
    // check the last element, if they didn't specify  'noand
    if (!('noand in opts)) {
        line = explode(output[listlen(output)]);
        tmp = "";
        for x in [1 .. listlen(line)] {
            if ((line[x]) == "and") {
                output = delete(output, listlen(output));
                if (tmp)
                    output = [@output, tmp];
                tmp = $list.to_string(sublist(line, x + 1));
                if (tmp)
                    output = [@output, tmp];
    
                // only bother with the first "and"
                break;
            }
            tmp = (tmp + (tmp ? " " | "")) + (line[x]);
        }
    }
    return output;
.

method explode_delimited
    arg str, left, right;
    var pattern, parsed, matched, match_num, match_result;
    
    // parse str looking for anything surrounded by left and right
    // ;$string.explode_delimited("foo%[bar]baz", "%[", "]")
    // => [["foo", 1, "baz"], ["bar"]]
    pattern = ((("*" + left) + "*") + right) + "*";
    parsed = [];
    matched = [];
    match_num = 0;
    while (str) {
        match_result = match_pattern(pattern, str);
        if (match_result) {
            match_num = match_num + 1;
            parsed = [@parsed, match_result[1], match_num];
            matched = [@matched, match_result[2]];
            str = match_result[3];
        } else {
            parsed = [@parsed, str];
            str = "";
        }
    }
    return [parsed, matched];
.

method wrap_line
    arg string, length, [stuff];
    var output, cutoff, firstline, prefix;
    
    // takes string and wraps it by words, compared to length, returns a list.
    prefix = [@stuff, ""][1];
    firstline = [@stuff, 0, 0][2];
    output = [];
    length = length - strlen(prefix);
    if (firstline)
        string = prefix + string;
    while (strlen(string) > length) {
        cutoff = .rindex(substr(string, 1, length), " ");
        output = [@output, substr(string, 1, cutoff - 1)];
        string = prefix + substr(string, cutoff + 1);
    }
    return [@output, string];
.

method rindex
    arg string, index;
    var loc, rest;
    
    // returns the first occurance of index starting from the end of the string,
    // and moving to the beginning.
    loc = index in string;
    rest = loc && substr(string, loc + 1);
    while (loc && (index in rest)) {
        loc = loc + (index in rest);
        rest = loc && substr(string, loc + 1);
    }
    return loc;
.

method match_sub_tag
    arg string, tag;
    var x, expl, output, match, matches;
    
    // matches a string between 'tag' and " " in a larger string against
    // the sender's environment.  If a match is found it subs the match.name
    // with the string, otherwize it lets it pass through with the tag, ie:
    // .match_sub_tag("this test #of something #note or other");
    // => "this test #of something Note of sorts or other"
    // where the note is in the sender's environment.
    expl = .explode_delimited(string + " ", tag, " ");
    matches = expl[2];
    expl = expl[1];
    output = "";
    for x in (expl) {
        if (type(x) == 'integer) {
            match = (| sender().match_environment(matches[x]) |);
            if (match)
                output = (output + (match.namef())) + " ";
            else
                output = ((output + tag) + (matches[x])) + " ";
        } else {
            output = output + x;
        }
    }
    return substr(output, 1, strlen(output) - 1);
.

method search_pat
    arg pat, text, [start_at];
    var line, match_result, type;
    
    line = 1;
    type = [@start_at, 'pattern, 'pattern][2];
    if (start_at) {
        line = start_at[1];
        start_at = [@start_at, 1, 1][2];
        if (type == 'pattern)
            match_result = match_pattern(pat, substr(text[line], line));
        else
            match_result = match_regexp(pat, substr(text[line], line));
        if (match_result != 0) {
            if (type == 'pattern) {
                pat = $string.pat_sub(pat, match_result);
                return [line, (start_at + pat) in substr(text[line], start_at)];
            } else {
                return [line, start_at + ((match_result[1])[1])];
            }
        }
        line = line + 1;
    }
    while (line <= listlen(text)) {
        if (type == 'pattern)
            match_result = match_pattern(pat, text[line]);
        else
            match_result = match_regexp(pat, text[line]);
        if (match_result != 0) {
            if (type == 'pattern) {
                pat = $string.pat_sub(pat, match_result);
                return [line, pat in (text[line])];
            } else {
                return [line, (match_result[1])[1]];
            }
        }
        line = line + 1;
    }
    throw(~strnf, "String not found in text.");
.

method pat_sub
    arg pat, subs;
    var wc_idx;
    
    // wc_idx == wildcard index
    while (subs) {
        wc_idx = "*" in pat;
        if (wc_idx == 1)
            pat = (subs[1]) + substr(pat, 2);
        else if (wc_idx == strlen(pat))
            pat = substr(pat, 1, wc_idx - 1) + (subs[1]);
        else
            pat = (substr(pat, 1, wc_idx - 1) + (subs[1])) + substr(pat, wc_idx + 1);
        subs = delete(subs, 1);
    }
    return pat;
.

method is_boolean
    arg str;
    
    if (match_begin("yes", str) || (match_begin("true", str) || (str == "1")))
        return 1;
    else if (match_begin("no", str) || (match_begin("false", str) || (str == "0")))
        return 0;
    else
        return -1;
.

parent #7791
object #7792

var 1 dbref 'connection
var 1 child_index 0
var 1 fertile 1
var 1 manager #37
var 1 owned []
var 1 owners [#37]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 7791 buffer `[]
var 7791 ip ""
var 7791 hostname ""
var 7791 port 0
var 7791 socket 0
var 7791 active 0
var 1 inited 1
var 7792 daemon 0
var 7792 interface 0
var 7792 receive_internal 0
var 7792 timeout 0

method receive
    arg line, status;
    
    (> .perms(sender(), this(), @$sys.system(), daemon) <);
    if ((status != 'external) && (!receive_internal))
        return;
    if ((interface.parse_line(line)) == 'disconnect)
        .close();
.

method init_inbound_connection
    (> .perms(caller(), $root) <);
    daemon = 0;
    interface = 0;
.

method uninit_inbound_connection
    (> .perms(caller(), $root) <);
    daemon = 0;
    interface = 0;
.

method initialize_connection
    arg interface_parent, seconds;
    var addr;
    
    (> .perms(sender()) <);
    
    // spawn this now, if they want to connect to a permanent interface
    // the spawned one can do that (such as a user object)
    addr = .address();
    daemon = sender();
    interface = interface_parent.spawn();
    .add_writer(interface);
    interface.new_connection(addr);
    interface.set_manager(interface);
    timeout = seconds;
    .set_active(1);
.

method set_interface_object
    arg obj;
    
    // called by an interface object to change interfaces.
    (> .perms(sender(), 'this) <);
    interface = obj;
.

method close
    (> pass() <);
    (| daemon.connection_ending() |);
    (> .destroy() <);
.

method init_connection
    (> .perms(caller(), $root) <);
    timeout = -1;
    daemon = 0;
    interface = 0;
.

method uninit_connection
    (> .perms(caller(), $root) <);
    timeout = -1;
    daemon = 0;
    (| interface.connection_going_away() |);
.

method connect
    arg [args];
    
    (> pass(@args) <);
    daemon.connection_starting();
    interface.connection_starting();
    if (timeout >= 0)
        (| $scheduler.add_task(timeout, 'timeout) |);
.

method disconnect
    (> pass() <);
    daemon.connection_ending();
.

method timeout
    (> .perms(sender(), 'this) <);
    if (interface.timeout()) {
        .send(("Timeout (" + tostr(timeout)) + ").");
        .close();
    }
.

method address
    var addr;
    
    // return hostname or ip
    if (!('parameters in (.is_readable_by(sender()))))
        throw(~perm, "Sender does not have permission to get parameters.");
    addr = .hostname();
    if (!addr)
        addr = .ip();
    return addr;
.

method change_interface_object
    arg obj;
    var old_interface;
    
    // called by an interface object to change interfaces.
    (> .perms(sender(), interface) <);
    old_interface = interface;
    interface = obj;
    old_interface.connection_going_away();
    interface.new_connection(.address());
.

parent #1377
object #1139

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 1 inited 1
var 1 manager #1139
var 1 writable [#1139]
var 1 readable ['parameters, 'methods, 'code]
var 17 prose #[]
var 15 verbs 0
var 1 dbref 'event_handler

method event
    arg frob;
    
.

method announce_event
    arg frob;
    var x;
    
    for x in (.environment())
        (| x.event(frob) |);
.

parent #1377
object #15

var 15 verbs #[]
var 1 child_index 0
var 1 owners [#936]
var 1 fertile 1
var 1 inited 1
var 1 owned []
var 1 manager #15
var 1 writable [#15]
var 1 readable ['parameters, 'methods, 'code]
var 1 info ["$has_verbs defines all the functionality necessary for an object to have verbs, or methods activated by commands typed by a user object which is not this. Verbs are useful for making certain functionality only available when an object is present, and for allowing different objects to have identicle verbs with different internal meanings (turn alarm to 6am vs. turn safe to 10)."]
var 1 dbref 'has_verbs

method init_has_verbs
    if (caller() != $root)
        throw(~perm, "Caller is not $root.");
    verbs = #[];
.

method uninit_has_verbs
    var template;
    
    if (caller() != $root)
        throw(~perm, "Caller is not $root.");
    verbs = 0;
    for template in (dict_keys(verbs))
        $verb_cache.object_undefined_verb(template);
.

method verb_templates
    return dict_keys(verbs);
.

method add_verb
    arg template, method, remote;
    var words, pos;
    
    if (!(.is_writable_by(sender())))
        throw(~perm, "Sender is not an owner.");
    
    // Check argument types.
    if (type(template) != 'string)
        throw(~type, "Template is not a string.");
    if (type(method) != 'symbol)
        throw(~type, "Method obj_name is not a symbol.");
    if ((remote != 'remote) && (remote != 'noremote))
        throw(~type, "Remote specifier is neither 'remote nor 'noremote");
    
    // Make sure there's exactly one "%this" in the template, as a word by
    // itself.
    words = explode(template);
    if (((words[1]) == "%this") || (((words[1]) == "*") || ((words[1]) == "*=*")))
        throw(~template, "Template begins with wildcard.");
    pos = "%this" in words;
    if ((!pos) || ("%this" in sublist(words, pos + 1)))
        throw(~template, "Template does not contain exactly one \"%this\".");
    
    // Add the verbs to the dictionary, and notify $verb_cache.
    verbs = dict_add(verbs, template, [method, remote]);
    if (remote == 'remote)
        $verb_cache.del_template(template);
.

method del_verb
    arg template;
    var verb_info;
    
    if (!(.is_writable_by(sender())))
        throw(~perm, "Sender is not an owner.");
    catch ~keynf {
        verb_info = verbs[template];
        verbs = dict_del(verbs, template);
        (| $verb_cache.del_template(template) |);
    } with handler {
        throw(~verbnf, ("No verb with template " + tostr(template)) + ".");
    }
.

method verb_info
    disallow_overrides;
    arg template;
    var verb_info, anc;
    
    if (dict_contains(verbs, template))
        return verbs[template];
    for anc in (ancestors()) {
        verb_info = (| anc.local_verb_info(template) |);
        if (verb_info)
            return verb_info;
    }
    throw(~verbnf, "No verb with template " + template);
.

method local_verb_info
    disallow_overrides;
    arg template;
    
    catch ~keynf {
        return verbs[template];
    } with handler {
        throw(~verbnf, "No verb with template " + template);
    }
.

method verbs
    return verbs;
.

method all_verbs
    var p, vrblist, pv;
    
    vrblist = #[];
    for p in (.ancestors()) {
        pv = (| p.verbs() |);
        if (pv)
            vrblist = $dict.union(vrblist, pv);
        if (p == definer())
            break;
    }
    return vrblist;
.

parent #1377
object #2787

var 1 child_index 0
var 1 fertile 1
var 1 manager #2787
var 1 owned []
var 1 owners [#47]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 1 inited 1
var 1 dbref 'named
var 2787 name ['uniq, "Named Object"]
var 2787 name_aliases 0

method set_name
    arg new_name, [args];
    var proper;
    
    // .set_name(new_name, ['proper|'unique]) (default proper).
    // ['prop, "Name"] => proper, no indefinite/definite articles.
    // ['uniq, "Name"] => unique, normal indefinite/definite articles.
    .perms(sender());
    if (type(new_name) != 'string)
        throw(~type, "New name must be given as a string.");
    
    // this will not catch them all, but we can try.
    if ((" a " in new_name) || (" the " in new_name))
        throw(~bad_name, "Do not include articles in a name");
    
    //
    proper = [@args, 'prop][1];
    name = [proper, new_name];
.

method name_aliases
    return name_aliases;
.

method add_name_alias
    arg alias;
    
    .perms(sender());
    name_aliases = [@name_aliases, alias];
.

method del_name_alias
    arg alias;
    
    .perms(sender());
    name_aliases = setremove(name_aliases, alias);
.

method init_named
    var dbref;
    
    .perms(caller(), $root);
    dbref = tostr(dbref);
    name = ['uniq, tostr(dbref)];
    name_aliases = [];
.

method match_name
    arg str;
    
    return match_begin(.name('none), str);
.

method name
    arg [article];
    
    article = [@article, 'indef][1];
    if ((name[1]) == 'uniq) {
        switch (article) {
            case 'indef:
                return (($string.a_or_an(name[2])) + " ") + (name[2]);
            case 'def:
                return "the " + (name[2]);
        }
    }
    return name[2];
.

method match_name_aliases
    arg str;
    
    return str in name_aliases;
.

method namef
    arg [args];
    
    if (!args)
        args = [['name, 'def]];
    if ((args[1]) == 'ref) {
        if (.has_ancestor($named))
            args = [['name], " (", ['dbref], ")"];
        else
            args = [['dbref]];
    } else if ((args[1]) == 'xref) {
        if (.has_ancestor($named))
            args = [['dbref], " (", ['name], ")"];
        else
            args = [['dbref]];
    }
    return pass(@args);
.

parent #15
parent #2787
object #17

var 17 prose #[]
var 1 child_index 0
var 1 owners [#936]
var 1 fertile 0
var 15 verbs #[["l?ook at %this", ['look_vrb, 'noremote]], ["l?ook %this", ['look_vrb, 'noremote]], ["@examine|examine %this", ['examine_vrb, 'remote]]]
var 1 inited 1
var 1 owned []
var 1 manager #17
var 1 writable [#17]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'described
var 2787 name ['uniq, "Generic Described Object"]
var 2787 name_aliases []

method init_described
    .perms($root, caller());
    prose = #[];
.

method description
    arg actor, [exclude];
    var out;
    
    // similar to MOO's :look_self()
    // meant to be changed by descendants, if they so desire to.
    return [.name('def), @.prose('short)];
.

method look_vrb
    arg vrb, [args];
    var actor;
    
    actor = sender();
    actor.tell(.description(actor, actor));
.

method prose
    arg [type];
    
    type = [@type, 'short][1];
    switch (type) {
        case 'literal:
            return prose;
        default:
            return (| prose[type] |) || ((| prose['short] |) || ["You see nothing special."]);
    }
.

method descriptionf
    arg actor, exclude, [args];
    var out, part, type;
    
    // lists should be ['methodname, args for method]
    // symbols are shortcuts, to be defined on descendants.
    out = [];
    for part in (args) {
        type = type(part);
        switch (type) {
            case 'list:
                out = out + ((| .(part[1])(@sublist(part, 2)) |) || []);
            case 'symbol:
                // ignore them, they should have been dealt with by now.
        }
    }
    return out;
.

method set_prose
    arg ptype, new_prose;
    
    // ptype should be either 'short or 'long
    // prose should be a list of strings
    .perms(sender(), 'manager);
    if (type(ptype) != 'symbol)
        throw(~type, "Prose type can be either 'short or 'long.");
    if (type(new_prose) != 'list)
        throw(~type, "Prose must be given as a list of strings.");
    prose = dict_add(prose, ptype, new_prose);
.

method examine_vrb
    arg vrb, [args];
    var actor;
    
    actor = sender();
    actor.tell(.name());
    actor.tell(.prose('long));
.

parent #2787
object #1179

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 15 verbs 0
var 1 inited 1
var 1179 gender 0
var 17 prose #[]
var 1 manager #1179
var 1 writable [#1179]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'gendered
var 2787 name ['uniq, "The Generic Gendered Object"]
var 2787 name_aliases []

method gender_context
    return gender.pronoun('po);
.

method init_gendered
    .perms($root, caller());
    gender = $gender_neuter;
.

method set_gender
    arg gendr;
    
    .perms(sender(), 'manager);
    if ((type(gendr) != 'dbref) && (!(gendr in ($gender.children()))))
        throw(~invgender, ($data.unparse(gendr)) + " is not a valid gender object type.");
    gender = gendr;
.

method gender
    return gender;
.

parent #1178
parent #1139
parent #17
parent #1179
parent #2786
object #1387

var 1 child_index 0
var 1 fertile 0
var 1 manager #7232
var 1 owners [#7232, #1387]
var 1 writable [#1387, #37]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned [#1387, #1388, #4309, #4348, #5205, #7245, #7248, #7261]
var 15 verbs #[]
var 17 prose #[]
var 1 inited 1
var 1179 gender #1182
var 1387 visibility 0
var 1 dbref 'physical
var 2787 name ['uniq, "Generic Physical Object"]
var 2787 name_aliases []

method set_visibility
    arg val;
    
    .perms(sender(), 'manager);
    if (!(type(val) == 'integer))
        throw(~type, "Visibility must be set as a positive or negative integer.");
    visibility = val;
.

method visibility
    return visibility;
.

parent #1387
parent #16
object #19

var 19 contents []
var 1 child_index 0
var 1 owners [#936]
var 1 fertile 1
var 15 verbs #[]
var 1 inited 1
var 23 location #22
var 1 owned []
var 1179 gender #1182
var 17 prose #[]
var 1 manager #19
var 1 writable [#19]
var 1 readable ['parameters, 'methods, 'code]
var 16 commands []
var 16 shortcuts []
var 1 dbref 'location
var 2787 name ['uniq, "Generic Container Object"]
var 2787 name_aliases []

method init_location
    .perms(caller(), $root);
    contents = [];
.

method uninit_location
    var obj;
    
    .perms(caller(), $root);
    for obj in (contents)
        obj.move_to($nowhere);
.

method contents
    return contents || [];
.

method contains
    arg obj;
    
    return (obj in (.contents())) ? 1 | 0;
.

method put
    arg obj;
    
    obj._move_to(this());
.

method take
    arg obj;
    
    if (!(obj in contents))
        throw(~objnf, ("Object (" + toliteral(obj)) + ") not in contents.");
    obj._move_to(sender());
.

method will_arrive
    arg old_place;
    
    if (caller() != $located)
        throw(~perm, "Caller is not $located.");
.

method will_leave
    arg place;
    
    if (caller() != $located)
        throw(~perm, "Caller is not $located.");
.

method did_arrive
    arg place;
    
    if (caller() != $located)
        throw(~perm, "Caller is not $located.");
.

method did_leave
    arg place;
    
    if (caller() != $located)
        throw(~perm, "Caller is not $located.");
.

method add_sender_to_contents
    disallow_overrides;
    
    if (caller() != $located)
        throw(~perm, "Caller is not $located.");
    if ((sender().location()) != this())
        throw(~location, "Sorry, but you're not here.");
    contents = setadd(.contents(), sender());
.

method del_sender_from_contents
    disallow_overrides;
    
    if (caller() != $located)
        throw(~perm, "Caller not an agent of located protocol.");
    contents = setremove(contents, sender());
.

method validate_contents
    var obj, newcont;
    
    if (!(.is_writable_by(sender())))
        throw(~perm, "Must be an owner to validate contents");
    newcont = [];
    for obj in (contents) {
        if (valid(obj) && (obj.has_ancestor($located)))
            newcont = setadd(newcont, obj);
    }
    contents = newcont;
.

method environment
    return [this()] + contents;
.

method add_to_contents
    disallow_overrides;
    arg what;
    
    if (caller() != $located)
        throw(~perm, "Caller is not $located.");
.

method contents_accept_mail
    return 1;
.

method realm
    arg [args];
    var loc;
    
    loc = "";
    if ((| .location() |))
        loc = (.location()).realm();
    return ((loc + "[") + (.namef())) + "]";
.

method realm_name
    return "";
.

method local_verb_templates
    var obj, out;
    
    out = [];
    for obj in (.contents()) {
        if (obj.has_ancestor($has_verbs))
            out = out + dict_keys(obj.all_verbs());
    }
    return out;
.

parent #675
parent #15
object #7261

var 1 dbref 'public
var 1 child_index 0
var 1 fertile 1
var 1 manager #7232
var 1 owned []
var 1 owners [#7232, #1387, #1388]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 1 inited 1
var 7261 public []
var 15 verbs #[["@public on %this is *", ['public_vrb, 'remote]]]

method init_public
    .perms(caller(), $root);
    public = ['readable];
.

method is_publicly
    arg what;
    
    return what in public;
.

method set_public
    arg what;
    var x, valid;
    
    if (sender() != this())
        .perms(sender(), 'manager);
    if (type(what) == 'symbol) {
        if (what in public)
            return;
        what = [@public, what];
    }
    if (type(what) != 'list)
        throw(~type, toliteral(what) + " is an invalid type.");
    public = what;
.

method public
    return public;
.

method public_vrb
    arg vrb, on, this, is, args;
    var x, syn, p, who, opts;
    
    .perms(sender(), 'manager);
    syn = ((vrb + " on ") + this) + " <+/-[r|w]>";
    who = sender();
    if (!args)
        $parse.tell_error(["Must specify either readable or writable.", ("Current Public permissions: " + ($list.to_english(public))) + "."], syn, who);
    opts = #[["r", [1, 0]], ["w", [0, 0]]];
    args = $parse.options(args, opts);
    opts = args[2];
    args = args[1];
    if ((!((opt["r"])[1])) && ('readable in public))
        .set_public(setremove(public, 'readable));
    else if (((opt["r"])[1]) && (!('readable in public)))
        .set_public(public + ['readable]);
    if ((!((opt["w"])[1])) && ('writable in public))
        .set_public(setremove(public, 'writable));
    else if (((opt["w"])[1]) && (!('writable in public)))
        .set_public(public + ['writable]);
    sender().tell(("Public perms changed to: " + ($list.to_english(public))) + ".");
.

parent #19
parent #7261
object #2679

var 1 child_index 88
var 1 fertile 0
var 1 manager #37
var 1 owned []
var 1 owners [#47]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 1 inited 1
var 1179 gender #1182
var 17 prose #[]
var 15 verbs #[]
var 16 commands [["l?ook", 'look_cmd]]
var 16 shortcuts []
var 1 dbref 'place
var 2787 name ['uniq, "place"]
var 2787 name_aliases []
var 2679 realm 0
var 2679 exits 0
var 2679 coordinates 0
var 7261 public ['readable]

method init_place
    .perms($root, caller());
    exits = [];
    realm = $realm_of_creation.new();
    coordinates = #[];
    .set_public('location);
.

method uninit_place
    var x;
    
    .perms($root, caller());
    for x in (exits)
        (| x.destroy() |);
    (| realm.place_destroyed(this()) |);
    for x in (.area())
        (| x.place_destroyed(this()) |);
    (| $place_db.place_destroyed() |);
.

method environment
    return pass() + exits;
.

method description
    arg actor, [exclude];
    var output, dark;
    
    output = pass(actor, exclude);
    output = output + (._desc_contents(actor, exclude));
    output = output + (._desc_exits(actor, exclude));
    return output;
.

method exits
    return exits;
.

method add_exit
    disallow_overrides;
    arg coord1, coord2;
    var exit;
    
    // coordinates are not standard x/y, but radial/azimuth
    .perms($exit, caller());
    exit = sender();
    (> ._add_exit(exit) <);
    (> ._add_coordinate(exit, coord1, coord2) <);
    (> ._add_coordinate(exit.dest(), coord1, coord2) <);
.

method _add_exit
    disallow_overrides;
    arg obj;
    
    // use .add_exit()
    .perms(sender(), 'this);
    exits = [@exits, obj];
.

method _del_exit
    disallow_overrides;
    arg obj;
    
    // use .del_exit()
    .perms(sender(), 'this);
    exits = setremove(exits, obj);
.

method del_exit
    disallow_overrides;
    var exit;
    
    exit = sender();
    .perms(caller(), $exit);
    (| ._del_exit(exit) |);
    (| ._del_coordinate(exit) |);
    (| ._del_coordinate(exit.dest()) |);
.

method _add_coordinate
    disallow_overrides;
    arg obj, coord1, coord2;
    
    .perms(sender(), 'this);
    
    // should only be called from inside this object.
    coordinates = dict_add(coordinates, obj, [coord1, coord2]);
.

method _del_coordinate
    disallow_overrides;
    arg obj;
    
    .perms(sender(), 'this);
    
    // should only be called from inside this object.
    coordinates = dict_del(coordinates, obj);
.

method did_connect
    if ((.visibility()) >= 0)
        .announce((sender().namef()) + " has connected.", sender());
.

method did_disconnect
    if ((.visibility()) >= 0)
        .announce((sender().namef()) + " has disconnected.", sender());
.

method look_cmd
    arg cmd;
    var actor, text;
    
    sender().tell(.description(sender(), sender()));
.

method realm
    arg [args];
    var tmp, r;
    
    return realm;
.

method announce
    arg str, [except];
    var obj;
    
    for obj in (.contents()) {
        if (!(obj in except))
            (| obj.tell(str) |);
    }
.

method did_housekeep
    arg who;
    var message;
    
    // catch ~msgnf {
    catch any {
        message = .get_message('housekeeper);
    } with handler {
        message = "The housekeeper hauls %N away";
    }
    
    // this will have to do until we get a correct action setup
    .announce(strsub(message, "%N", who.namef()));
.

method set_name
    arg [args];
    var old_name;
    
    old_name = .name();
    (> pass(@args) <);
    (| $place_db.room_changed_name(old_name) |);
.

method set_realm
    arg frob_class, where;
    
    .perms(sender());
    if (!(frob_class.has_ancestor($frob_class)))
        throw(~type, "Realm must be submitted as a frob class object.");
    realm = frob_class.new([where]);
.

method examine_vrb
    arg vrb, [args];
    var actor, text;
    
    actor = sender();
    text = .description(actor, [actor], 'desc_name, 'long_description, '_desc_contents, '_desc_long_exits);
    actor.tell(text);
.

method _desc_contents
    arg actor, dont_show;
    var users, objects, output, obj, line;
    
    // called by .description
    .perms(sender(), 'this);
    users = [];
    objects = [];
    for obj in (.contents()) {
        if ((!(obj in dont_show)) || (| !(obj.obvious()) |)) {
            if (obj.has_ancestor($body))
                users = [@users, obj.namef('nactivity)];
            else
                objects = [@objects, obj.namef()];
        }
    }
    output = [];
    
    // we will get these both using @options eventually.
    if (users) {
        line = ($list.to_english(users)) + " ";
        line = (line + ((listlen(users) > 1) ? "are" | "is")) + " here.";
        output = [@output, line];
    }
    if (objects) {
        line = "You see ";
        line = (line + ($list.to_english(objects))) + " here.";
        output = [@output, line];
    }
    return output;
.

method _desc_exits
    arg actor, mode;
    
    .perms(sender(), 'this);
    return .visible_exits_formatted(actor, 'verbose);
.

method visible_exits
    var obv, exit;
    
    obv = [];
    for exit in (.exits()) {
        if ((exit.visibility()) >= (.visibility()))
            obv = [@obv, exit];
    }
    return obv;
.

method area
    var out, x;
    
    out = [];
    for x in (dict_keys(coordinates)) {
        if (x.has_ancestor($place))
            out = out + [x];
    }
    return out;
.

method realm_name
    return (((realm.name()) + " [") + (.name())) + "]";
.

method will_attach
    arg type, obj;
    
    // callable only from the methods on $exit, so don't worry too much.
    switch (type) {
        case 'source:
            .perms(obj);
        case 'dest:
            if ((!(.is_publicly('location))) && (!(| .perms(obj) |)))
                throw(~perm, ("Place refuses to link with " + (obj.namef('ref))) + ".");
    }
.

method visible_exits_formatted
    arg actor, how;
    var output, ex, exits, line;
    
    exits = .visible_exits();
    switch (how) {
        case 'none:
            return [];
        case 'brief:
            if (!exits)
                return [];
            return ["Exits: " + ($list.to_english($list.map(exits, 'namef), "none"))];
        case 'average:
            output = [];
            for ex in (exits) {
                line = (ex.namef()) + " (";
                line = line + ($list.to_english(ex.name_aliases(), "no aliases"));
                output = [@output, line];
            }
            return output ? ["Exits: " + ($list.to_english(output))] | [];
        case 'long:
            output = [];
            for ex in (exits)
                output = [@output, ((("  " + (ex.namef())) + " to: ") + ((ex.dest()).namef())) + "."];
            return output ? ["Exits: ", @$list.lcolumnize(output, actor.linelen())] | [];
        case 'verbose:
            output = [];
            for ex in (exits)
                output = [@output, ex.description(actor, 'short)];
            return output ? [$list.to_string(@output)] | [];
    }
.

method place_destroyed
    arg place;
    
    // announces when a place is destroyed
    .perms(caller(), $place, $realms_class);
    (| ._del_coordinate(place) |);
.

parent #2679
object #247

var 1 child_index 0
var 1 owners [#936]
var 1 fertile 0
var 16 commands []
var 16 shortcuts []
var 15 verbs #[]
var 19 contents [#5203, #7232]
var 1 inited 1
var 1231 name_aliases []
var 1 owned []
var 1179 gender #1182
var 17 prose #[]
var 1 manager #247
var 1 writable [#247]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'body_cave
var 2787 name ['uniq, "Body Cave"]
var 2787 name_aliases []
var 2679 exits []
var 2679 realm <#2717, ['interior]>
var 2679 coordinates #[]

parent #675
object #1093

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 1 inited 1
var 1 manager #1093
var 1 writable [#1093]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'filters

method compress
    arg input;
    var e, output;
    
    // only goes 1 element deep--sorry, anybody sending anything past that will
    // be shot.
    output = [];
    if (type(input) == 'list) {
        for e in (input) {
            if (type(e) == 'list)
                output = [@output, @e];
            else
                output = [@output, e];
        }
    } else {
        output = [input];
    }
    return output;
.

parent #1093
object #1095

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 1 inited 1
var 1 manager #1095
var 1 writable [#1095]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'epic_filter

method old_filter
    arg input;
    var output, x, z, line;
    
    // this filter MUST be first in the filters list..
    output = [];
    input = .compress(input);
    for z in (input) {
        line = [];
        z = ($string.explode_delimited(z, "<", ">"))[1];
        for x in (z) {
            if (type(x) == 'string)
                line = [@line, x];
        }
        output = [@output, $list.to_string(line, "")];
    }
    return output;
.

method filter
    arg what;
    var tags;
    
    $jeff.debug('filter, what);
    if (type(what) != 'frob)
        return what;
    if (!(class(what) in [$ctext]))
        return what;
    $jeff.debug('frob);
    what = what.evaluate(sender());
    $jeff.debug(what);
    return what;
.

parent #664
parent #15
object #4309

var 1 dbref 'user_data
var 1 child_index 0
var 1 fertile 0
var 1 manager #7232
var 1 owned []
var 1 owners [#7232, #1387, #1388]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 16 commands [["@user-data * my * is|are *", 'data_is_cmd], ["@user-data *", 'data_cmd]]
var 16 shortcuts []
var 1 inited 1
var 4309 valid_settings #[["real name", 'real_name], ["email", 'email], ["address", 'address], ["affiliation", 'affiliation], ["position", 'position], ["location", 'location], ["interests", 'interests], ["plan", 'plan], ["projects", 'projects], ["see also", 'see_also]]
var 4309 user_data #[]
var 15 verbs #[["finger %this", ['finger_vrb, 'remote]]]

method init_user_info
    .perms(caller(), $root);
    user_data = #[['real_name, [1, "???"]], ['email, [1, "???"]]];
.

method data_on
    arg data;
    
    data = (| user_data[data] |);
    if (data) {
        if ((data[1]) || (.is_writable_by(sender())))
            return data[2];
        return "not public.";
    } else {
        return "not set.";
    }
.

method set_data
    arg key, value, public;
    
    .perms(sender(), 'this);
    user_data = dict_add(user_data, key, [public, value]);
.

method init_user_data
    .perms(caller(), $root);
    user_data = #[['real_name, [1, "???"]], ['email, [1, "???"]]];
.

method valid_settings
    return valid_settings;
.

method data_is_cmd
    arg com, public, me, what, is, value;
    var valid, kvalid, tmp;
    
    .perms(sender(), 'parser);
    valid = $user_data.valid_settings();
    what = (| valid[what] |);
    if (!what) {
        tmp = " [+p|+public|-p|-public] my <setting name> is <value>'";
        .tell(("! => Syntax: '" + com) + tmp);
        .tell("!  Where setting name can be any of: ");
        tmp = $string.wrap_line($list.to_english(dict_keys(valid)), .linelen(), "!    ");
        tmp = replace(tmp, 1, "!    " + (tmp[1]));
        .tell(tmp);
        return;
    }
    if ((!public) || (public in ["+p", "+public"]))
        public = 1;
    else if (public in ["-p", "-public"])
        public = 0;
    else
        $parse.tell_error("Invalid public setting (must be +p, +public, -p or -public)");
    .set_data(what, value, public);
    .tell("Value set.");
.

method data_cmd
    arg com, who;
    var valid, line, user;
    
    .perms(sender(), 'parser);
    
    //
    if (!who)
        user = this();
    else
        user = (| .find_object(who, 'environment, 'user, 'grasp) |);
    if (!user) {
        .tell(("!  No user found by the name \"" + who) + "\".");
        .tell("!  To set a value use the syntax:");
        .tell(("!    '" + com) + " [+p|+public|-p|-public] my <parameter> is|are <value>'");
        return;
    }
    .tell(("Current personal data settings on " + (user.namef())) + ":");
    valid = $user_data.valid_settings();
    .tell(user.display_data());
    .tell("-=-");
.

method display_data
    arg [dont_display];
    var x, valid, line, len, pub, actor, data, lines, output;
    
    actor = sender();
    len = actor.linelen();
    valid = $user_data.valid_settings();
    output = [];
    for x in (valid) {
        if (!((x[2]) in dont_display)) {
            data = (| user_data[x[2]] |);
            if (data) {
                if ((data[1]) || (.is_writable_by(actor)))
                    line = data[2];
                else
                    line = "not public.";
            } else {
                continue;
            }
            pub = (| (user_data[x[2]])[1] |);
            pub = ((!pub) && (type(pub) != 'error)) ? "*" | " ";
            if ((len - 20) < strlen(line)) {
                output = [@output, (pub + ($string.capitalize(x[1]))) + ":"];
                lines = $string.wrap_line(line, len, "   ");
                lines = replace(lines, 1, "   " + (lines[1]));
                output = output + lines;
            } else {
                output = output + [(pub + pad(($string.capitalize(x[1])) + ": ", 13)) + line];
            }
        }
    }
    return output;
.

method finger_vrb
    arg [args];
    
.

parent #675
object #1431

var 1 child_index 7
var 1 fertile 0
var 1 manager #1431
var 1 owners [#47]
var 1 writable [#47]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 1 inited 1
var 1 dbref 'parsers

method parse
    arg user, str, next_parser, [other_parsers];
    
    // Minimum parser routine.
    return next_parser.parse(user, str, @other_parsers);
.

parent #1431
object #2321

var 1 child_index 0
var 1 fertile 0
var 1 manager #2321
var 1 owners [#47]
var 1 writable [#2321]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 1 inited 1
var 1 dbref 'verb_parser

method match_verb
    arg str, user;
    var templates, template, fields, word, obj, verb_info, i, j, output;
    
    // Resort to verb cache.
    templates = $verb_cache.templates();
    output = [];
    catch ~objnf, ~verbnf {
        for template in (templates) {
            fields = match_template(strsub(template, "%this", "*"), str);
            if (!fields)
                continue;
            j = 1;
            for word in (explode(template)) {
                if (word == "%this") {
                    obj = user.match_env_nice(fields[j]);
                    verb_info = obj.verb_info(template);
                    if (((verb_info[2]) != 'remote) && (!(user.local_to_environment(obj))))
                        user.tell("!  You cannot do that from here.");
                    else
                        obj.(verb_info[1])(@fields);
                    return;
                } else if (word == "*=*") {
                    j = j + 2;
                } else {
                    j = j + 1;
                }
            }
        }
    } with handler {
        switch (error()) {
            case ~verbnf:
                user.tell("! You can't do that to that object.");
            default:
                user.tell("!  " + ((traceback()[1])[2]));
        }
        return;
    }
.

method parse
    arg user, str, next_parser, [other_parsers];
    var templates, template, fields, word, obj, verb_info, i, j, output;
    
    // Match verbs on objects.
    // (this is a rather icky system involving the verb cache, etc..
    // I'm planning to redo this completely eventually.
    // Resort to verb cache.
    templates = ($verb_cache.templates()) + (user.local_verb_templates());
    output = [];
    catch ~objnf, ~verbnf {
        for template in (templates) {
            fields = match_template(strsub(template, "%this", "*"), str);
            if (!fields)
                continue;
            j = 1;
            for word in (explode(template)) {
                if (word == "%this") {
                    obj = user.match_env_nice(fields[j]);
                    verb_info = obj.verb_info(template);
                    if (((verb_info[2]) != 'remote) && (!(user.local_to_environment(obj))))
                        return "You cannot do that from here.";
                    else
                        return [obj, verb_info[1], @fields];
                } else if (word == "*=*") {
                    j = j + 2;
                } else {
                    j = j + 1;
                }
            }
        }
    } with handler {
        return "You can't do that to that object.";
    }
    return next_parser.parse(user, str, @other_parsers);
.

parent #3
object #4

var 1 owners [#936]
var 1 owned []
var 1 manager #4
var 1 writable [#4]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'true_lock_class

method new
    return <this(), []>;
.

method try
    arg lock, obj;
    
    return 1;
.

parent #2
object #1165

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 1 inited 1
var 1 manager #1165
var 1 writable [#1165]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'heap_class

method new
    arg list, [key];
    var ret_heap;
    
    // returns list as a valid heap sorted on key || 1
    key = [@key, 1][1];
    if (!list)
        return <this(), #[['key, key], ['data, []]]>;
    ret_heap = .new([], key);
    while (list) {
        ret_heap = ret_heap.add(list[1]);
        list = delete(list, 1);
    }
    return ret_heap;
.

method data
    arg self;
    
    return self['data];
.

method should_swap
    arg self, element1, element2;
    
    // returns true iff data[element2] should appear earlier in the list to maintain
    // consistent data structure.
    // re-define in children of $heap_class to adjust sort order
    return 0;
.

method swap
    arg self, a, b;
    
    return <this(), $dict.replace(self, 'data, $list.swap(self['data], a, b))>;
.

method add
    arg self, element;
    var swap, cur_element, element_above;
    
    // add element to self
    // tack it on the end and change self from rep (a dict) to heap_class (a frob)
    self = <this(), $dict.replace(self, 'data, (self['data]) + [element])>;
    
    // loop percolates new element up
    cur_element = self.length();
    element_above = cur_element / 2;
    swap = 1;
    while (element_above && swap) {
        if (self.should_swap(element_above, cur_element))
            self = self.swap(element_above, cur_element);
        else
            swap = 0;
        cur_element = element_above;
        element_above = cur_element / 2;
    }
    return self;
.

method del
    arg self, element;
    var data, cur_element, next_element, len;
    
    // remove element'th element from self
    // this method works by pushing element down the heap, swapping it with
    // the element below it that should be on top (of the two).
    // self rep changed to frob for swapping
    self = <this(), self>;
    
    // data = self['data];
    len = self.length();
    if ((element > len) || (element < 1))
        throw(~range, "Element index out of range.");
    cur_element = element;
    next_element = cur_element * 2;
    while (next_element < len) {
        if (self.should_swap(next_element, next_element + 1))
            next_element = next_element + 1;
        self = self.swap(cur_element, next_element);
        cur_element = next_element;
        next_element = cur_element * 2;
    }
    
    // if it didn't trickle down to the end...
    if (cur_element != len) {
        // swap cur w/ last (so we can delete it)
        self = self.swap(cur_element, len);
    
        // tricle swapped element up
        next_element = cur_element / 2;
        while (next_element) {
            if (self.should_swap(next_element, cur_element))
                self = self.swap(next_element, cur_element);
            else
                next_element = 0;
            cur_element = next_element;
            next_element = cur_element / 2;
        }
    }
    self = self._drop_last();
    return self;
.

method _drop_last
    arg rep;
    
    if (!(rep['data]))
        throw(~range, "Attempt to kill last element of null heap.");
    return <this(), $dict.replace(rep, 'data, delete(rep['data], listlen(rep['data])))>;
.

method element
    arg self, index;
    
    return (self['data])[index];
.

method length
    arg self;
    
    return listlen(self['data]);
.

method heaped
    arg self;
    var element;
    
    // returns true if data structure is consistent
    if (!(self['data]))
        return 1;
    element = 1;
    
    // loop through elements
    while (1) {
        if ((!(| .should_swap(self, element, element * 2) |)) && (!(| .should_swap(self, element, (element * 2) + 1) |)))
            element = element + 1;
        else
            return 0;
        if (element >= ((.length(self)) / 2))
            return 1;
    }
.

parent #1165
object #1166

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 1 inited 1
var 1 manager #1166
var 1 writable [#1166]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'small_first_heap_class

method should_swap
    arg self, element1, element2;
    
    // see $heap_class.should_swap for comments
    if ((element1 < 1) || ((element2 < 1) || ((element1 > (.length(self))) || (element2 > (.length(self))))))
        throw(~range, "Element index out of range.");
    else
        return (((self['data])[element1])[self['key]]) > (((self['data])[element2])[self['key]]);
.

parent #664
object #9399

var 1 dbref 'settings_ui
var 1 child_index 0
var 1 fertile 0
var 1 manager #37
var 1 owned []
var 1 owners [#37]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 16 commands [["@set?tings *", 'settings_cmd], ["@add-setting-template|@ast * as * on *", 'add_setting_template_cmd], ["@del-setting-template|@dst * from *", 'del_setting_template_cmd]]
var 16 shortcuts []
var 1 inited 1

method settings_cmd
    arg cmd, args;
    var flag, value, template, syn, bool, line;
    
    (> .perms(sender()) <);
    syn = cmd + " [+|-]<flag>[=<value>]";
    if (!args) {
        return .list_settings('local);
    } else if (args in ["-all", "-a"]) {
        return .list_settings('all);
    } else {
        bool = (args[1]) in ["-", "+"];
        if (bool)
            args = substr(args, 2);
        args = explode(args, "=");
        flag = args[1];
        if (listlen(args) == 2)
            value = args[2];
        else
            value = "";
        template = .setting_template(flag);
        if (!template)
            $parse.tell_error(("No setting available with the flag \"" + flag) + "\".", syn);
        switch (template[2]) {
            case 'boolean:
                if (!bool)
                    $parse.tell_error(("Value must be boolean (+|-" + flag) + ").", syn);
                value = bool - 1;
            case 'integer:
                if (!($string.is_numeric(value)))
                    $parse.tell_error(("Value must be an integer (" + flag) + "=<integer>).", syn);
                value = toint(value);
            case 'string:
                if (!value)
                    $parse.tell_error(("Value must be a string (" + flag) + "=<string>).", syn);
        }
        .set_setting(flag, value);
        line = ("Setting " + flag) + " set to ";
        switch (template[2]) {
            case 'boolean:
                line = line + ((value == 1) ? "+" | "-");
            default:
                line = line + toliteral(value);
        }
        .tell(line);
    }
.

method list_settings
    arg how;
    var templates, settings, setting_templates, t, x, len, line;
    
    (> .perms(sender()) <);
    len = ((.linelen()) - 2) / 2;
    switch (how) {
        case 'all:
            templates = .all_setting_templates();
            settings = .settings();
            setting_templates = dict_keys(settings);
            for x in (templates) {
                .tell(("Settings available on " + ((x[1]).namef('xref))) + ":");
                for t in (x[2]) {
                    switch (t[2]) {
                        case 'boolean:
                            line = "  " + pad("[+|-]" + (t[1]), len);
                        case 'integer:
                            line = "  " + pad(("     " + (t[1])) + "=<integer>", len);
                        case 'string:
                            line = "  " + pad(("     " + (t[1])) + "=<string>", len);
                    }
                    if (!((t[1]) in setting_templates)) {
                        line = line + " is unset";
                    } else {
                        switch (t[2]) {
                            case 'boolean:
                                line = (line + " is ") + (((settings[t[1]])[2]) ? "+" | "-");
                            default:
                                line = (line + " is ") + toliteral((settings[t[1]])[2]);
                        }
                    }
                    .tell(line);
                }
            }
        case 'local:
            settings = .settings();
            if (!settings)
                return .tell("All of your settings are either off or unset.");
            .tell("Your settings:");
            for x in (settings) {
                switch ((x[2])[1]) {
                    case 'boolean:
                        line = "  +" + (x[1]);
                    default:
                        line = (("   " + (x[1])) + "=") + toliteral((x[2])[2]);
                }
                .tell(line);
            }
    }
    .tell("---");
.

method add_setting_template_cmd
    arg cmd, flag, as, vtype, on, obj;
    var syn;
    
    (> .perms(sender()) <);
    syn = ((((cmd + " <flag> ") + as) + " <setting type> ") + on) + " <object>";
    obj = .match_env_nice(obj);
    if ((flag[1]) in ["-", "+"])
        flag = substr(flag, 2);
    if ((vtype[1]) == "'")
        vtype = substr(vtype, 2);
    vtype = tosym(vtype);
    if (!(vtype in ['boolean, 'integer, 'string]))
        $parse.tell_error("Setting type must be one of: 'boolean, 'integer, or 'string.", syn);
    catch ~perm {
        obj.add_setting_template(flag, vtype);
    } with handler {
        $parse.tell_error(("You cannot add settings to " + (obj.namef('xref))) + ".", syn);
    }
    .tell((((("Setting template with flag \"" + flag) + "\" as value of type ") + tostr(vtype)) + " added to ") + (obj.dbref()));
.

method del_setting_template_cmd
    arg cmd, flag, from, obj;
    var syn;
    
    (> .perms(sender()) <);
    syn = ((cmd + " <flag> ") + from) + " <object>";
    obj = .match_env_nice(obj);
    if ((flag[1]) in ["-", "+"])
        flag = substr(flag, 2);
    catch ~perm {
        obj.del_setting_template(flag);
    } with handler {
        $parse.tell_error(("You cannot change settings on " + (obj.namef('xref))) + ".", syn);
    }
    .tell((("Setting template with flag \"" + flag) + "\" deleted from ") + (obj.dbref()));
.

parent #3
object #6

var 1 owners [#936]
var 1 owned []
var 1 manager #6
var 1 writable [#6]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'object_lock

method new
    arg obj;
    
    if (type(obj) != 'dbref)
        throw(~perm, "Argument is not a dbref.");
    return <this(), [obj]>;
.

method try
    arg lock, obj;
    
    return (lock[1]) == obj;
.

method test
    arg testlist, testee, [args];
    var x;
    
    for x in (testlist) {
        if (testee == x)
            return 1;
    }
    return 0;
.

parent #675
object #40

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 1 inited 1
var 40 pronouns 0
var 40 gender 0
var 40 cgender_name 0
var 40 gender_name 0
var 40 person 0
var 40 has 0
var 40 number 0
var 1 manager #40
var 1 writable [#40]
var 1 readable ['parameters, 'methods, 'code]
var 40 context []
var 1 dbref 'gender

method init_gender
    .perms($root, caller());
    cgender_name = "";
    gender_name = "";
    
    // these should be inited by hand, later.
    pronouns = #[['pr, "itself"], ['pp, "its"], ['po, "it"], ['ps, "it"], ['pq, "its"], ['prc, "Itself"], ['ppc, "Its"], ['poc, "It"], ['psc, "It"], ['pqc, "Its"], ['have, "has"]];
.

method pronoun
    arg pronoun;
    
    return pronouns[pronoun];
.

method gender
    return gender;
.

method set_gender_names
    arg name, cname;
    
    .perms(sender());
    cgender_name = cname;
    gender_name = name;
.

method set_pronouns
    arg nmbr, ps, po, pp, pq, pr, psc, poc, ppc, pqc, prc;
    var x;
    
    .perms(sender(), 'manager);
    pronouns = #[['pr, pr], ['pp, pp], ['po, po], ['ps, ps], ['pq, pq], ['prc, prc], ['ppc, ppc], ['poc, poc], ['psc, psc], ['pqc, pqc]];
    number = nmbr;
    context = [ps, po, pp, pq, pr, psc, poc, ppc, pqc, prc];
.

method pronouns
    return pronouns;
.

method "name(old)"
    arg [caps];
    
    caps = [@caps, 'null][1];
    switch (caps) {
        case 'caps:
            return cgender_name;
        default:
            return gender_name;
    }
.

method context
    return context;
.

parent #40
object #2036

var 1 child_index 0
var 1 fertile 0
var 1 manager #2036
var 1 owners [#2036]
var 1 writable [#2036, #47]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 40 cgender_name ""
var 40 gender_name ""
var 40 pronouns #[['pr, "themselves"], ['pp, "their"], ['po, "them"], ['ps, "they"], ['pq, "theirs"], ['prc, "Themselves"], ['ppc, "Their"], ['poc, "Them"], ['psc, "They"], ['pqc, "Theirs"]]
var 1 inited 1
var 40 number 2
var 40 context ["themselves", "their", "them", "they", "theirs", "Themselves", "Their", "Them", "They", "Theirs"]
var 1 dbref 'gender_plural

parent #1170
object #5264

var 1 dbref 'heart
var 1 child_index 0
var 1 fertile 0
var 1 manager #5264
var 1 owned [#5264]
var 1 owners [#5264]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 1 inited 1
var 5264 heart_failures []
var 5264 hearts []

method pulse
    var robot, h;
    
    // send every robot that has a heart a pulse, if needed.
    for robot in [1 .. listlen(hearts)] {
        if ((((hearts[robot])[2]) + ((hearts[robot])[3])) < time()) {
            .debug("pulsing", hearts[robot]);
            hearts = replace(hearts, robot, [(hearts[robot])[1], time(), (hearts[robot])[3]]);
            (| ((hearts[robot])[1]).pulse() |);
        }
    }
.

method add_heartbeat
    arg [delay];
    var p;
    
    delay = [@delay, 60][1];
    for p in [1 .. listlen(hearts)] {
        if (((hearts[p])[1]) == sender()) {
            hearts = replace(hearts, p, [sender(), 0, delay]);
            return;
        }
    }
    hearts = [@hearts, [sender(), 0, delay]];
.

method del_heartbeat
    var h, pos;
    
    h = [];
    for pos in [1 .. listlen(hearts)] {
        if (((hearts[pos])[1]) == sender()) {
            if (pos > 1)
                h = [@s, sublist(hearts, 1, pos - 1)];
            if (pos < listlen(hearts))
                h = [@h, sublist(hearts, pos + 1)];
            hearts = h;
            return;
        }
    }
    throw(~objnf, ("Sender (" + tostr(sender())) + ") does not have a heartbeat.");
.

parent #12
object #7245

var 1 dbref 'data
var 1 child_index 0
var 1 fertile 0
var 1 manager #7232
var 1 owned []
var 1 owners [#7232, #1387, #1388]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 1 inited 1

method unparse
    arg data, [full];
    var str, element, association, pos;
    
    switch (type(data)) {
        case 'integer:
            return tostr(data);
        case 'string:
            return toliteral(data);
        case 'symbol:
            return toliteral(data);
        case 'error:
            return toliteral(data);
        case 'buffer:
            return toliteral(data);
        case 'dbref:
            if (full)
                return $object.get_name(data, 'namef, ['xref]);
            else
                return $object.get_name(data, 'dbref);
        case 'list:
            if (!data)
                return "[]";
            str = "[";
            for element in (sublist(data, 1, listlen(data) - 1)) {
                str = str + ($data.unparse(element));
                str = str + ", ";
            }
            str = str + ($data.unparse(data[listlen(data)]));
            return str + "]";
        case 'dictionary:
            if (!data)
                return "#[]";
            str = "#[";
            for association in (data) {
                str = str + ($data.unparse(association));
                str = str + ", ";
            }
            return substr(str, 1, strlen(str) - 2) + "]";
        case 'frob:
            return data.unparse();
    }
.

method verify_type
    arg value, type;
    var elem, type_elem, ok_flag;
    
    // returns true if type(value) is type, or in the case 
    // of lists and dicts it checks the elements
    //
    // If type is a list or dict, the elements it contains are possible types for value
    // for example: .verify_value([['foo], 1],['integer, 'list, ['symbol]]) => 1
    // To indicate that you don't care what the elements of a dict or list are,
    // simply use 'list or 'dictionary.
    if (type(value) == type)
        return 1;
    if ((type(type) in ['dictionary, 'list]) && (type(type) == type(value))) {
        for elem in (value) {
            ok_flag = 0;
            for type_elem in (type) {
                if (.verify_type(elem, type_elem)) {
                    ok_flag = 1;
                    break;
                }
                if (!ok_flag)
                    return 0;
            }
        }
        return 1;
    }
    
    // value is not of type, or values elements are not of @type, or etc
    return 0;
.

parent #3
object #7

var 1 owners [#936]
var 1 owned []
var 1 manager #7
var 1 writable [#7]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'and_lock_class

method new
    arg lhs, rhs;
    
    if ((type(lhs) != 'frob) || (type(rhs) != 'frob))
        throw(~perm, "Arguments are not both frobs.");
    return <this(), [lhs, rhs]>;
.

method try
    arg lock, obj;
    
    return ((lock[1]).try(obj)) && ((lock[2]).try(obj));
.

parent #2679
object #22

var 1 child_index 0
var 1 owners [#936]
var 1 fertile 0
var 16 commands []
var 16 shortcuts []
var 15 verbs #[]
var 19 contents []
var 1 inited 1
var 1231 name_aliases []
var 1 owned []
var 1179 gender #1182
var 17 prose #[['short, ["A place existing for the soul purpose of doing so, when it wishes be."]]]
var 1 manager #22
var 1 writable [#22]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'void
var 2787 name ['uniq, "Void"]
var 2787 name_aliases []
var 2679 exits []
var 2679 realm <#2717, ['interior]>
var 2679 coordinates #[]

parent #2485
object #2486

var 1 child_index 0
var 1 fertile 0
var 1 manager #2486
var 1 owners [#936]
var 1 writable [#2486]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 1 inited 1
var 1 dbref 'true

method unparse
    arg dummy;
    
    return "1";
.

method test
    arg [args];
    
    return 1;
.

parent #1387
object #23

var 23 inited 0
var 23 location #21
var 1 child_index 0
var 1 owners [#936]
var 1 fertile 0
var 15 verbs #[]
var 1 owned []
var 1179 gender #1182
var 23 obvious 1
var 17 prose #[]
var 1 manager #23
var 1 writable [#23]
var 1 readable []
var 1 dbref 'located
var 2787 name ['uniq, "Generic Located Object"]
var 2787 name_aliases []

method init_located
    .perms($root, caller());
    location = $nowhere;
    location.add_sender_to_contents();
    obvious = 1;
.

method uninit
    if (caller() != $root)
        throw(~perm, "Caller is not root.");
    location.del_sender_from_contents();
    location = 0;
.

method environment
    return [this()] + setremove(location.environment(), this());
.

method match_environment
    arg str;
    var thing, matches;
    
    if (str == "here") {
        return location;
    } else if (str in ["everyone", "everybody", "everything"]) {
        matches = [];
        if (str in ["everyone", "everybody"]) {
            for thing in (setremove((.location()).contents(), this())) {
                if (thing.has_ancestor($user))
                    matches = [@matches, thing];
            }
        } else {
            matches = (.location()).contents();
        }
        if (listlen(matches) > 1)
            throw(~ambig, "Several matches.", matches);
        else if (matches)
            return matches[1];
        else
            throw(~objnf, "No matches.");
    } else {
        return (> pass(str) <);
    }
.

method location
    disallow_overrides;
    
    return location || $void;
.

method _move_to
    disallow_overrides;
    arg place;
    var old;
    
    if (sender() != this())
        throw(~perm, "Use .move_to()");
    
    // Don't do anything if we're already here.
    if (place == location)
        return;
    if (!(place.has_ancestor($location)))
        throw(~type, "Argument isn't a location.");
    
    // Notify involved parties of impending move, allowing them to throw
    // errors.
    if (!valid(location))
        location = $nowhere;
    (> .will_move(sender(), place) <);
    (> location.will_leave(place) <);
    (> place.will_arrive(location) <);
    
    // Set location.
    old = location;
    location = place;
    old.del_sender_from_contents();
    place.add_sender_to_contents();
    
    // Notify involved parties of completed move, in reverse order.
    place.did_arrive(old);
    old.did_leave(place);
    .did_move(sender(), old);
.

method will_move
    arg mover, place;
    
    if ((caller() != definer()) || (sender() != this()))
        throw(~perm, "Invalid call to protected method.");
.

method did_move
    arg mover, old_place;
    
    if ((caller() != definer()) || (sender() != this()))
        throw(~perm, "Invalid call to protected method.");
.

method realm
    return realm;
.

method uninit_located
    if (caller() != $root)
        throw(~perm, "Caller is not root.");
    (.location()).del_sender_from_contents();
.

method move_to
    disallow_overrides;
    arg place;
    
    if (.is_writable_by(sender())) {
        ._move_to(place);
    } else {
        // we will have to get some checking and validation in here.
        ._move_to(place);
    }
.

method match_environment_all
    arg s;
    
    if (s == "here")
        return [location, @(> pass(@args) <)];
    else
        return (> pass(s) <);
.

method obvious
    return obvious;
.

method set_obvious
    arg obv;
    
    .perms(sender());
    obvious = obv;
.

method realm_name
    return (.location()).realm_name();
.

method local_verb_templates
    var obj, out;
    
    return (.location()).local_verb_templates();
.

parent #675
object #790

var 1 child_index 2
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 1 inited 1
var 1 manager #790
var 1 writable [#790]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'db
var 790 database #[]
var 1 info ["Nothing more than a dictionary of names and objects."]

method init_db
    .perms(caller(), $root);
    database = #[];
.

method database
    return database;
.

method value_changed
    arg key, new_value;
    
    // change the value of a key.
    (> .remove(key) <);
    (> .insert(key, new_value) <);
.

method remove
    arg key;
    
    // remove a key/value from the database
    //THIS: is breaking the user_db (quick comment fix :)
    // .perms(sender(), 'writer);
    database = dict_del(database, key);
.

method exact_match
    arg key;
    var match;
    
    // get an exact match of a key, return the value
    match = (| database[key] |);
    if (match == ~keynf)
        throw(~matchnf, "No object by that key exists in the database.");
    return match;
.

method match_begin
    arg key;
    var matches, entry;
    
    // use match_begin of the key, return the value
    matches = [(| .exact_match(key) |)];
    if (!(matches[1])) {
        matches = [];
        for entry in (database) {
            if (match_begin(entry[1], key))
                matches = [@matches, entry[2]];
        }
    }
    if (matches) {
        if (listlen(matches) == 1)
            return matches[1];
        else
            throw(~ambig, "More than one object matches that key.", matches);
    } else {
        throw(~matchnf, "No entries in the database match that key.");
    }
.

method insert
    arg key, value;
    
    // insert a key/value to the database
    //  .perms(sender(), 'writer);
    database = dict_add(database, key, value);
.

method uninit_db
    .perms(caller(), $user);
    database = 0;
.

method key_changed
    arg old_key, new_key;
    var val;
    
    // change the value of a key.
    val = database[old_key];
    .remove(old_key);
    .insert(new_key, val);
.

parent #790
object #3775

var 1 dbref 'registry
var 1 child_index 0
var 1 fertile 0
var 1 manager #37
var 1 owned []
var 1 owners [#47]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 790 database #[]
var 1 inited 1
var 3775 stripped_characters ""
var 3775 min_char_len 0
var 3775 max_char_len 0
var 3775 max_word_len 0
var 3775 reserved_names []
var 3775 invalid_names []

method init_registry
    .perms(caller(), $root);
    .set_trusted(1);
.

method uninit_registry
    .perms(caller(), $root);
    reserved_names = 0;
    invalid_names = 0;
    trusted = 0;
    stripped_characters = 0;
.

method set_max_word_len
    arg value;
    
    .perms(sender(), 'manager);
    if (type(value) != 'integer)
        throw(~type, "Value is not an integer");
    max_word_len = value;
.

method set_max_char_len
    arg value;
    
    .perms(sender(), 'manager);
    if (type(value) != 'integer)
        throw(~type, "Value is not an integer");
    max_char_len = value;
.

method set_min_char_len
    arg value;
    
    .perms(sender(), 'manager);
    if (type(value) != 'integer)
        throw(~type, "Value is not an integer");
    min_char_len = value;
.

method set_stripped_characters
    arg string;
    
    .perms(sender(), 'manager);
    if (type(string) != 'string)
        throw(~type, "Value is not a string.");
    stripped_characters = string;
.

method insert
    arg name, obj;
    
    // registers obj with obj.name
    //  .perms(caller(), 'trusts);
    if (stripped_characters)
        name = $string.strip(name, stripped_characters);
    (> pass(name, obj) <);
.

method remove
    arg name;
    
    // removes the object from the database. 
    // THIS: is what is broken with guests, should fix it.
    // .perms(caller(), 'trusts);
    if (stripped_characters)
        name = $string.strip(name, stripped_characters);
    (> pass(name) <);
.

method database
    if (!('parameters in (.is_readable_by(sender()))))
        throw(~perm, "Database is not readable by sender.");
    return (> pass() <);
.

method exact_match
    arg name;
    
    // returns a direct match of the name (if there is one)
    if (!('parameters in (.is_readable_by(sender()))))
        throw(~perm, "Database is not readable by sender.");
    if (stripped_characters)
        name = $string.strip(name, stripped_characters);
    return (> pass(name) <);
.

method valid_name
    arg name;
    var word, sname;
    
    // returns 1 if the name is valid
    /// if (!('parameters in .is_readable_by(sender())))
    //    throw(~perm, "Database is not readable by sender.");
    (> .perms(caller(), 'trusts) <);
    
    // check name itself first
    sname = name;
    if (stripped_characters)
        sname = $string.strip(name, stripped_characters);
    if (max_word_len && (listlen(explode(name)) > max_word_len))
        throw(~invname, ("Names can only be " + tostr(max_word_len)) + " words long.");
    if (min_char_len && (strlen(sname) < min_char_len))
        throw(~invname, ("Names must have at least " + tostr(min_char_len)) + " alpha-numeric characters in them");
    if (max_char_len && (strlen(name) > max_char_len))
        throw(~invname, ("Names can only be " + tostr(max_char_len)) + " characters long.");
    
    // see if it already exists
    if ((| .exact_match(name) |)) {
        if (!(((.database())[sname]) == sender()))
            throw(~invname, "Name already exists.");
    }
    
    // check reserved and invalid names
    for word in (explode(name)) {
        if (reserved_names && (word in reserved_names))
            throw(~invname, ("`" + word) + "' is a reserved name.");
        if (invalid_names) {
            for word in (invalid_names) {
                if (match_pattern(("*" + word) + "*", name))
                    throw(~invname, ("`" + word) + "' is not allowed as part of a name.");
            }
        }
    }
.

method match_begin
    arg name;
    var matches, obj;
    
    // returns a direct match, or partial matches
    if (stripped_characters)
        name = $string.strip(name, stripped_characters);
    return (> pass(name) <);
.

method stripped_characters
    return stripped_characters;
.

method key_changed
    arg old_name, new_name;
    
    // adjusts the database for the new name
    .perms(caller(), 'trusts);
    if (stripped_characters) {
        old_name = $string.strip(old_name, stripped_characters);
        new_name = $string.strip(new_name, stripped_characters);
    }
    (> pass(old_name, new_name) <);
.

method find
    arg name;
    var tmp;
    
    if (.stripped_characters())
        name = $string.strip(name, .stripped_characters());
    if (!name)
        throw(~namenf, "No matches found.");
    tmp = (| .exact_match(name) |);
    if (tmp)
        return tmp;
    catch any {
        tmp = (> .match_begin(name) <);
    } with handler {
        switch (error()) {
            case ~ambig:
                rethrow(error());
            default:
                throw(~namenf, "No matches found.");
        }
    }
    return tmp;
.

parent #3
object #9

var 1 owners [#936]
var 1 owned []
var 1 manager #9
var 1 writable [#9]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'not_lock_class

method new
    arg lock;
    
    if (type(lock) != 'frob)
        throw(~perm, "Argument is not a lock.");
    return <this(), [lock]>;
.

method try
    arg lock;
    
    return !((lock[1]).try(obj));
.

parent #23
object #24

var 1 child_index 22
var 1 owners [#936]
var 1 fertile 1
var 15 verbs #[["take|get %this", ['take_vrb, 'noremote]], ["drop %this", ['drop_vrb, 'noremote]]]
var 23 location #21
var 1 inited 1
var 1 owned []
var 1179 gender #1182
var 23 obvious 1
var 17 prose #[]
var 1 manager #24
var 1 writable [#24]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'thing
var 2787 name ['uniq, "Generic Thing"]
var 2787 name_aliases []

method take_vrb
    arg verb, this;
    
    if ((.location()) == sender()) {
        sender().tell("You already have it.");
    } else {
        sender().tell(("You take " + (.namef())) + ".");
        (sender().location()).announce((((sender().namef()) + " takes ") + (.namef())) + ".", this(), sender());
        if ((.location()) != (sender().location()))
            (.location()).announce((((sender().namef()) + " takes ") + (.namef())) + ".", this(), sender());
        .move_to(sender());
    }
.

method drop_vrb
    arg verb, this;
    
    if ((.location()) != sender()) {
        sender().tell("You don't have that.");
    } else {
        sender().tell(("You drop " + (.namef())) + ".");
        (sender().location()).announce((((sender().namef()) + " drops ") + (.namef())) + ".", this(), sender());
        .move_to(sender().location());
    }
.

parent #675
object #1032

var 1 child_index 4
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 1 inited 1
var 1032 text 0
var 1 info []
var 1 manager #1032
var 1 writable [#1032]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'text

method init_text
    if (caller() != $root)
        throw(~perm, "Caller is not $root.");
    text = [];
.

method uninit_text
    if (caller() != $root)
        throw(~perm, "Caller is not $root.");
    text = [];
.

method text
    // returns text
    if ((!(.is_writable_by(sender()))) && (sender() != this()))
        throw(~perm, "Permission Denied.");
    return text;
.

method set_text
    arg txt;
    
    // resets ,text to the list sent
    if ((!(.is_writable_by(sender()))) && (sender() != this()))
        throw(~perm, "Permission Denied.");
    text = txt;
.

method ins_line
    arg txt, [loc];
    
    // inserts txt at loc (where loc is an integer)
    if ((!(.is_writable_by(sender()))) && (sender() != this()))
        throw(~perm, "Permission Denied.");
    if (!loc)
        text = [@text, txt];
    else
        text = (> insert(text, loc, txt) <);
.

method del_text
    // deletes all text
    if ((!(.is_writable_by(sender()))) && (sender() != this()))
        throw(~perm, "Permission Denied.");
    text = [];
.

method del_line
    arg linestr;
    
    // deletes "line" where line is the actual line to delete
    if ((!(.is_writable_by(sender()))) && (sender() != this()))
        throw(~perm, "Permission Denied.");
    text = setremove(text, line);
.

method del_nline
    arg nline;
    
    // deletes nline where nline is an integer reference to a list location
    if ((!(.is_writable_by(sender()))) && (sender() != this()))
        throw(~perm, "Permission Denied.");
    text = (> delete(text, nline) <);
.

method ins_lines
    arg lines, loc;
    var line;
    
    // inserts txt at loc (where loc is an integer)
    if ((!(.is_writable_by(sender()))) && (sender() != this()))
        throw(~perm, "Permission Denied.");
    if (type(lines) != 'list)
        throw(~type, "Lines should be passed as a list of strings.");
    for line in (lines) {
        text = (> insert(text, loc, line) <);
        loc = loc + 1;
    }
.

parent #24
parent #1032
parent #7261
object #7248

var 1 dbref 'note
var 1 child_index 11
var 1 fertile 1
var 1 manager #7232
var 1 owned []
var 1 owners [#7232, #1387, #1388]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 1032 text []
var 1 inited 1
var 23 location #21
var 23 obvious 1
var 1178 messages #[]
var 17 prose #[]
var 15 verbs #[["erase %this", ['erase_vrb, 'remote]], ["read|nread %this", ['read_vrb, 'remote]], ["write on %this", ['write_vrb, 'remote]], ["write at * on %this", ['write_at_vrb, 'remote]], ["write * on %this", ['write_str_vrb, 'remote]], ["copy from %this to *", ['copy_vrb, 'remote]], ["erase * on|from %this", ['erase_on_vrb, 'remote]]]
var 1179 gender #1182
var 2787 name ['uniq, "Generic Note"]
var 2787 name_aliases ["note"]
var 7248 seperator 0
var 7261 public []
var 1 info ["Generic Note", "============", "", "For basic editing and saving of text.", "", "Descendant of $text", "", "Commands:", "", "  \"erase * on %this\"                    rmt 'erase_on_vrb", "  \"erase %this\"                         rmt 'erase_vrb", "  \"read|nread %this\"                    rmt 'read_vrb", "  \"write on %this\"                      rmt 'write_vrb", "  \"write at * on %this\"                 rmt 'write_at_vrb", "  \"write * on %this\"                    rmt 'write_str_vrb", "  \"copy from %this to *\"                rmt 'copy_vrb", "", "erase", "-----", "", "Erases all or part of the text.  \"erase %this\" and \"erase all on %this\" erases all text from the note.  \"erase <line(s)> on %this\" erases a line or lines from the note, example: \"erase 2-5 on %this\".", "", "read|nread", "----------", "", "Read the text.  \"nread\" will read the text and prepend each line with it's relative number.", "", "write", "-----", "", "Write on the note using this command.  \"write on %this\" will accept text after the command line and append it to the end.  \"write <line> on %this\" will add the line to the end of the note.  \"write at <line> on %this\" will accept text after the command line and place it in the text beginning at <line>.", "", "copy", "----", "", "Used to copy the text from the note to either another descendant of $note or if a method is specified it sends to that method instead.", "", "Maintenance", "===========", "", "As an owner of the note object you can set it as publicly writable or readable.  The Note is a child of the generic public object, so you can do this by using the \"@public\" command (Syntax: `@public on note <+|-[w?ritable|r?eadable]>`).  Writers following the system permissions scheme are also allowed to write on the note.", "", "The seperator can be changed using eval on the .set_seperator() method.  This is not a command as most people don't change it."]

method read_vrb
    arg vrb, [args];
    var who, text, prose;
    
    who = sender();
    if ((!(.is_publicly('readable))) && (!(.trusts(who))))
        return who.tell((.name('def)) + " is not publicly readable!");
    who.tell(.name('def));
    prose = .prose('literal);
    if (prose)
        who.tell((| prose['short] |) || []);
    who.tell(.seperator());
    text = .text();
    if ((vrb == "nread") && text)
        text = $list.numbered_text(text);
    who.tell(text ? text | ["", "(nothing)", ""]);
    who.tell(.seperator());
    who.tell(("You finish reading " + (.name('def))) + ".");
.

method write_vrb
    arg write, [args];
    var who, line;
    
    who = sender();
    if ((!(.is_publicly('writable))) && (!(.is_writable_by(who))))
        return who.tell((.namef()) + " is not publicly writable!");
    
    // because I'm odd lets do this all 1 one command.
    if (listlen(args) == 2) {
        line = "Now writing on " + (.name('def));
        line = line + ", enter \".\" to finish and \"@abort\" to abort.";
        who.tell(line);
        who.read('add_text, sender());
    } else {
        args = explode(args[1]);
        who.debug(args);
    }
.

method erase_on_vrb
    arg erase, str, prep, this;
    var line, nline, who, len, oldline;
    
    who = sender();
    if ((!(.is_publicly('writable))) && (!(.is_writable_by(who))))
        return who.tell((.namef()) + " is not publicly writable!");
    if (!str)
        return who.tell("You must erase either a line, line number, or all");
    catch any {
        if (match_begin("all", str)) {
            .del_text();
    
            // if erase is null, this method was called by an editor
            if (erase)
                who.tell(("All text cleared from " + (.name('def))) + ".");
        } else {
            if (listlen(explode(str)) > 1)
                nline = toint(explode(str)[2]);
            else
                nline = toint(str);
            oldline = (.text())[nline];
            .del_nline(nline);
            line = ("Line " + tostr(nline)) + " (\"";
            len = (who.linelen()) - (25 + strlen(.name('def)));
            line = line + ($string.chop(oldline, len));
            line = (line + "\") erased from ") + (.name('def));
            who.tell(line);
        }
    } with handler {
        switch (error()) {
            case ~range:
                who.tell("There are not that many lines in the text.");
            default:
                who.tell("Oops: " + ((traceback()[1])[2]));
        }
    }
.

method erase_vrb
    arg erase, this;
    var line, nline, len;
    
    if ((!(.is_publicly('writable))) && (!(.is_writable_by(sender()))))
        return sender().tell((.namef()) + " is not publicly writable!");
    .del_text();
    
    // if erase is null, this method was called by an editor originally.
    if (erase)
        sender().tell(("All text cleared from " + (.name('def))) + ".");
.

method add_text
    arg ntext, who, [args];
    
    // called by .read()
    // if at they should be an int defining where to insert.
    if ((!(.is_publicly('writable))) && (!(.is_writable_by(who))))
        throw(~perm, "Permission Denied.");
    if (ntext) {
        if (args) {
            if (!(| .ins_lines(ntext, args[1]) |))
                who.tell(("There are not that many lines in " + (.name('ref))) + ".");
        } else {
            .set_text((.text()) + ntext);
        }
        who.tell(((("Line" + ((listlen(ntext) == 1) ? "" | "s")) + " added to ") + (.name('def))) + ".");
    } else {
        who.tell("Text not added.");
    }
.

method seperator
    return (type(seperator) == 'string) ? seperator | "---";
.

method write_str_vrb
    arg write, str, prep, this;
    var who, line;
    
    who = sender();
    if ((!(.is_publicly('writable))) && (!(.is_writable_by(who))))
        return who.tell((.namef()) + " is not publicly writable!");
    if (!str)
        return .tell(("Nothing to write on " + (.name('def))) + "!");
    .add_text([str], sender());
.

method write_at_vrb
    arg write, at, str, prep, this;
    var who, line, lines, syn;
    
    who = sender();
    if ((!(.is_publicly('writable))) && (!(.is_writable_by(who))))
        return who.tell((.namef()) + " is not publicly writable!");
    syn = ((("`" + write) + " at [line] <line number> on ") + this) + "`";
    str = explode(str);
    if ((str[1]) == "line")
        str = delete(str, 1);
    line = $string.is_numeric(str[1]);
    if (!at)
        $parse.tell_error(("Unknown line \"" + (str[1])) + "\".", syn, who);
    lines = listlen(.text());
    if (line > (lines + 1))
        $parse.tell_error(("There are only " + tostr(lines)) + " lines!", syn, who);
    str = "Now writing on " + (.name('def));
    str = str + ", enter \".\" to finish and \"@abort\" to abort.";
    who.tell(str);
    who.read('add_text, sender(), line);
.

method copy_vrb
    arg com, from, this, prep, where;
    var obj, what;
    
    // this method is outdated, needs to be rewritten.
    // it probably doesn't even work.
    if ((!(.is_writable_by(sender()))) && (!(.is_publicly_readable())))
        return sender().tell(("You cannot read the text on " + (.namef('ref))) + ".");
    if ("." in where) {
        where = $parse.reference(where);
        what = 1;
    } else {
        where = $parse.reference(where, ",");
    }
    obj = sender().match_env_nice(where[1]);
    if (!(obj.is_writable_by(sender())))
        return .tell(("!  " + (obj.namef('ref))) + " is not owned by you.");
    if ((obj.has_ancestor($note)) && (!(where[2])))
        obj.add_text(text, sender());
    
    // they want a method ref
    if (where[2]) {
        catch any {
            where = tosym(where[2]);
            if (what) {
                obj.(where)(text, sender());
                sender().tell(((("Text copied to " + ($data.unparse(obj))) + ".") + tostr(where)) + "().");
            } else {
                if (!(where in (obj.parameters())))
                    return .tell(("!  parameter '" + tostr(where)) + " not found");
                obj.eval([(tostr(where) + " = ") + ($data.unparse(.text()))]);
            }
        } with handler {
            $brandon.tell_traceback(traceback());
            $parse.tell_error((traceback()[1])[2], ("`" + com) + " <obj>[.,<destination]`", sender());
        }
    }
    sender().tell("Text copied from " + (.namef()));
.

method init_note
    .perms(caller(), $root);
    .set_readable(['methods, 'code]);
.

method init_for_core
    .perms(caller(), $sys);
.

method set_seperator
    arg newsep;
    
    .perms(sender(), 'manager);
    seperator = newsep;
.

parent #7248
object #2250

var 1 child_index 2
var 1 fertile 1
var 1 manager #2250
var 1 owners [#936]
var 1 writable [#2250]
var 1 readable ['methods, 'code]
var 1 trusted []
var 1 owned []
var 15 verbs #[["read * on %this", ['read_cmd, 'remote]]]
var 17 prose #[['short, ["the place that Ye administrators should be logging somewhat impacting changes that others would like to know about."]]]
var 1179 gender #1182
var 23 location #21
var 23 obvious 1
var 1 inited 1
var 1 dbref 'log
var 2787 name ['uniq, "Generic Log"]
var 2787 name_aliases ["log", "changes", "log"]
var 1032 text ["9-28-94/22:33:17> foo"]
var 7261 public ['readable]

method read_cmd
    arg [args];
    var loglen, text;
    
    if (0) {
        // later on i'll adjust this so you can 'read from line 12 on log'
        return;
    } else {
        text = .text();
        loglen = listlen(text);
        sender().tell(["---", (((((.namef()) + ", entries ") + tostr(loglen - 10)) + " to ") + tostr(loglen)) + " (last 10 lines).", "---"]);
        sender().tell(sublist(text, loglen - 10));
        sender().tell("---");
    }
.

method log
    arg line;
    
    .perms(caller(), 'trusts);
    .ins_line((($time.time_stamp()) + "> ") + line);
.

parent #2250
object #8598

var 1 dbref 'http_log
var 1 child_index 0
var 1 fertile 0
var 1 manager #37
var 1 owned []
var 1 owners [#37]
var 1 writable [#8019, #7969]
var 1 readable ['methods, 'code]
var 15 verbs #[]
var 7261 public ['readable]
var 1032 text ["11-10-94/23:26:47> 129.123.1.155 \"GET /bin/list_method?$root.generate_html() HTTP/1.0\" Mozilla/0.9 beta (X11; OSF1 V2.0 alpha)", "11-11-94/02:57:08> topaz.cm.cf.ac.uk \"GET / HTTP/1.0\" Mozilla/0.9 beta (X11; SunOS 4.1.3 sun4c)", "11-11-94/11:51:04> millville.declab.usu.edu \"GET / HTTP/1.0\"  NCSA Mosaic for the X Window System/2.5b2  libwww/2.12 modified", "11-11-94/11:51:23> millville.declab.usu.edu \"GET /history.html HTTP/1.0\"  NCSA Mosaic for the X Window System/2.5b2  libwww/2.12 modified", "11-11-94/11:51:41> millville.declab.usu.edu \"GET /current.html HTTP/1.0\"  NCSA Mosaic for the X Window System/2.5b2  libwww/2.12 modified", "11-11-94/14:13:16> bolero.rahul.net \"GET /VESP.html HTTP/1.0\"  Lynx/2.3 BETA  libwww/2.14", "11-11-94/14:13:27> avon.declab.usu.edu \"GET /VESP.html HTTP/1.0\"  Lynx/2.3 BETA  libwww/2.14", "11-11-94/14:18:55> avon.declab.usu.edu \"GET /VESP.html HTTP/1.0\"  Lynx/2.3 BETA  libwww/2.14"]
var 2787 name ['prop, "HTTP Log"]
var 2787 name_aliases []
var 1179 gender #1182
var 17 prose #[]
var 1178 messages #[]
var 23 location #21
var 23 obvious 1
var 1 inited 1

parent #664
object #9291

var 1 dbref 'web_ui
var 1 child_index 0
var 1 fertile 0
var 1 manager #37
var 1 owned []
var 1 owners [#37]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 16 commands []
var 16 shortcuts []
var 1 inited 1
var 9291 http_file_root 0

method http_request
    arg method, path;
    var page;
    
    if (http_file_root) {
        page = http_file_root.find_file([http_file_root.filename(), @path]);
        if (page)
            return page.retrieve_html();
    }
    return 0;
.

method set_http_file_root
    arg obj;
    
    (> .perms(sender(), 'manager) <);
    http_file_root = obj;
.

method http_file_root
    return http_file_root;
.

parent #1431
object #2622

var 1 child_index 0
var 1 fertile 0
var 1 manager #2622
var 1 owned [#2622]
var 1 owners [#2622]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 1 inited 1
var 1 dbref 'null_parser

method parse
    arg user, str, [anything_else];
    var i;
    
    for i in [1 .. strlen(str)] {
        if ((str[i]) != " ")
            return 'failed;
    }
    return 'ok;
.

parent #1170
object #9153

var 1 dbref 'network
var 1 child_index 0
var 1 fertile 0
var 1 manager #37
var 1 owned []
var 1 owners [#37]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 1 inited 1
var 9153 valid_slate_callers [#4707]

method valid_slate_callers
    return valid_slate_callers;
.

method add_slate_caller
    arg obj;
    
    (> .perms(sender(), 'manager) <);
    valid_slate_callers = setadd(valid_slate_callers, obj);
.

method del_slate_caller
    arg obj;
    
    (> .perms(sender(), 'manager) <);
    valid_slate_callers = setremove(valid_slate_callers, obj);
.

parent #24
parent #19
object #25

var 1 child_index 0
var 1 owners [#936]
var 1 fertile 1
var 15 verbs #[]
var 19 contents []
var 23 location #21
var 1 inited 1
var 1 owned []
var 1179 gender #1182
var 23 obvious 1
var 17 prose #[]
var 1 manager #25
var 1 writable [#25]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'located_location
var 2787 name ['uniq, "Generic Located Location"]
var 2787 name_aliases []

method environment
    return pass() + (.contents());
.

method local_verb_templates
    var obj, out;
    
    // get redundant so we don't hit an endless loop
    out = [];
    for obj in (.contents()) {
        if (obj.has_ancestor($has_verbs))
            out = out + dict_keys(obj.all_verbs());
    }
    return pass() + out;
.

parent #25
object #28

var 1 child_index 0
var 1 owners [#936]
var 1 fertile 0
var 15 verbs #[]
var 19 contents []
var 23 location #21
var 1 inited 1
var 1 owned []
var 28 body_parts #[]
var 1179 gender #1182
var 23 obvious 1
var 17 prose #[]
var 1 manager #28
var 1 writable [#28]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'body
var 2787 name ['uniq, "Generic Body"]
var 2787 name_aliases []

method tell
    //
.

method set_body_part
    arg part, frob, param;
    
    if (sender().has_ancestor($wearable_class))
        throw(~perm, "Sender must be $wearable_class.");
    body_parts = dict_add(body_parts, frob.new(part, param));
.

method init_body
    if (caller() != $root)
        throw(~perm, "Sender is not $root");
    body_parts = #[];
.

method body_parts
    return body_parts;
.

method namef
    arg [args];
    
    if (!args)
        args = [['name]];
    if (((args[1]) == 'nactivity) || ((args[1]) == 'titled))
        args = sublist(args, 2);
    return pass(@args);
.

parent #664
object #86

var 1 child_index 0
var 1 owners [#936]
var 1 fertile 0
var 16 commands [["wh?isper * to *", 'whisper_cmd], ["@register-ch?annel|@reg-ch?annel *", 'register_channel_cmd], ["@delete-ch?annel|@del-ch?annel *", 'delete_channel_cmd], ["say *", 'say_cmd], ["to * say *", 'say_to_cmd], ["@paste *", 'paste_cmd], ["page * with *", 'page_cmd], ["emote *", 'emote_cmd], ["strip *", 'strip_cmd], ["@tuned|@ch?annels *", 'channels_cmd], ["repeat *", 'repeat_cmd], ["@tune in|out *", 'tune_channel_cmd], ["on * say *", 'on_subj_cmd], ["vowel?ize *", 'late_vowels_cmd], ["epage * with *", 'page_emote_cmd]]
var 16 shortcuts [["|*", '_interact, ["|", 1]], ["<*", '_interact, ["<", 1]], [">*", '_interact, [">", 1]], ["[*", '_interact, ["[", 1]], ["]*", 'right_bracket_cmd, [1]], ["think *", 'think_cmd, [1]], ["%*", 'think_cmd, [1]], ["#*", 'channel_cmd, ["#", 1]], ["\"*", 'say_cmd, ["", 1]], [":*", 'emote_cmd, ["", 1]], [")* *", 'on_subj_cmd, ["on", 1, "say", 2]], ["!*", 'polite_spoof_cmd, [1]], ["''*", 'say_to_cmd, ["to", "", "say", 1]], ["'* *", 'say_to_cmd, ["to", 1, "say", 2]], ["--*", 'page_cmd, ["page", "", "with", 1]], ["-* *", 'page_cmd, ["page", 1, "with", 2]], ["++*", 'page_emote_cmd, ["epage", "", "with", 1]], ["+* *", 'page_emote_cmd, ["epage", 1, "with", 2]]]
var 1 inited 1
var 86 stage #[[">", " -> "], ["<", " <- "], ["[", " ["], ["|", " | "]]
var 86 last_interacted_with 0
var 1 owned []
var 1 manager #86
var 1 writable [#86]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'interaction
var 1 info ["  ]     [Lynx text]                 |     Lynx | text", "  [     Lynx [text]:                <     Lynx <- text", "  )     (Lynx text)                 >     Lynx -> text", "  (     Lynx (text):                !     text      -- Lynx", "  %     Lynx . o O ( text )         \"     Lynx says, \"text\"", "  '     Lynx to who, \"text\"         ''    Lynx [to who]: text", "  `     Lynx [to who]: text         ``    Lynx [to who]: text", "  -     Lynx pages: text            --    Lynx pages: text", "  +     (from...) Lynx text         ++    (from...) Lynx text", "  ,     Lynx jumps, \"text\"          ,,    Lynx jumps, \"text\"", "  :     Lynx text                   ::    Lynxtext", "  .     Lynx text         (pose)    ;     ;eval", "  #     <Channel - Lynx> text", "Unused: ~ $ & * =", "Dont use: ?"]

method page_cmd
    arg com, who, prep, message;
    var user, recipient, targets;
    
    .perms(sender(), 'parser);
    who = $string.explode_english_list(who);
    if (!who) {
        if (last_interacted_with)
            who = last_interacted_with[2];
        else
            $parse.tell_error("You must specify somebody or something to speak to.");
    }
    targets = who;
    for recipient in (who) {
        if (type(recipient) == 'dbref) {
            user = recipient;
        } else {
            user = (| $user_db.match_begin(recipient) |);
            if (!user)
                user = (| .match_environment(recipient) |);
        }
        if (user && ((user.has_ancestor($user)) && (user.connected()))) {
            user.tell(((.namef()) + " pages: ") + message);
            who = replace(who, recipient in who, user.namef());
            targets = replace(targets, recipient in targets, user);
        } else {
            .tell(("! " + ($data.unparse(recipient))) + " is either not connected, not a user, or misspelled.");
            who = setremove(who, recipient);
            targets = setremove(targets, recipient);
        }
    }
    if (targets) {
        last_interacted_with = [time(), targets];
        .tell(((("You page \"" + message) + "\" to ") + ($list.to_english(who, 'namef))) + ".");
    }
.

method wall_cmd
    arg what;
    
    .perms(sender(), 'parser);
    ._interact("|", what);
.

method right_bracket_cmd
    arg what;
    var space;
    
    .perms(sender(), 'parser);
    space = " ";
    if (what && (substr(what, 1, 1) == "]")) {
        what = substr(what, 2);
        space = "";
    }
    (.location()).announce(((("[" + (.namef())) + space) + what) + "]");
.

method polite_spoof_cmd
    arg what;
    var name;
    
    .perms(sender(), 'parser);
    
    // Polite spoof: Send what unmarred if it contains " "+.namef()+" ",
    // otherwise, tack on "     -- "+.namef()
    name = .namef();
    if (!(((name + " ") in what) || ((" " + name) in what)))
        what = (what + "     -- ") + name;
    (.location()).announce(what);
.

method say_to_cmd
    arg com, who, prep, msg;
    var thing, x, recipient, tmp, targets, errargs;
    
    .perms(sender(), 'parser);
    who = $string.explode_english_list(who);
    if (!who) {
        if (last_interacted_with)
            who = last_interacted_with[2];
        else
            $parse.tell_error("You must specify somebody or something to speak to.");
    }
    targets = who;
    for x in [1 .. listlen(who)] {
        recipient = who[x];
        if (type(recipient) == 'dbref) {
            thing = recipient;
        } else {
            catch ~ambig {
                thing = .match_env_nice(recipient);
            } with handler {
                eargs = (traceback[1])[3];
                tmp = $list.map(errags, 'namef);
                who = (sublist(who, 1, x - 1) + tmp) + sublist(who, x + 1);
                targets = (sublist(who, 1, x - 1) + errargs) + sublist(who, x + 1);
            }
        }
        if (thing) {
            who = replace(who, x, thing.namef());
            targets = replace(targets, recipient in targets, thing);
        }
    }
    last_interacted_with = [time(), targets];
    (.location()).announce(((((.namef()) + " [to ") + ($list.to_english(who))) + "]: ") + msg);
.

method whisper_cmd
    arg com, what, prep, who;
    var loc;
    
    .perms(sender(), 'parser);
    who = .match_env_nice(who);
    loc = .location();
    if ((who.location()) != loc) {
        .tell("You must be in the same room as a person, to whisper to them.");
        return;
    }
    who.tell((((.namef()) + " whispers, \"") + what) + "\"");
    .tell(((("You whisper, \"" + what) + "\" to ") + (who.namef())) + ".");
    loc.announce((((.namef()) + " whispers to ") + (who.namef())) + ".", who, this());
.

method wiz_cmd
    arg what;
    
    if (sender() != this())
        throw(~perm, "Sender not this.");
    $comm_tuner.channel_announce('wiz, what);
.

method _interact
    arg verb, what;
    var stage;
    
    .perms(sender(), 'parser);
    stage = $interaction.get_stage();
    
    // echo .namef()+stage[verb]+what to the room
    if (verb in dict_keys(stage))
        (.location()).announce(((.namef()) + (stage[verb])) + what);
    else
        throw(~unknownverb, ("Unknown verb '" + verb) + "'");
.

method get_stage
    return stage;
.

method think_cmd
    arg what;
    
    .perms(sender(), 'parser);
    (.location()).announce((((.namef()) + " . o O ( ") + what) + " )");
.

method channel_cmd
    arg com, what;
    var channel, text, syntax, sep_loc;
    
    syntax = "`#<channel> <text>'";
    if (sender() != this())
        throw(~perm, "Sender not this.");
    catch any {
        sep_loc = " " in what;
        channel = $channels.match_channel(substr(what, 1, sep_loc - 1));
        if (!channel)
            $parse.tell_error("That channel does not exist.", syntax);
        if (listlen(channel) > 1)
            $parse.tell_error(("Which channel? That could refer to any of these: " + ($data.unparse(channel))) + ".", syntax);
        channel = channel[1];
        text = substr(what, sep_loc + 1);
        $channels.announce(channel, text);
    } with handler {
        switch (error()) {
            case ~range:
                $parse.tell_error("You must specify some text to send", syntax);
            default:
                $parse.tell_error((traceback()[1])[2], syntax);
        }
    }
.

method tune_channel_cmd
    arg com, inout, channel;
    var syn;
    
    .perms(sender(), 'parser);
    syn = ("\"" + com) + " '<channel>\"";
    catch any {
        switch (inout) {
            case "in":
                channel = $channels.validate_channel(channel);
                $channels.tune_in(channel);
            case "out":
                channel = $channels.validate_channel(channel);
                $channels.tune_out(channel);
            default:
                $parse.tell_error("You must tune a channel \"in\", or \"out\".", syn);
        }
    } with handler {
        $parse.tell_error((traceback()[1])[2], ("`" + com) + " <channel>'");
    }
    .tell(((("Channel '" + tostr(channel)) + " tuned ") + inout) + ".");
.

method channels_cmd
    arg com, who;
    
    .perms(sender(), 'parser);
    if (!who)
        who = this();
    else
        who = .match_env_nice(who);
    .tell("Communication Channels:");
    .tell($list.lcolumnize(who.get_channels(), .linelen()));
.

method register_channel_cmd
    arg com, what;
    var syn, name, tunable, senders;
    
    if (sender() != this())
        throw(~perm, "Sender is not this");
    syn = [("Syntax: `" + com) + " <name> [<tunable> <senders>]'", "<tunable> and <senders> can be either 1, 0, or a list of users"];
    what = explode(what);
    name = [@what, "BAD NAME"][1];
    tunable = [@what, 1, 1][2];
    senders = [@what, 1, 1, 1][3];
    catch any {
        $channels.new_channel(name, tunable, senders, sender(), [sender()]);
    } with handler {
        $parse.tell_error(syn + [(traceback()[1])[2]]);
    }
    .tell(("New channel registered with the name `" + tostr(name)) + "'.");
.

method delete_channel_cmd
    arg com, name;
    var syn;
    
    if (sender() != this())
        throw(~perm, "Sender is not this");
    syn = ("`" + com) + " <name>'";
    catch any {
        $channels.del_channel($channels.validate_channel(name));
    } with handler {
        $parse.tell_error((traceback()[1])[2], syn);
    }
    .tell("Channel deleted");
.

method emote_cmd
    arg com, what;
    
    if (what && ((what[1]) == ":"))
        (.location()).announce((.namef()) + ($string.match_sub_tag(substr(what, 2), "^")));
    else
        (.location()).announce(((.namef()) + " ") + ($string.match_sub_tag(what, "^")));
.

method late_vowels_cmd
    arg what;
    var output, letter, index;
    
    if (sender() != this())
        throw(~perm, "Sender not this.");
    output = ["", ""];
    while (what) {
        letter = what[1];
        what = substr(what, 2);
        if (letter in ["a", "e", "i", "o", "u", "A", "E", "I", "O", "U"])
            output = [output[1], (output[2]) + letter];
        else if (letter != " ")
            output = [(output[1]) + letter, output[2]];
        else
            output = [(output[1]) + letter, (output[2]) + letter];
    }
    (.location()).announce(((.namef()) + " ") + (output[1]));
    $scheduler.add_task(1, 'emote_cmd, "", output[2]);
.

method say_cmd
    arg say, what;
    var type, how, idx;
    
    .perms(sender(), 'parser);
    
    // .location().announce(pad(.name(), -9) + "->ALL  " + what);
    // return;
    idx = strlen(what);
    if (what) {
        switch (what[idx]) {
            case "!":
                how = "exclaim";
            case "?":
                how = "ask";
            case ")":
                if (((what[idx - 1]) == ":") || ((what[idx - 1]) == "8"))
                    how = "grin";
                else
                    how = "say";
            default:
                how = "say";
        }
    } else {
        how = "say";
    }
    (.location()).announce((((((.name()) + " ") + how) + "s, \"") + what) + "\"");
.

method pose_cmd
    arg dummy1, str;
    var actor;
    
    actor = sender();
    if (str && ((str[1]) == ":"))
        (.location()).announce((actor.namef()) + substr(str, 2));
    else
        (.location()).announce(((actor.namef()) + " ") + str);
.

method paste_cmd
    arg com, [who];
    var obj;
    
    .perms(sender(), 'parser);
    who = [@who, 0][1];
    if (who) {
        who = $list.to_string(sublist(explode(who), 2));
        obj = (| .find_object(who, 'environment, 'environment, 'grasp) |);
        if (!obj)
            $parse.tell_error(("No user found by the name \"" + who) + "\".", "Syntax: '@paste [to <user>]'");
    }
    .tell("Enter text to paste, terminated by \".\" on a line by itself. (Or \"@abort\" by itself)");
    .read('paste_done, obj);
.

method paste_done
    arg text, who;
    var padlen;
    
    if (sender() != this())
        throw(~perm, "Sender not this.");
    padlen = 79;
    text = [$string.center((" " + (.namef())) + " (@paste's) ", padlen, "-"), @text, $string.center(" + Finis + ", padlen, "-")];
    if (who) {
        who.tell(text);
        .tell(("Text pasted to " + (who.namef())) + ".");
    } else {
        (.location()).announce(text);
    }
.

method strip_cmd
    arg com, str;
    
    str = ((.namef()) + " ") + str;
    (.location()).announce($string.strip(str, str[random(strlen(str))]));
.

method get_channels
    var ch, chs, entry, new_chs, len, public, subscribed;
    
    .perms(sender());
    chs = $channels.channels();
    new_chs = [];
    public = $channels.all_tuners();
    
    // pick a random dictionary to get the name list from
    len = $list.element_maxlength(chs);
    for ch in (chs) {
        subscribed = $channels.listeners(ch);
        entry = ((this() in subscribed) ? "+" | "") + tostr(ch);
        entry = pad(entry, -(len + 2));
        entry = entry + (((public[ch]) == 1) ? " - Public " | " - Private");
        new_chs = [@new_chs, entry];
    }
    return new_chs;
.

method repeat_cmd
    arg com, [args];
    var syntax, x, times, line, out, repeat, other;
    
    syntax = ("`" + com) + " [+times|+t=<times>] <what>'";
    args = explode(args ? args[1] | "");
    if (!args)
        $parse.tell_error("You must specify something to repeat antisocially.", syntax);
    if (match_begin(args[1], "+t")) {
        x = (| explode(args[1], "=")[2] |);
        if (!x)
            $parse.tell_error("You must define repeat times as +times=* to something.", syntax);
        times = toint(x);
        args = sublist(args, 2);
        if (!args)
            $parse.tell_error("You must specify something to repeat antisocially.", syntax);
    }
    if (!times)
        times = 3;
    repeat = args[1];
    other = (| sublist(args, 2) |) || [];
    
    //
    line = "";
    for x in [1 .. times]
        line = line + repeat;
    args = sublist(args, 2);
    
    //
    .emote_cmd("emote", $list.to_string([line] + other));
.

method page_emote_cmd
    arg com, who, prep, message;
    var user, recipient, targets, name;
    
    .perms(sender(), 'parser);
    who = $string.explode_english_list(who);
    if (!who) {
        if (last_interacted_with)
            who = last_interacted_with[2];
        else
            $parse.tell_error("You must specify somebody or something to speak to.");
    }
    targets = who;
    name = (.namef()) + " ";
    for recipient in (who) {
        if (type(recipient) == 'dbref) {
            user = recipient;
        } else {
            user = (| $user_db.match_begin(recipient) |);
            if (!user)
                user = (| .match_environment(recipient) |);
        }
        if (user && ((user.has_ancestor($user)) && (user.connected()))) {
            user.tell(((("[from " + ((.location()).namef())) + "] ") + name) + message);
            who = replace(who, recipient in who, user.namef());
            targets = replace(targets, recipient in targets, user);
        } else {
            .tell(("! " + ($data.unparse(recipient))) + " is either not connected, not a user, or misspelled.");
            who = setremove(who, recipient);
            targets = setremove(targets, recipient);
        }
    }
    if (targets) {
        last_interacted_with = [time(), targets];
        .tell(("You epage " + ($list.to_english(who, 'namef))) + ".");
    }
.

method on_subj_cmd
    arg com, subj, says, what;
    
    .perms(sender(), 'parser);
    (.location()).announce(((((.namef()) + " (on ") + subj) + "): ") + what);
.

parent #1377
object #2337

var 1 child_index 0
var 1 fertile 1
var 1 manager #2337
var 1 owners [#47]
var 1 writable [#47]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 1 inited 1
var 2337 receiving 0
var 2337 input 0
var 1 dbref 'input

method finish_receiving
    var oreceiving, oinput;
    
    // called by $input_parser.parse when one is finished.
    .perms(sender(), 'parser);
    
    // we have to reset the parameter before we run it's values.
    oreceiving = receiving;
    oinput = input;
    .reset_input();
    (oreceiving[2]).(oreceiving[3])(oinput, @sublist(oreceiving, 4));
.

method start_receiving
    arg lines, obj, method, [args];
    
    // called by this().read() or this().read_line()
    .perms(sender(), 'this);
    receiving = [lines, obj, method, @args];
    input = [];
    .add_parser($input_parser, 'first);
.

method reset_input
    // resets values, for aborting or other emergency reset.
    .perms(sender(), 'parser);
    receiving = 0;
    input = 0;
    .del_parser($input_parser);
.

method new_line
    arg line;
    
    // called by $input_parser.parse with a new string to be added.
    .perms(sender(), 'parser);
    input = [@input, line];
.

method lines
    // returns how many lines the user wishes to read.
    return receiving[1];
.

method read
    arg method, [args];
    
    // read input lines from the user.
    // returns sender().method(["input", "lines"], @args);
    if (receiving)
        throw(~wait, "User is currently receiving input.");
    if (type(method) != 'symbol)
        throw(~type, "Method reference must be given as a symbol.");
    
    // looks ok.
    .start_receiving('terminated, sender(), method, @args);
.

method prompt
    arg prompt, method, [args];
    
    .read_line(method, @args);
    
    //   .tell(prompt);
    .non_terminated_tell(prompt);
.

method read_line
    arg method, [args];
    
    // read input lines from the user.
    // returns sender().method(["input", "lines"], @args);
    if (receiving)
        throw(~wait, "User is currently receiving input.");
    if (type(method) != 'symbol)
        throw(~type, "Method reference must be given as a symbol.");
    
    // looks ok.
    .start_receiving('one, sender(), method, @args);
.

parent #664
object #922

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 16 commands []
var 16 shortcuts []
var 1 inited 1
var 922 command_aliases []
var 1 manager #922
var 1 writable [#922]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'command_aliases

method init_command_aliases
    if (caller() != $root)
        throw(~perm, "Caller is not $root.");
    command_aliases = [];
.

method uninit_command_aliases
    if (caller() != $root)
        throw(~perm, "Caller is not $root.");
    command_aliases = [];
.

method command_aliases
    return command_aliases;
.

method all_command_aliases
    var user, aliases, userc;
    
    // Collect complete command alias list from ancestors.
    aliases = [];
    for user in (.ancestors()) {
        userc = (| user.command_aliases() |);
        if (userc)
            aliases = aliases + userc;
        if (user == definer())
            break;
    }
    return aliases;
.

method match_command_aliases
    arg str;
    var alias, argf, match, newstr;
    
    // attempts to rebuild the string for an alias.
    if (sender() != this())
        throw(~perm, "Sender is not this.");
    for alias in (.all_command_aliases()) {
        match = match_pattern(alias[1], str);
        if (match != 0) {
            newstr = alias[2];
            for argf in [1 .. listlen(match)]
                newstr = strsub(newstr, "%" + tostr(argf), match[argf]);
            return newstr;
        }
    }
    return str;
.

method add_command_alias
    arg alias, actual;
    var index, a;
    
    (> .perms(sender()) <);
    if ((type(alias) != 'string) || (type(actual) != 'string))
        throw(~type, "alias and actual are not strings.");
    while ("%" in alias) {
        alias = strsub(alias, "%" + tostr(index), "*");
        index = index + 1;
    }
    
    // have it 'replace' the old alias (if one exists) by first removing
    // the old one, and adding the new one later.
    for a in (command_aliases) {
        if ((a[1]) == alias)
            command_aliases = setremove(command_aliases, a);
    }
    command_aliases = [@command_aliases, [alias, actual]];
.

method del_command_alias
    arg alias;
    var ca;
    
    (> .perms(sender()) <);
    if (type(alias) != 'string)
        throw(~type, "alias is not a string.");
    for ca in (command_aliases) {
        if ((ca[1]) == alias) {
            command_aliases = setremove(command_aliases, ca);
            return;
        }
    }
    throw(~aliasnf, ("alias `" + alias) + "' is not found");
.

parent #664
object #1140

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 16 commands [["quit", 'old_command_cmd], ["WHO", 'old_command_cmd], ["@create *", 'old_command_cmd], ["@dig *", 'old_command_cmd]]
var 16 shortcuts []
var 1 inited 1
var 1140 non_supported_cmds #[["quit", "@quit"], ["WHO", "@who"], ["@create", "@spawn"], ["@dig", "@build"]]
var 1 manager #1140
var 1 writable [#1140]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'bad_commands

method mangled_command
    arg str;
    
.

method add_old_cmd_reference
    arg oldcmd, [newcmd];
    
    .perms(sender(), 'admin);
    if (this() != $bad_commands)
        throw(~perm, "Only define bad commands on $bad_commands");
    if (newcmd)
        non_supported_cmds = dict_add(non_supported_cmds, oldcmd, newcmd[1]);
    .add_command(oldcmd, 'old_command_cmd);
.

method del_old_cmd_reference
.

method old_command_cmd
    arg com, [args];
    var line, equiv;
    
    equiv = (| ($bad_commands.non_supported_cmds())[com] |);
    line = ("Oops, `" + com) + "` is not supported here.  Use `help commands` for";
    sender().tell("!  " + line);
    line = "an explanation on the differences in commands.";
    sender().tell(("!  " + line) + (equiv ? ("  Try: `" + equiv) + "`" | ""));
.

method non_supported_cmds
    return non_supported_cmds;
.

parent #675
object #9398

var 1 dbref 'has_settings
var 1 child_index 0
var 1 fertile 1
var 1 manager #37
var 1 owned []
var 1 owners [#37]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 1 inited 1
var 9398 settings #[]
var 9398 setting_templates #[]

method setting_templates
    (> .perms(sender()) <);
    return setting_templates || #[];
.

method all_setting_templates
    var obj, tmpl, out;
    
    (> .perms(sender()) <);
    out = #[];
    for obj in (.ancestors()) {
        tmpl = (| obj.setting_templates() |);
        if (tmpl)
            out = dict_add(out, obj, tmpl);
        if (obj == definer())
            break;
    }
    return out;
.

method add_setting_template
    arg template, type;
    
    (> .perms(sender()) <);
    if (!setting_templates)
        setting_templates = #[];
    if (type(template) != 'string)
        throw(~type, "Setting templates must be strings.");
    if (type(type) != 'symbol)
        throw(~type, "Setting data types must be symbols.");
    setting_templates = dict_add(setting_templates, template, type);
.

method del_setting_template
    arg template;
    
    (> .perms(sender()) <);
    if (setting_templates) {
        if (template in dict_keys(setting_templates))
            setting_templates = dict_del(setting_templates, template);
    }
.

method set_setting
    arg flag, value;
    var template, objects, x, y, type;
    
    (> .perms(sender()) <);
    
    // is it a valid template?
    template = (| .setting_template(flag) |);
    if (!template)
        throw(~setting, ("Unknown setting \"" + flag) + "\".");
    
    // make sure the value is submitted correctly.
    type = template[2];
    switch (type) {
        case 'boolean:
            if (!(value in [1, 0]))
                throw(~type, ("Value must be boolean (+/-" + flag) + ").");
        case 'integer:
            if (type(value) != 'integer)
                throw(~type, ("Value must be an integer (" + flag) + "=<integer>).");
        case 'string:
            if (type(value) != 'string)
                throw(~type, ("Value must be a string (" + flag) + "=<string>).");
        default:
            throw(~type, "Setting has an unknown type definition, IT'S BROKE.");
    }
    
    // incase they weren't initialized, initialize settings.
    if (!settings)
        settings = #[];
    
    // Ok, set it...
    // for space concerns, if value is null remove the setting.
    if (((type == 'boolean) && (value == 0)) || ((type == 'string) && (value == ""))) {
        if ((| settings[template[1]] |))
            return .unset_setting(template[1]);
    }
    settings = dict_add(settings, template[1], [type, value]);
.

method unset_setting
    arg template;
    
    (> .perms(sender()) <);
    if ((| settings[template] |))
        settings = dict_del(settings, template);
.

method settings
    (> .perms(sender()) <);
    return settings || #[];
.

method setting
    arg template;
    
    return (| (settings[template])[2] |) || 0;
.

method setting_template
    arg template;
    var templates, t, obj;
    
    (> .perms(sender()) <);
    for obj in (.ancestors()) {
        templates = (| obj.setting_templates() |);
        if (templates) {
            t = (| templates[template] |);
            if (t)
                return [template, t];
        }
        if (obj == definer())
            break;
    }
    return 0;
.

parent #28
parent #86
parent #2337
parent #922
parent #1140
parent #4309
parent #9398
parent #9399
object #30

var 1 child_index 47
var 1 owners [#936]
var 1 fertile 0
var 16 commands [["@quit", 'quit_cmd], ["i?nventory", 'inventory_cmd], ["@title *", 'title_cmd], ["@aliases *", 'aliases_cmd], ["@add-name-alias|@ana *", 'add_name_alias_cmd], ["@del-name-alias|@dna *", 'del_name_alias_cmd], ["@rename * to *", 'rename_cmd], ["@time *", 'time_cmd], ["@audit *", 'audit_cmd], ["@who *", 'who_cmd], ["@who-s?hort|@whos?hort", 'who_short_cmd], ["news", 'news_cmd], ["@del-command-a?lias|@dca?lias *", 'del_command_alias_cmd], ["@command-a?liases|@ca?liases *", 'command_aliases_cmd], ["@wrap *", 'wrap_cmd], ["@prompt *", 'prompt_cmd], ["@password *", 'password_cmd], ["@idle", 'idle_cmd], ["@who-a?dmins|@whoa?dmins *", 'who_admins_cmd], ["@add-command-a?lias|@aca?lias *", 'add_command_alias_cmd], ["@who-c?ount|@whoc?ount", 'who_count_cmd], ["@who-p?rogrammers|@whop?rogrammers *", 'who_progs_cmd], ["@login-watch *", 'watch_logins_cmd], ["@com?mands *", 'commands_cmd], ["@age *", 'age_cmd], ["@spawn|@create *", 'spawn_cmd], ["@prose|@describe *", 'prose_cmd], ["@status", 'status_cmd]]
var 16 shortcuts []
var 15 verbs #[]
var 19 contents []
var 23 location #21
var 1 inited 1
var 30 password "$HexDY0MZCuK2"
var 30 connected_at 0
var 30 last_command_at 0
var 30 connections []
var 30 linelen 0
var 30 title 0
var 30 email 0
var 30 action 0
var 30 creation_time 0
var 30 home 0
var 30 pagelen 0
var 30 activity 0
var 30 parsers []
var 30 filters []
var 30 watch_logins 0
var 30 tell_traceback 0
var 30 last_name 0
var 1 dbref 'user
var 30 prompt ""
var 1 owned []
var 922 command_aliases []
var 682 letters #[]
var 682 letters_index #[]
var 682 senders 1
var 682 readers [#47]
var 682 notify [#47]
var 682 last_letter 0
var 679 subscribed #[[#30, 0]]
var 1179 gender #1182
var 23 obvious 1
var 17 prose #[]
var 1 manager #30
var 1 writable [#30]
var 1 readable ['parameters, 'methods, 'code]
var 666 current_help #534
var 666 help_dict #[["*", #534], ["help", #547], ["**", #535]]
var 30 context 0
var 2787 name ['uniq, "Generic User Object"]
var 2787 name_aliases []
var 4309 user_data #[['real_name, [1, "???"]], ['email, [1, "???"]]]
var 9398 setting_templates #[["terminated-tell", 'boolean], ["Content-type", 'string]]

method init_user
    .perms(caller(), $root);
    password = "*";
    connected_at = 0;
    last_command_at = 0;
    connections = [];
    creation_time = time();
    parsers = [$command_parser, $verb_parser];
    filters = [];
    action = "";
    prompt = "";
    context = #[];
    .set_quota($sys.user_starting_quota());
    $user_db.insert(.namef(), this());
    .set_readable([]);
    .move_to($body_cave);
.

method uninit_user
    var conn;
    
    (> .perms(caller(), $root) <);
    if (.connected())
        (| (.location()).did_disconnect() |);
    
    // and incase any are lying about
    for conn in (connections)
        (| conn.user_going_away() |);
    password = 0;
    connections = 0;
    (| $user_db.remove(.name()) |);
.

method trusted
    return pass() + ($parsers.children());
.

method will_move
    arg mover, place;
    
    (> pass(mover, place) <);
    
    //if (!place.has_ancestor($room))
    //  throw(~perm, "Players can only move into rooms.");
.

method watch_logins
    return watch_logins;
.

method connected_at
    return connected_at;
.

method last_command_at
    return last_command_at;
.

method tell
    arg what;
    var f;
    
    if (filters) {
        for f in (filters)
            what = f.filter(what);
    }
    ._tell(what);
.

method set_password
    arg str;
    var x, num;
    
    .perms(sender(), 'manager);
    if (strlen(str) < 5)
        throw(~badpasswd, "Passwords must be at least 5 characters long.");
    
    // this is assuming they have alphabetic characters as well (shrug).
    // for x in [1 .. strlen(str)] {
    //   if (str[x] in "1234567890")
    //     num = num + 1;
    // }
    // if (num < 2)
    //   throw(~badpasswd, "Passwords must contain at least 2 numeric characters.");
    password = crypt(str);
.

method check_password
    arg str;
    
    return crypt(str, substr(password, 1, 2)) == password;
.

method did_move
    arg [args];
    var loc;
    
    (> pass(@args) <);
    loc = .location();
    (| loc.look_cmd("look") |);
.

method parsers
    .perms(sender(), 'trusts);
    return parsers;
.

method add_parser
    arg parser, [position];
    
    // adds a new $parser at 'position.
    .perms(sender(), 'parser);
    
    // do this in three steps, first make sure the posistion is valid,
    // then check for it already, then figure its insert position.
    position = [@position, 'first][1];
    if (!(position in ['last, 'first]))
        throw(~type, "Posistion types must be one of: 'last, 'first.");
    
    // does it exist?  If so remove it.
    if (parser in parsers)
        parsers = setremove(parsers, parser);
    
    // figure position
    if (position == 'last)
        position = listlen(parsers) + 1;
    else if (position == 'first)
        position = 1;
    parsers = insert(parsers, position, parser);
.

method del_parser
    arg parser;
    var keepers;
    
    // removes a parser.  Cannot remove $command_parser or $verb_parser
    keepers = [$command_parser, $verb_parser];
    if (!(parser in parsers))
        throw(~parsernf, ($data.unparse(parser)) + " is not in the parser list.");
    if (parser in keepers)
        throw(~twink, ("You must always have " + ($list.map_to_english(keepers, 'namef))) + ".");
    parsers = setremove(parsers, parser);
.

method parse_line
    arg line;
    var result;
    
    .perms(caller(), $old_connection);
    last_command_at = time();
    catch any {
        result = parsers ? (parsers[1]).parse(this(), line, @sublist(parsers, 2), $null_parser) | 'failed;
        if (type(result) == 'list)
            return (result[1]).(result[2])(@sublist(result, 3));
        switch (result) {
            case 'failed:
                .tell(("I don't understand \"" + ($string.chop(line, (.linelen()) - 22))) + "\".");
            case 'ok:
            default:
                .tell(tostr(result));
        }
    } with handler {
        if (((traceback()[1])[3]) != 'no_traceback)
            .tell_traceback(traceback(), line, 0, error());
    }
    return 0;
.

method connection_logged_in
    arg addr, port;
    var line;
    
    if (caller() != $old_connection)
        throw(~perm, "Caller is not $old_connection.");
    connections = connections + [sender()];
    if (listlen(connections) == 1)
        .login(sender());
    else
        .login_again(sender());
    line = ("CONNECT " + tostr(sender() in connections)) + ": ";
    line = (((line + (.dbref())) + " <") + (sender().addr())) + "> ";
    $sys.log(line);
.

method connection_logged_out
    arg addr, port;
    var con, line;
    
    if (caller() != $old_connection)
        throw(~perm, "Caller is not $old_connection.");
    con = sender() in connections;
    connections = setremove(connections, sender());
    if (!connections)
        .logout(sender());
    else
        .logout_connection(sender());
    connections = setremove(connections, sender());
    line = ("DISCONNECT " + tostr(sender() in connections)) + ": ";
    line = (((line + (.dbref())) + " <") + (sender().addr())) + "> ";
    $sys.log(line);
.

method login
    arg connection;
    var loc;
    
    if ((sender() != this()) || (definer() != caller()))
        throw(~perm, "Invalid access to private method.");
    .tell(("* * * Login successful (" + (connection.addr())) + ") * * *");
    connected_at = time();
    last_command_at = time();
    
    //
    loc = .location();
    if (loc == $body_cave) {
        if ((.home()) != $body_cave)
            (| .move_to(.home()) |);
        else
            (| .move_to($places.place('starting)) |);
    } else if ((loc == (.home())) || (loc != $body_cave)) {
        (| loc.look_cmd("look") |);
    } else {
        (| .move_to(.home()) |);
    }
    (| (.location()).did_connect() |);
    (| .login_notify() |);
    (| $login_watcher.did_connect() |);
    (| $user_db.did_connect() |);
.

method login_again
    arg connection;
    
    if ((sender() != this()) || (definer() != caller()))
        throw(~perm, "Invalid access to private method.");
    last_command_at = time();
    .tell(((("* * * " + ($integer.n_to_nth(connection in (.connections())))) + " Login successful (") + (connection.addr())) + ") * * *");
.

method logout
    arg connection;
    
    if ((sender() != this()) || (definer() != caller()))
        throw(~perm, "Invalid access to private method.");
    (| (.location()).did_disconnect() |);
    
    // user specific things
    if (!($guest in (.parents()))) {
        (| $housekeeper.did_disconnect() |);
        (| $user_db.last_log_disconnect(this()) |);
    } else {
        (| $user_db.last_log_disconnect($guest) |);
    }
    (| $user_db.did_disconnect() |);
    (| $login_watcher.did_disconnect() |);
.

method connections
    return connections;
.

method connected
    disallow_overrides;
    
    return connections ? 1 | 0;
.

method who_cmd
    arg com, [args];
    var who, x, person, where, meths, header;
    
    // just the basic who listing
    .perms(sender(), 'parser);
    who = [];
    if (!(args[1])) {
        who = $user_db.connected();
    
        // looks like they want who in a room.
    } else if (((args[1])[1]) == "@") {
        where = $room.match_descendants(substr(args[1], 2));
        if (!where)
            $parse.tell_error(("I do not know where \"" + substr(args[1], 2)) + "\" is.");
        for x in (where.contents()) {
            if (x.has_ancestor($user))
                who = [@who, x];
        }
        if (!who)
            $parse.tell_error(("Nobody is in " + (where.namef())) + ".");
        meths = [['namef, 'titled, " (", 'activity, ")"], ['time_poll]];
        header = ["Name", "Times (idle)"];
        .tell($code.generate_listing(who, "Users in " + (where.namef()), meths, header, [1, 1]));
        return;
    } else {
        //
        // user, or list of users
        for x in ($string.explode_english_list(@args)) {
            catch any {
                person = $user_db.find(x);
            } with handler {
                switch (error()) {
                    case ~ambig:
                        .tell(((("The name \"" + x) + "\" can match any of: ") + ($list.to_english($list.map((traceback()[1])[3], 'namef)))) + ".");
                    default:
                        .tell(("I don't know who \"" + x) + "\" is.");
                }
                continue;
            }
            who = [@who, person];
        }
        if (!who)
            return;
    }
    .tell($code.generate_listing(who));
.

method email
    return email || "**no email address**";
.

method quit_cmd
    arg dummy;
    
    .perms(sender(), 'parser);
    return 'disconnect;
.

method inventory_cmd
    arg dummy;
    var i;
    
    .perms(sender(), 'parser);
    if (.contents()) {
        .tell("Carrying:");
        for i in (.contents())
            .tell(" " + (i.namef()));
    } else {
        .tell("You are empty-handed.");
    }
.

method match_env_nice
    arg name, [syntax];
    var obj, args, line;
    
    // calls .match_environment() returns nice errors. as well as stopping if it
    // breaks.  No returns neccessary
    syntax = [@syntax, ""][1];
    catch any {
        obj = .match_environment(name);
    } with handler {
        switch (error()) {
            case ~ambig:
                args = (traceback()[1])[3];
                line = ("\"" + (args[listlen(args)])) + "\" can match any of: ";
                line = line + ($list.map_to_english(args[1], 'namef));
                (> $parse.tell_error(line, syntax) <);
            case ~objnf:
                line = ("Nothing found by the name \"" + ((traceback()[1])[3])) + "\".";
                (> $parse.tell_error(line, syntax) <);
            default:
                line = (traceback()[1])[2];
                (> $parse.tell_error(line, syntax) <);
        }
    }
    return obj;
.

method linelen
    return linelen || 79;
.

method idle_seconds
    return time() - last_command_at;
.

method who_short_cmd
    arg com;
    var user, tmp, who, namestr, total;
    
    if (sender() != this())
        throw(~perm, "Sender not this.");
    who = [];
    total = listlen($user_db.connected());
    .tell((("Currently connected users (total of " + tostr(total)) + ((total == 1) ? " person" | " people")) + "):");
    for user in ($user_db.connected()) {
        namestr = (((((" " + (user.namef())) + " (") + ($time.elapsed(user.connected_at()))) + " ") + ($time.dhms(user.idle_seconds()))) + ")";
        who = [@who, namestr];
        if (tmp < (strlen(namestr) + 2))
            tmp = strlen(namestr) + 2;
    }
    .tell($list.columnize(who, (.linelen()) / (tmp + 1), " ", .linelen()));
.

method who_admins_cmd
    arg com, [who];
    var admins, admin, title;
    
    who = who[1];
    
    // everybody, connected or not
    if (who == "all") {
        admins = $sys.admins();
        title = "All Admins";
    
        // ok, just the connected ones then
    } else if (who == "") {
        title = "All Connected Admins";
        admins = [];
        for admin in ($sys.admins()) {
            if (admin.connected())
                admins = [@admins, admin];
        }
    
        // hrm, possibly somebody specific
    } else {
        admins = [.match_object_nice(who, $admin, 'children)];
    }
    .tell($code.generate_listing(admins, title));
.

method who_progs_cmd
    arg com, [args];
    var progs, all_progs, x, title;
    
    args = args[1];
    if (args) {
        if (match_begin(args, "all")) {
            progs = $programmer.descendants();
            title = "All Programmers";
        } else {
            title = "Programmer";
            progs = [.find_object_nice(args, 'environment, 'user, 'grasp)];
        }
    } else {
        progs = [];
        title = "Connected Programmers";
        for x in ($programmer.descendants()) {
            if (x.connected())
                progs = [@progs, x];
        }
    }
    .tell($code.generate_listing(progs, title));
.

method who_count_cmd
    arg com;
    var len, rz, pz;
    
    .perms(sender(), 'parser);
    len = listlen($user_db.connected());
    if (len == 1) {
        rz = "is";
        pz = "person";
    } else {
        rz = "are";
        pz = "people";
    }
    .tell(((((("There " + rz) + " currently ") + tostr(len)) + " ") + pz) + " connected.");
    .tell("Lag is <lag meter will eventually go here>");
.

method title
    return title || "";
.

method action
    // different from activity, returns a more accurate second to second action
    if (.connected())
        return action || "";
    else
        return "(asleep)";
.

method time_poll
    arg [args];
    var idle;
    
    if (!(.connected()))
        return "Last On: " + substr(ctime(last_command_at), 1, 10);
    if (!args)
        idle = ((.idle_seconds()) > 10) ? $time.dhms(.idle_seconds(), 'long) | "";
    else
        idle = ((.idle_seconds()) > 10) ? $time.dhms(.idle_seconds()) | "";
    return ($time.elapsed(.connected_at())) + (idle ? " " + idle | "");
.

method title_cmd
    arg com, str;
    
    .perms(sender(), 'parser);
    .tell("Temporary until the real title setup is working");
    catch any {
        .set_title(str);
    } with handler {
        $parse.tell_error((traceback()[1])[2]);
    }
    .tell(("Title Set as: \"" + str) + "\"");
.

method commands_cmd
    arg cmd, args;
    var obj, coms, c, len, lcoms, scoms, ulen, l, what, a, opts, lines;
    
    // returns all commands in a nice format.
    .perms(sender(), 'parser);
    args = explode(args);
    if (!args) {
        what = .ancestors();
        .tell("All commands: (prepare to be spammed)");
    } else {
        what = [.match_env_nice(args[1])];
        .tell("Commands on " + ((what[1]).namef('ref)));
    }
    ulen = .linelen();
    for obj in (what) {
        if (!((obj.has_ancestor($has_commands)) || (obj.has_ancestor($has_verbs))))
            continue;
        coms = [];
        coms = coms + ((| $list.slice(obj.shortcuts(), 1) |) || []);
        coms = coms + ((| $list.slice(obj.commands(), 1) |) || []);
        coms = coms + ((| obj.verb_templates() |) || []);
        if (coms) {
            scoms = [];
            lcoms = [];
            for c in (coms) {
                len = strlen(c) + 2;
                if (len > (ulen / 3))
                    lcoms = [@lcoms, "  " + c];
                else
                    scoms = [@scoms, "  " + c];
            }
            lines = ($list.lcolumnize(scoms, ulen)) + ($list.lcolumnize(lcoms, ulen));
            for l in (lines)
                .tell($string.trim(l, 'right));
            .tell("  -=-");
        }
        if (obj == $has_commands)
            break;
    }
.

method tell_commands
    arg p, ps, pc, space;
    var x, a, c;
    
    // called by $builder.commands_cmd
    .tell(((((space + "Commands on ") + (p.namef('ref))) + " (") + toliteral(p)) + ")");
    pc = ps + pc;
    if (!pc) {
        .tell(space + "  None");
        return;
    }
    for x in [1 .. listlen(pc)] {
        a = pad(tostr((pc[x])[1]), 30) + " ";
        c = pad(toliteral((pc[x])[2]), 20) + " ";
        .tell(((space + "  ") + a) + c);
    }
.

method set_email
    arg email_str;
    var syn, email, host;
    
    if (!(.is_writable_by(sender())))
        throw(~perm, "Sender is not an owner.");
    
    // kludgy way to check for semi valid email addresses:
    email = explode(email_str, "@");
    if (listlen(email) < 2)
        throw(~invemail, "Invalid email: " + email_str);
    
    // check hostname for at least 1 subnet and a machine name.
    host = explode(email[2], ".");
    if (listlen(host) < 2)
        throw(~invemail, "Invalid hostname: " + (host[1]));
    
    // email is purposefully constructed this way, as at one point it will
    // be able to automatically tack on your host, if you do not provide it.
    set_var('email, ((email[1]) + "@") + (email[2]));
.

method set_watch_logins
    arg value;
    
    // either have a single reference, or: 'none|'all
    .perms(sender());
    watch_logins = value;
.

method echo_file
    arg str;
    var con;
    
    for con in (connections)
        con.echo_file(str);
.

method set_home
    arg obj;
    
    // if (!obj.is_writable_by(sender()))
    //  return .tell("You do not own " + obj.namef() + ".");
    home = obj;
.

method pagelen
    return pagelen || 24;
.

method set_pagelen
    arg len;
    
    if (!(.is_writable_by(sender())))
        throw(~perm, "Sender not an owner.");
    if (type(len) != 'integer)
        throw(~type, "pagelength must be an integer");
    pagelen = len;
.

method set_linelen
    arg len;
    
    if (!(.is_writable_by(sender())))
        throw(~perm, "Sender not an owner.");
    if (type(len) != 'integer)
        throw(~type, "Linelength must be an integer");
    linelen = len;
.

method aliases_cmd
    arg com, [obj];
    
    if (!(.is_writable_by(sender())))
        throw(~perm, "Sender not owner.");
    obj = .match_env_nice((obj[1]) ? obj[1] | (.dbref()));
    if (!(obj.has_ancestor($named))) {
        .tell(("Object `" + (obj.dbref())) + "' is not a named object.");
        throw(~stop, "", 'no_traceback);
    }
    .tell((("Aliases for " + (obj.namef())) + ": ") + ($list.to_english(obj.name_aliases(), "none")));
.

method activity
    var idle;
    
    // different from action, returns a broader version of your doings
    if (!(.connected()))
        return "asleep";
    if (activity)
        return activity;
    idle = .idle_seconds();
    if (idle < 180)
        return "";
    if (idle < 300)
        return "daydreaming";
    if (idle < 900)
        return "zoned";
    else
        return "long gone";
.

method add_name_alias_cmd
    arg com, [args];
    var syn, obj, what;
    
    if (!(.is_writable_by(sender())))
        throw(~perm, "Sender not this");
    syn = ("`" + com) + " <alias> to <object>' (to <object> is optional)";
    args = explode(args[1]);
    what = args[1];
    obj = .match_env_nice([@args, .dbref(), .dbref()][3]);
    if (!what)
        $parse.tell_error("You must name an alias.", syn);
    if (what in (.name_aliases()))
        $parse.tell_error(("You already have the name alias `" + what) + "'");
    catch any {
        obj.add_name_alias(what);
    } with handler {
        switch (error()) {
            case ~methodnf:
                $parse.tell_error((obj.namef('ref)) + " is not a descendant of $xxxxxxxxx", syn);
            default:
                $parse.tell_error((traceback()[1])[2], syn);
        }
    }
    .tell(((("Name Alias `" + what) + "' added to ") + (obj.namef())) + ".");
.

method modes
    return modes;
.

method del_name_alias_cmd
    arg com, [args];
    var syn, obj, what;
    
    if (!(.is_writable_by(sender())))
        throw(~perm, "Sender not this");
    syn = ("`" + com) + " <alias> from <object>' (from <object> is optional)";
    args = explode(args[1]);
    what = args[1];
    obj = .match_env_nice([@args, .dbref(), .dbref()][3]);
    if (!what)
        $parse.tell_error("You must name an alias to delete.", syn);
    if (!(what in (.name_aliases())))
        $parse.tell_error((((obj.namef('ref)) + " doesn't have the name alias `") + what) + "'");
    catch any {
        obj.del_name_alias(what);
    } with handler {
        switch (error()) {
            case ~methodnf:
                $parse.tell_error((obj.namef('ref)) + " is not a descendant of $matchable", syn);
            default:
                $parse.tell_error((traceback()[1])[2], syn);
        }
    }
    .tell(((((("Name Alias `" + what) + "' deleted from ") + (obj.namef())) + ", aliases are now: ") + ($list.to_english(.name_aliases()))) + ".");
.

method home
    return home || $body_cave;
.

method set_dbref
    arg new_dbref;
    
    if ((caller() != $user) && (!(sender() in ($sys.system()))))
        throw(~perm, "User dbrefs can only be changed by $user.");
    (> pass(new_dbref) <);
.

method rename_cmd
    arg com, what, prep, line;
    var syn, x, article, name;
    
    if (sender() != this())
        throw(~perm, "Sender is not this");
    syn = ((("`" + com) + " <object> ") + prep) + " <newname>'";
    what = .match_env_nice(what);
    if (!(what.has_ancestor($named)))
        $parse.tell_error(("Object `" + ($data.unparse(what))) + "' is not descended from $named.", syn);
    line = explode(line);
    article = 'uniq;
    for x in [1 .. listlen(line)] {
        if (((line[x]) == "-prop") || (((line[x]) == "-p") || ((line[x]) == "-proper"))) {
            article = 'prop;
            line = delete(line, x);
            break;
        }
        if (((line[x]) == "-uniq") || (((line[x]) == "-u") || ((line[x]) == "-unique"))) {
            article = 'uniq;
            line = delete(line, x);
            break;
        }
    }
    name = $list.to_string(line);
    catch any {
        what.set_name(name, article);
    } with handler {
        $parse.tell_error((traceback()[1])[2], syn);
    }
    .tell("Name is now: " + (what.name()));
.

method time_cmd
    arg command, [args];
    var rtime, itime, ptime;
    
    .perms(sender(), 'parser);
    
    // rtime = "Terran Time:      " + $time.ltime('12hr, 'ampm) + "  " +
    $time.ltime();
    rtime = "Terran Time:      " + ctime();
    itime = (("Ilraitheen Time:  " + ($dark_time.ilraitheen_time())) + " day ") + tostr($dark_time.day());
    ptime = "Paradisical Time: " + ($dark_time.paradise_time());
    .tell([rtime, itime, ptime]);
.

method audit_cmd
    arg com, [args];
    var owner, obj, col, total, line, syntax, loc, size;
    
    if (sender() != this())
        throw(~perm, "Sender not this.");
    syntax = "";
    owner = (args[1]) ? args[1] | "me";
    owner = .match_env_nice(owner, syntax);
    if (!(owner.owned())) {
        .tell("  None");
    } else {
        col = (.linelen()) / 2;
        line = ("Objects owned by " + (owner.namef('ref))) + ":";
        .tell((pad(line, col) + pad("bytes", -10)) + " Location");
        for obj in (owner.owned()) {
            if (!valid(obj)) {
                .tell(("  ** invalid object (" + toliteral(obj)) + ") **");
                continue;
            }
            line = pad("  " + (obj.namef('ref)), col);
            size = $integer.to_english(obj.size());
            line = (line + pad(size, -((strlen(size) > 10) ? strlen(size) | 10))) + " ";
            loc = (obj.has_ancestor($located)) ? ("[" + ((obj.location()).namef())) + "]" | "";
            .tell(pad(line + loc, .linelen()));
            total = total + (obj.size());
        }
    }
    .tell(("Total usage: " + ($integer.to_english(total))) + " bytes");
    size = owner.get_quota();
    line = ("Total quota: " + ($integer.to_english(size))) + " bytes       ";
    line = ((line + "Remaining: ") + ($integer.to_english(size - total))) + " bytes";
    .tell(line);
.

method login_notify
    // called by .login, set items here that will 'notify' a user of varous
    // different things, such as new mail, news, etc.
    if ($news.new())
        .tell("There is new News (use `news' to read it).");
    if (.unread())
        .tell("You have new mail (use `@Mm?ail on me' to list it).");
    .mmail_lists_cmd("", "subscribed");
.

method _set_watch_logins
    arg value;
    
    if (sender() != this())
        throw(~perm, "Invalid call to private method");
    watch_logins = value;
.

method get_mode
    arg mode;
    
    // returns the variable for the mode
    if (mode in dict_keys(modes))
        return modes[mode];
    throw(~modenf, ("Mode \"'" + tostr(mode)) + "\" is not found in the users dictionary");
.

method add_mode
    arg mode, setting;
    
    if (!(.is_writable_by(sender())))
        throw(~perm, "Sender is not an owner.");
    if (type(mode) != 'symbol)
        throw(~type, "Modes must be a symbol");
    modes = dict_add(modes, mode, setting);
.

method news_cmd
    arg [args];
    
    (> .perms(sender(), 'parser) <);
    $news.read_vrb("read", "news");
.

method del_mode
    arg mode;
    
    if (!(.is_writable_by(sender())))
        throw(~perm, "Sender is not an owner.");
    if (mode in dict_keys(modes)) {
        modes = dict_del(modes, mode);
        return;
    }
    throw(~modenf, "Mode is not in users modes dictionary");
.

method add_command_alias_cmd
    arg com, input;
    var syn, alias, actual, tmpalias, tmpactual, num;
    
    if (sender() != this())
        throw(~perm, "Sender is not this");
    input = explode(input, "\"");
    
    // hell, i'll be nice and check for a few possibilities:
    syn = com + " \"<alias>\" [to] \"<actual command>\"";
    if (listlen(input) < 2)
        $parse.tell_error("Not enough arguments (enclose each alias in quotes)", syn);
    if (listlen(input) > 3)
        $parse.tell_error("Too many arguments (enclose each alias in quotes)", syn);
    
    // sort and get the alias and actual
    if (listlen(input) == 3)
        input = delete(input, 2);
    alias = input[1];
    actual = input[2];
    
    // make sure the %foo's match up
    tmpalias = alias;
    tmpactual = actual;
    while ("%" in tmpalias) {
        num = tmpalias[("%" in tmpalias) + 1];
        if (!toint(num))
            $parse.tell_error("referece cards must be integers", syn);
        num = "%" + num;
        if (!(num in tmpactual))
            $parse.tell_error("reference cards to not match up", syn);
        tmpalias = strsub(tmpalias, num, "");
        tmpactual = strsub(tmpactual, num, "");
    }
    if ("%" in tmpactual)
        $parse.tell_error("reference cards do not match up", syn);
    .add_command_alias(alias, actual);
    .tell(((("New command alias \"" + alias) + "\" => \"") + actual) + "\" added.");
.

method del_command_alias_cmd
    arg com, template;
    
    if (sender() != this())
        throw(~perm, "Sender is not this");
    template = explode(template, "\"")[1];
    catch ~aliasnf {
        .del_command_alias(template);
    } with handler {
        $parse.tell_error(("No command alias is found matching the template \"" + template) + "\".");
    }
    .tell(("Command alias \"" + template) + "\" deleted.");
.

method command_aliases_cmd
    arg com, what;
    var aliases, a, line;
    
    if (!what)
        what = this();
    else
        what = .match_env_nice(what);
    if ((what != this()) && (!(what.is_writable_by(this()))))
        $parse.tell_error("You are not allowed to read the command aliases on " + (what.namef()));
    .tell(("--- Command aliases on " + (what.namef('xref))) + ":");
    aliases = what.command_aliases();
    if (aliases) {
        for a in (aliases) {
            line = "  " + pad(("\"" + (a[1])) + "\"", ((.linelen()) - 10) / 2);
            .tell(((line + " => \"") + (a[2])) + "\"");
        }
    } else {
        .tell("  <none>");
    }
    .tell("---");
.

method _tell
    arg what;
    var conn, line;
    
    .perms(sender(), 'this);
    if (type(what) == 'list) {
        for line in (what)
            ._tell(line);
    } else {
        for conn in (connections)
            conn.tell(what);
    }
.

method add_filter
    arg filter, [position];
    
    if ((!(sender().has_ancestor($filters))) && (!(.is_writable_by(sender()))))
        throw(~perms, "%O does not have permission to remove filters.", sender());
    
    // do this in three steps, first make sure the posistion is valid,
    // then check for it already, then figure its insert position.
    position = [@position, 'first][1];
    if (!(position in ['last, 'first]))
        throw(~type, "Posistion types must be one of: 'last, 'first.");
    
    // does it exist?  If so remove it.
    if (filter in filters)
        filters = setremove(filters, filter);
    
    // figure position
    if (position == 'last)
        position = listlen(filters) + 1;
    else if (position == 'first)
        position = 1;
    filters = insert(filters, position, filter);
.

method del_filter
    arg filter;
    
    if ((!(sender().has_ancestor($filters))) && (!(.is_writable_by(sender()))))
        throw(~perms, "%O does not have permission to remove filters.", sender());
    if (filters) {
        filters = setremove(filters, filter);
        return;
    } else {
        throw(~nofilters, "You do not have any tell filters.");
    }
.

method wrap_cmd
    arg com, how;
    var filters;
    
    .perms(sender(), 'this);
    if (!(how in ["on", "off"]))
        return .tell("!  You can either turn line wrapping `on' or `off'");
    filters = .filters();
    if (how == "on") {
        if (filters && ($wrap_filter in filters))
            return .tell("!  You already have line wrapping on..");
        .add_filter($wrap_filter);
        return .tell("Line wrapping turned on.");
    } else {
        if (filters && (!($wrap_filter in filters)))
            return .tell("! You dont have line wrapping turned on.");
        .del_filter($wrap_filter);
        return .tell("Line wrapping turned off.");
    }
.

method filters
    .perms(sender());
    return filters;
.

method tell_traceback
    arg traceback, [args];
    var tt, name, eargs, error, str;
    
    // tt = tell_traceback || ['verbose, 0, "! "];
    str = [@args, ""][1];
    eargs = [@args, 0, 0][2];
    error = [@args, 0, 0, 0][3];
    tt = ['verbose, -1, "! "];
    switch (tt[1]) {
        case 'verbose:
            traceback = $parse.traceback(traceback, tt[2], tt[3], error);
            if (args)
                name = (| $list.to_english($list.map(args, 'namef, 'ref)) |);
            if (!name)
                name = "Object";
            .tell(strsub(traceback[1], "%O", name));
            .tell(sublist(traceback, 2));
        default:
            .tell(("! Internal error processing \"" + str) + "\", contact an administrator.");
    }
.

method set_tell_traceback
    arg which, [lines];
    
    .perms(sender(), 'manager);
    if (!(which in ['verbose, 'brief, 'none]))
        throw(~type, "Which style must either be 'verbose, 'brief, or 'none.");
    if (lines && (type(lines[1]) != 'integer))
        throw(~type, "You must specify the max lines as an integer.");
    if (!lines)
        lines = 0;
    else
        lines = lines[1];
    tell_traceback = [which, lines];
.

method namef
    arg [args];
    
    if (!args)
        args = [['name]];
    
    // first check for shortcuts, if so re-call this method correctly.
    if ((args[1]) == 'nactivity) {
        if (.activity())
            args = [['name], " (", ['activity], ")"] + sublist(args, 2);
        else
            args = [['name]] + sublist(args, 2);
    }
    if ((args[1]) == 'titled) {
        if (.title())
            args = [['name], ", ", ['title]] + sublist(args, 2);
        else
            args = [['name]] + sublist(args, 2);
    }
    return pass(@args);
.

method get_prompt
    return prompt;
.

method set_prompt
    arg what;
    
    .perms(sender(), 'this);
    prompt = what;
.

method prompt_cmd
    arg com, [args];
    
    .perms(sender(), 'this);
    if (!args)
        args = [""];
    .set_prompt(args[1]);
    .tell(("Prompt set as \"" + (args[1])) + "\"");
.

method password_cmd
    arg com, [args];
    var syn;
    
    .perms(sender(), 'parser);
    syn = ("`" + com) + " <old password> <new password>'";
    args = explode(@args);
    if ((listlen(args) < 2) || (listlen(args) > 2))
        $parse.tell_error("Not enough arguments specified (note: passwords cannot contain spaces).", syn);
    if (!(.check_password(args[1])))
        $parse.tell_error("Old password does not match up.", syn);
    catch any {
        .set_password(args[2]);
    } with handler {
        $parse.tell_error((traceback()[1])[2], syn);
    }
    .tell("Password changed.");
.

method set_title
    arg str;
    
    .perms(sender(), 'manager);
    if (strlen(str) > 30)
        throw(~type, "Titles must be under 30 characters.");
    title = str;
.

method watch_logins_cmd
    arg com, args;
    
    args = explode(args);
    if (!args)
        return .tell("You must specify someone to watch (logging in/out).");
    if ((args[1]) in ["all", "everybody", "everyone"]) {
        .set_watch_logins(1);
        .tell("You are now listening to login messages from everybody.");
    } else if ((args[1]) in ["none", "noone"]) {
        .set_watch_logins(0);
        .tell("You are now ignoring login messages.");
    } else {
        .tell("nothing else on this command is progged yet.");
    }
.

method delimited_tell
    arg text;
    var conn;
    
    // will adjust perms etc later.
    for conn in (.connections())
        conn.enh_tell([text]);
.

method match_context
    arg str;
    
    return context[str];
.

method context
    return context;
.

method match_environment
    arg str;
    var match, gend;
    
    match = (> pass(str) <);
    gend = (| match.gender() |);
    if (gend)
        context = dict_add(context, gend.pronoun('po), match);
    return match;
.

method non_terminated_tell
    arg text;
    var conn;
    
    if (.setting("terminated-tell")) {
        for conn in (.connections())
            conn.enh_tell([text]);
    } else {
        .tell(text);
    }
.

method set_name
    arg new_name, [ignore];
    var old_name, part, sname;
    
    .perms(sender(), 'manager);
    
    // so it doesnt bomb on .set_dbref
    if ((.namef()) == new_name)
        return;
    if ($user_db.valid_name(new_name))
        old_name = .namef();
    sname = $string.strip(new_name, $user_db.stripped_characters());
    catch any {
        pass(new_name);
        $user_db.key_changed(old_name, new_name);
        .set_dbref(tosym("user_" + sname));
    } with handler {
        (| pass(old_name) |);
        rethrow(error());
    }
.

method find_object_nice
    arg str, [args];
    var match;
    
    catch any {
        match = .find_object(str, @args);
    } with handler {
        .tell("!  " + ((traceback()[1])[2]));
        throw(~stop, "", 'no_traceback);
    }
    return match;
.

method find_object
    arg str, [args];
    var trace, match;
    
    // comprehensive matching method.
    // args define what to match.
    if (!args)
        args = ['environment];
    while (args) {
        switch (args[1]) {
            case 'environment:
                match = (| .match_environment(str) |);
            case 'user:
                match = (| $user_db.find(str) |);
            case 'grasp:
                match = (| $object.to_dbref(str) |);
        }
        if (match)
            return match;
        args = delete(args, 1);
    }
    throw(~objnf, ("No object found by the reference \"" + str) + "\".");
.

method creation_time
    return creation_time;
.

method age_cmd
    arg com, user;
    var person, time;
    
    .perms(sender(), 'parser);
    person = (| $user_db.find(user) |);
    if (!person) {
        person = (| .match_environment(user) |);
        if (!person)
            return .tell(("No person can be found by the name \"" + user) + "\".");
    }
    time = person.creation_time();
    .tell(((person.namef()) + " was created on ") + ($time.ldate(time)));
    .tell(((((person.gender()).pronoun('psc)) + " is ") + ($time.elapsed(time() - time, 'long))) + " old.");
.

method spawn_cmd
    arg com, args;
    var syn, new_obj, moved, name, parent, builder;
    
    if (sender() != this())
        throw(~perm, "Sender not this.");
    syn = ("`" + com) + " <parent> [named|called] <new object name>'";
    args = explode(args);
    builder = !($user in (.parents()));
    if ((!args) || (((listlen(args) < 1) && builder) || (listlen(args) < 2)))
        $parse.tell_error("Not enough arguments specified.", syn);
    args = [@args, ""];
    parent = args[1];
    parent = .match_env_nice(parent, syn);
    
    // users shouldn't be creating non VR objs.
    if ((!(parent.has_ancestor($thing))) && (!builder))
        $parse.tell_error("Parent is not a descendant of a Generic Thing ($thing).");
    if (match_begin("named", args[2]) || match_begin("called", args[2]))
        args = delete(args, 2);
    name = $list.to_string(sublist(args, 2));
    catch any {
        new_obj = parent.spawn();
        if (name) {
            if (!(new_obj.has_ancestor($named)))
                .tell("Object is not descended from $named.");
            else
                (> new_obj.set_name(name) <);
        }
        moved = (| new_obj.move_to(this()) |);
        .tell(((("Object " + (new_obj.namef('ref))) + " spawned from ") + (parent.namef('ref))) + ".");
    } with handler {
        $parse.tell_error((traceback()[1])[2], syn);
    }
.

method _prose_done
    arg text, obj, which;
    
    .perms(sender(), 'this);
    (> obj.set_prose(which, text) <);
    which = tostr(which);
    .tell(((($string.capitalize(which)) + " prose description for ") + (obj.namef('ref))) + " set.");
.

method prose_cmd
    arg cmd, args;
    var syn, which, obj;
    
    .perms(sender());
    syn = ("`" + cmd) + " <object> [long|short]`";
    args = explode(args);
    obj = [@args, ""][1];
    which = [@args, "short", "short"][2];
    if (!(which in ["short", "long"]))
        $parse.tell_error("Must either be \"short\" or \"long\" for the prose type.", syn);
    which = tosym(which);
    if (!obj)
        $parse.tell_error("No object specified.", syn);
    obj = .match_env_nice(obj);
    if (!(obj.has_ancestor($described)))
        $parse.tell_error((obj.namef('ref)) + " is not a describeable object!", syn);
    if (!(| obj.perms(this()) |))
        $parse.tell_error(("You do not have permission to write the prose description for " + (obj.namef('ref))) + ".", syn);
    if (which == 'short) {
        .prompt("Enter line: ", '_prose_done, obj, which);
    } else {
        .tell("Enter text for prose (end with a period or abort with `@abort`):");
        .read('_prose_done, obj, which);
    }
.

method status_cmd
    arg com, [args];
    var line;
    
    (> .perms(sender(), 'this) <);
    .tell(((($motd.server_name()) + ", ") + ($motd.server_title())) + ".");
    .tell("Startup time:     " + ($time.date($sys.startup_time())));
    .tell(("                  (" + ($time.to_english($sys.uptime()))) + ")");
    .tell("Last backup time: " + ($time.date($sys.last_backup())));
    .tell("Driver:           ColdMUD " + ($sys.version('driver)));
    .tell("Core:             the Cold Dark Core " + ($sys.version('core)));
.

method del_command_alias
    arg alias;
    
    (> .perms(sender()) <);
    (> pass(alias) <);
    if ((!(.command_aliases())) && ($command_aliases_parser in (.parsers()))) {
        .tell("Removing $command_aliases_parser from your list of parsers.");
        .del_parser($command_aliases_parser);
    }
.

method add_command_alias
    arg alias, actual;
    
    (> .perms(sender()) <);
    (> pass(alias, actual) <);
    if ((.command_aliases()) && (!($command_aliases_parser in (.parsers())))) {
        .tell("Adding $command_aliases_parser to your list of parsers..");
        .add_parser($command_aliases_parser, 'first);
    }
.

method logout_connection
    arg connection;
    
    if ((sender() != this()) || (definer() != caller()))
        throw(~perm, "Invalid access to private method.");
    .tell(("* * * " + ($integer.n_to_nth(listlen(.connections()) + 1))) + " Logout sucessful * * *");
.

method tell_ctext
    arg ctext, originator;
    var output, type;
    
    type = (.setting("content-type")) || "text/plain";
    output = ctext.translate_to(type);
    .tell(output);
.

parent #30
object #936

var 1 child_index 0
var 1 owners [#936]
var 1 owned [#675, #1170, #2, #12, #0, #7791, #40, #1093, #10, #790, #1032, #7794, #7968, #1182, #1184, #1183, #1095, #1094, #247, #22, #21, #140, #2250, #592, #185, #30, #31, #7232, #936, #32, #33, #37, #16, #1178, #15, #1139, #35, #664, #19, #27, #86, #922, #1140, #25, #28, #1162, #758, #747, #1138, #23, #26, #24, #984, #17, #1179, #1204, #8019, #282, #465, #888, #2485, #1165, #1142, #3, #2490, #2489, #2488, #2486, #2487, #2491, #2494, #6, #4, #5, #9, #7, #2495, #1166, #310, #49, #51, #46, #44, #13, #740, #45, #720, #334, #333]
var 1 fertile 0
var 16 commands []
var 16 shortcuts []
var 922 command_aliases []
var 15 verbs #[]
var 19 contents []
var 23 location #21
var 30 password "*"
var 30 connected_at 0
var 30 last_command_at 0
var 30 connections []
var 30 creation_time 759878010
var 30 action ""
var 1 inited 1
var 30 modes #[]
var 682 letters #[]
var 682 letters_index #[]
var 682 senders 1
var 682 readers [#37]
var 682 notify [#37]
var 682 last_letter 0
var 679 subscribed #[[#936, 0]]
var 1179 gender #1182
var 23 obvious 1
var 17 prose #[]
var 30 prompt ""
var 1 manager #936
var 1 writable [#936]
var 1 readable ['parameters, 'methods, 'code]
var 30 parsers [#2000, #2321]
var 30 tell_traceback ['brief, 0]
var 30 context #[]
var 1 quota 75000
var 1 dbref 'no_one
var 2787 name ['prop, "No One"]
var 2787 name_aliases ["No", "One"]
var 4309 user_data #[['real_name, [1, "???"]], ['email, [1, "???"]]]

parent #16
object #27

var 27 user 0
var 27 addr 0
var 27 port 0
var 27 buffer `[]
var 27 connect_help ["Connection HELP", "===============", "", "Connecting as a guest:    'connect guest <name> <email>'", "              Example:    'connect guest John Doe johnd@site.usa.com'", "", "Connecting as a user:     'connect <name> <password>'", "             Example:     'connect John Doe mypassword'", "", "Quitting (this screen):   '@quit'   or   'quit'", "", "Connected User's Listing: '@who'    or   'who'", "Connection HELP", "===============", "", "Connecting as a guest:    'connect guest <name> <email>'", "              Example:    'connect guest John Doe johnd@site.usa.com'", "", "Connecting as a user:     'connect <name> <password>'", "             Example:     'connect John Doe mypassword'", "", "Quitting (this screen):   'quit'   or   '@quit'", "", "Connected User's Listing: 'who'    or   '@who'"]
var 27 connect_notes []
var 16 commands [["@quit|QUIT", 'quit_cmd], ["h?elp", 'help_cmd], ["@who|WHO", 'who_cmd], ["c?onnect guest *", 'connect_guest_cmd], ["c?onnect *", 'connect_cmd], ["m?otd", 'motd_cmd], ["c?reate *", 'create_cmd]]
var 16 shortcuts []
var 1 inited 1
var 1 child_index 5479
var 1 owners [#936]
var 1 fertile 1
var 1 owned []
var 1 manager #27
var 1 writable [#27]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'old_connection
var 27 ip 0

method init_old_connection
    .perms(caller(), $root);
    user = 0;
    addr = 0;
    port = 0;
    ip = 0;
    buffer = `[];
.

method uninit_old_connection
    .perms(caller(), $root);
    user.connection_logged_out(addr, port);
.

method tell
    arg what, [format];
    var l;
    
    // Crag: added caller() != $parse so I can use $parse.tell_error().
    // sigh...
    if ((sender() != this()) && ((sender() != user) && (caller() != $parse)))
        throw(~perm, "Sender not this or the user.");
    
    // if (user)
    //  .prompt(user.get_prompt(), 1);
    echo(buffer_from_strings([what]));
    
    // if (user)
    //  .prompt(user.get_prompt(), 0);
.

method connect
    arg [args];
    var x, addr_arg, port_arg;
    
    if (sender() != 0)
        throw(~perm, "Sender not the server.");
    addr_arg = args[1];
    port_arg = args[2];
    addr = hostname(addr_arg);
    ip = addr_arg;
    port = port_arg;
    if (!(| .motd() |)) {
        .tell("Error displaying the Message of the Day, hit enter once, if this problem");
        .tell("continues email: " + ($sys.get_system_email('login)));
    }
    $sys.connection_starting();
    (| $scheduler.add_task(300, 'timeout) |);
.

method disconnect
    if (sender() != 0)
        throw(~perm, "Sender not the server.");
    .tell("Goodbye.");
    .destroy();
.

method parse
    arg incoming;
    var lines, line, loc;
    
    if ((sender() != 0) && (caller() != 0))
        throw(~perm, "Sender and caller are not the server");
    lines = buffer_to_strings(buffer_append(buffer, incoming));
    buffer = lines[listlen(lines)];
    for line in (sublist(lines, 1, listlen(lines) - 1))
        (| .parse_line(line) |);
.

method parse_line
    arg str;
    var cmd, x, coms;
    
    if ((caller() != definer()) || (sender() != this()))
        throw(~perm, "Invalid access to private method.");
    
    // send it to the user object, otherwize they are at the MOTD
    if (user) {
        if ((user.parse_line(str)) == 'disconnect)
            disconnect();
        return;
    }
    
    // they are at the MOTD
    // Display tracebacks, even though user may be clueless
    catch any {
        cmd = .match_command(str);
        if (cmd) {
            .(cmd[1])(@cmd[2]);
        } else {
            .tell("");
            if (str)
                .tell(("I don't understand \"" + ($string.chop(str, 57))) + "\".");
            .tell("Try: help, quit, who, motd, create, connect, or connect guest.");
        }
    } with handler {
        if (((traceback()[1])[3]) != 'no_traceback) {
            for str in (traceback())
                .tell(str);
        }
    }
    if (!user)
        .enh_tell(["", "> "]);
.

method user
    return user;
.

method addr
    return addr;
.

method port
    return port;
.

method connect_cmd
    arg com, words;
    var words, u, password, salt, syn, name, passwd;
    
    .perms(sender(), 'this);
    
    // arrg, this is kludgy, but its the best we can do on $old_connection
    syn = "`connect <name> <pass>' (last word is taken as the password)";
    
    // Get user name and password--sort accordingly
    words = explode(words);
    if (listlen(words) < 2)
        $parse.tell_error(syn);
    passwd = words[listlen(words)];
    name = $list.to_string(sublist(words, 1, listlen(words) - 1));
    
    // Look for a user with the given name.
    catch ~namenf {
        u = $user_db.find(name);
    } with handler {
        $parse.tell_error("Either that user does not exist or has a different password.", syn);
    }
    
    // Check if the password is correct.
    if (!(u.check_password(passwd)))
        $parse.tell_error("Either that user does not exist or has a different password.", syn);
    
    // Log the user in.
    user = u;
    user.connection_logged_in(addr, port);
.

method create_cmd
    arg com, words;
    var words, syn;
    
    syn = "!  Usage: `create <name> <password> <email@host>'";
    if (sender() != this())
        throw(~perm, "Sender is not this.");
    
    // Get user name, password, and email.
    words = explode(words);
    if (listlen(words) != 3)
        return .tell(syn);
    
    // Create a new user object.
    catch any {
        user = $sys.create_user(words[1], words[2], words[3]);
    } with handler {
        .tell(syn);
        switch (error()) {
            case ~duplicate:
                .tell(("!  The user " + toliteral(words[1])) + " already exists.");
            default:
                .tell("!  There was a problem creating you:");
                .tell("!  => " + ((traceback()[1])[2]));
                .tell("!  If there is a problem contact: " + ($sys.get_system_email('login)));
    
                // $sys.log(traceback());
        }
        if (user) {
            (| user.destroy() |);
            user = 0;
        }
        return;
    }
    
    // Log the user in.
    user.connection_logged_in(addr, port);
.

method quit_cmd
    arg dummy;
    
    if (sender() != this())
        throw(~perm, "Sender is not this.");
    .tell("Goodbye.");
    disconnect();
.

method user_going_away
    if (caller() != $user)
        throw(~perm, "Caller is not $user.");
    disconnect();
.

method connect_guest_cmd
    arg com, com2, words;
    var syn, email, name, result;
    
    .perms(sender(), 'this);
    syn = "=> Syntax: 'connect guest <name> <email>' (type 'help' for more help)";
    
    // Get user name and password.
    words = explode(words);
    if (listlen(words) < 2)
        return .tell(syn);
    name = $list.to_string(sublist(words, 1, listlen(words) - 1));
    email = words[listlen(words)];
    result = $code.valid_email(email);
    if ((result[1]) != 'valid) {
        switch (result[1]) {
            case 'invalid:
                .tell("!  The given email address is not a legitimate address.");
                .tell("!  Specify both username and hostname (do not use brackets).");
                return;
            case 'invip, 'invhostname:
                .echo($string.wrap_line(((("The hostname \"" + (result[3])) + "\" is invalid, when in actuality you are connecting from \"") + ((addr == "-1") ? ip | addr)) + "\".  The server is not currently locking out invalid email addresses, although your connection has been noted (We do realize that some hosts may not function normally).", 79, "!  ", 1));
                $channels.announce('System, ((((((("Invalid Connection Email: " + email) + " <") + addr) + ":") + ip) + "> (") + name) + ")");
        }
    }
    catch any {
        user = $sys.create_user(name, 0, email, 'anonymous_class);
    } with handler {
        .tell(syn);
        switch (error()) {
            case ~duplicate:
                .tell(("!  The name " + toliteral(words[1])) + " is already in use.");
            default:
                .tell("!  There was a problem creating you:");
                .tell("!  => " + ((traceback()[1])[2]));
                .tell("!  If there is a problem contact: " + ($sys.get_system_email('login)));
        }
        $brandon.tell_traceback(traceback());
    
        // $sys.log(traceback());
        return;
    }
    
    // Log the user in.
    $sys.log((("GUEST: " + (words[1])) + " ") + (words[2]));
    user.connection_logged_in(addr, port);
.

method echo_file
    arg what;
    
    if ((sender() != this()) && (sender() != user))
        throw(~perm, "Sender not this or the user.");
    echo_file(what);
.

method spiffy_quote
    return $code.random_theme_quote();
.

method connect_help
    return connect_help;
.

method who_cmd
    arg com;
    var l;
    
    for l in ($code.generate_listing($user_db.connected()))
        .tell(l);
.

method motd
    var line, stuff;
    
    // a slightly cooler in-db welcome message
    if ((sender() != this()) || (caller() != definer()))
        throw(~perm, "Invalid access to private method.");
    .echo($login.build('default));
    .tell("");
    .echo(" ** Use 'H?elp' for a list of commands **", 'center);
    .tell("");
.

method enh_tell
    arg what;
    var elem, out;
    
    // Echo list consisting of buffers and strings.
    // if (!$sys.is_system(sender()) && (caller() != $user || sender() != this()))
    //  throw(~perm, "Permission Denied: Invalid call to a private method.");
    for elem in (what) {
        if (type(elem) == 'string)
            echo(buffer_truncate(buffer_from_strings([elem]), strlen(elem)));
        else
            echo(elem);
    }
.

method enh_tell_move
    arg X, Y;
    
    // Move cursor on most ANSI and VT terminals to X,Y
    .enh_tell([`[27], ((("[" + tostr(Y)) + ";") + tostr(X)) + "H"]);
.

method help_cmd
    arg com;
    var l;
    
    .perms(sender(), 'this);
    for l in ($old_connection.connect_help())
        .tell(l);
.

method connect_notes
    return connect_notes;
.

method prompt
    arg prompt, [erase];
    var buf;
    
    buf = buffer_from_strings([prompt]);
    buf = buffer_truncate(buf, buffer_len(buf) - 2);
    erase = erase && (erase[1]);
    if (erase) {
        buf = buffer_len(buf);
        while (buf) {
            echo(`[8]);
            buf = buf - 1;
        }
    } else {
        echo(buf);
        if (prompt)
            echo(`[255, 249]);
    }
.

method echo
    arg what, [format];
    var l;
    
    // the difference being that this one is designed for non-connected conns
    if ((sender() != this()) && (sender() != user))
        throw(~perm, "Sender not this or the user.");
    format = [@format, 'none][1];
    if (type(what) == 'list) {
        for l in (what)
            .echo(l, format);
    } else {
        switch (format) {
            case 'center:
                what = $string.center(what, 79);
        }
        echo(buffer_from_strings([what]));
    }
.

method motd_cmd
    arg [args];
    
    .perms(sender(), 'this);
    .motd();
.

method timeout
    .perms(sender(), 'this);
    if (!user) {
        .tell("Timeout (5 minutes).");
        disconnect();
    }
.

parent #12
object #13

var 1 child_index 0
var 1 owners [#936]
var 1 fertile 0
var 1 inited 1
var 1 owned []
var 1 manager #13
var 1 writable [#13]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'list

method to_string
    arg list, [sep];
    var str, part;
    
    // uses $data.unparse() rather than tostr()
    if (!list)
        return "";
    sep = [@sep, " "][1];
    str = tostr(list[1]);
    for part in (delete(list, 1))
        str = (str + sep) + tostr(part);
    return str;
.

method to_english
    arg list, [options];
    var empty, and, sep;
    
    // uses $data.unparse() rather than tostr()
    empty = [@options, "nothing"][1];
    switch (listlen(list)) {
        case 0:
            return empty;
        case 1:
            return tostr(list[1]);
    }
    and = [@options, " and ", " and "][2];
    sep = [@options, ", ", ", ", ", "][3];
    return ((.to_string(delete(list, listlen(list)), sep)) + and) + tostr(list[listlen(list)]);
.

method map
    arg list, method, [args];
    var out, x;
    
    // call 'method on each object, return results.
    out = [];
    for x in (list)
        out = [@out, x.(method)(@args)];
    return out;
.

method filter
    arg list, method, [args];
    var out, x;
    
    // similar to .map, but returns a list of objects which returned a
    // true value from 'method.
    out = [];
    for x in (list) {
        if (x.(method)(@args))
            out = [@out, x];
    }
    return out;
.

method sort
    arg list, [sortby];
    
    // calls ._sort().  Does not set an element to sort by yet, but should
    // eventually will have to fix.
    return ._sort(list, 1, listlen(list));
.

method _sort
    arg lst, x, y;
    var p, i, j;
    
    switch ((y - x) + 1) {
        case 0, 1:
            return lst;
        case 2:
            if ((lst[x]) <= (lst[y]))
                return lst;
            p = lst[x];
            lst = replace(lst, x, lst[y]);
            lst = replace(lst, y, p);
            return lst;
        case 3:
            if ((lst[x]) <= (lst[x + 1])) {
                if ((lst[x + 1]) <= (lst[y])) {
                } else if ((lst[x]) <= (lst[y])) {
                    p = lst[x + 1];
                    lst = replace(lst, x + 1, lst[y]);
                    lst = replace(lst, y, p);
                } else {
                    p = lst[x];
                    lst = replace(lst, x, lst[y]);
                    lst = replace(lst, y, lst[x + 1]);
                    lst = replace(lst, x + 1, p);
                }
            } else if ((lst[x]) <= (lst[y])) {
                p = lst[x];
                lst = replace(lst, x, lst[x + 1]);
                lst = replace(lst, x + 1, p);
            } else if ((lst[x + 1]) <= (lst[y])) {
                p = lst[x];
                lst = replace(lst, x, lst[x + 1]);
                lst = replace(lst, x + 1, lst[y]);
                lst = replace(lst, y, p);
            } else {
                p = lst[x];
                lst = replace(lst, x, lst[y]);
                lst = replace(lst, y, p);
            }
            return lst;
    }
    p = lst[x];
    i = x;
    j = y;
    while (1) {
        while ((i < j) && (p <= (lst[j])))
            j = j - 1;
        if (i == j)
            break;
        lst = replace(lst, i, lst[j]);
        i = i + 1;
        while ((i < j) && (p >= (lst[i])))
            i = i + 1;
        if (i == j)
            break;
        lst = replace(lst, j, lst[i]);
        j = j - 1;
    }
    lst = replace(lst, i, p);
    lst = ._sort(lst, x, i - 1);
    lst = ._sort(lst, i + 1, y);
    return lst;
.

method columnize
    arg list, cols, [rest];
    var width, lines, line, separator, linelength, curcol;
    
    // turn [...] into ".   .   ."
    // rest[1]==separator; rest[2]==linelength
    separator = [@rest, "   "][1];
    linelength = [@rest, 78, 78][2];
    width = (linelength / cols) - strlen(separator);
    lines = [];
    while (list) {
        line = pad(list[1], width);
        list = sublist(list, 2);
        for curcol in [2 .. cols] {
            if (list) {
                line = (line + separator) + pad(list[1], width);
                list = sublist(list, 2);
            }
        }
        lines = [@lines, line];
    }
    return lines;
.

method reverse
    arg list;
    var elm, reversed;
    
    // .reverse(list)
    // -> list with its elements reversed
    reversed = [];
    for elm in (list)
        reversed = [elm, @reversed];
    return reversed;
.

method compress
    arg list;
    var out, last, x;
    
    // [a,a,b,b,c,c,d,d] => [a,b,c,d]
    // removes duplicate entries in a list
    last = list[1];
    out = [last];
    for x in (delete(list, 1)) {
        if (x != last) {
            out = [@out, x];
            last = x;
        }
    }
    return out;
.

method last
    arg list;
    
    return list[listlen(list)];
.

method count
    arg elem, list;
    var count;
    
    // count of elem in list
    while (elem in list) {
        count = count + 1;
        list = sublist(list, (elem in list) + 1);
    }
    return count;
.

method element_maxlength
    arg list;
    var elm, max, len;
    
    // Returns tostr(element) string in list.
    if (type(list) != 'list)
        throw(~type, "Second argument is not a list");
    max = 0;
    for elm in (list) {
        len = strlen(tostr(elm));
        max = (len > max) ? len | max;
    }
    return max;
.

method nth_element_maxlength
    arg lists, element;
    var list, max, len;
    
    // Returns longest string whose index is element in one of the lists in lists.
    if (type(element) != 'integer)
        throw(~type, "First argument is not an integer");
    if (type(lists) != 'list)
        throw(~type, "Second argument is not a list");
    max = 0;
    for list in (lists) {
        len = strlen(tostr(list[element]));
        if (len > max)
            max = len;
    }
    return max;
.

method numbered_text
    arg text;
    var line;
    
    // receives a list of strings, returns that list with line numbers pre-pended
    for line in [1 .. listlen(text)]
        text = replace(text, line, ((((line < 10) ? " " | "") + tostr(line)) + ": ") + (text[line]));
    return text;
.

method slice
    arg big_list, element;
    var list, ret_list;
    
    // Return elementh' element of all lists in big_list
    // No type or length checking done for speed purposes.
    ret_list = [];
    for list in (big_list)
        ret_list = [@ret_list, list[element]];
    return ret_list;
.

method swap
    arg list, a, b;
    var holder;
    
    // swap elements at indexes a and b
    holder = (> list[a] <);
    list = (> replace(list, a, list[b]) <);
    list = replace(list, b, holder);
    return list;
.

method max
    arg [list];
    
    // return greatest element of list (no type checking performed)
    // if list is [], returns 0
    while (listlen(list) > 1) {
        if ((list[1]) > (list[2]))
            list = delete(list, 2);
        else
            list = delete(list, 1);
    }
    return [@list, 0][1];
.

method min
    arg [list];
    
    // return least element of list (no type checking performed)
    // if list is [], returns 0
    while (listlen(list) > 1) {
        if ((list[1]) < (list[2]))
            list = delete(list, 2);
        else
            list = delete(list, 1);
    }
    return [@list, 0][1];
.

method lcolumnize
    arg list, linelen, [seperator];
    var lines, mlen, cols, width, c, line;
    
    // var width, lines, line, separator, linelength, curcol;
    // turn [...] into ".   .   ."
    // this one just fits the columns into the linelen
    seperator = [@seperator, " "][1];
    lines = [];
    mlen = (.element_maxlength(list)) + 1;
    cols = (linelen > mlen) ? linelen / mlen | 1;
    width = linelen / cols;
    while (list) {
        line = pad(list[1], width);
        list = sublist(list, 2);
        for c in [2 .. cols] {
            if (list) {
                line = (line + seperator) + pad(list[1], width);
                list = sublist(list, 2);
            }
        }
        lines = [@lines, line];
    }
    return lines;
.

method swapsort
    arg list, [sort_by];
    var bot_elem, cur_elem, elem, compare;
    
    // note: iterative implementation allows sorts of extra-long lists
    elem = [@sort_by, 1];
    compare = [@sort_by, 'gt, 'lt][2];
    for bot_elem in [1 .. listlen(list)] {
        for cur_elem in [bot_elem + 1 .. listlen(list)] {
            if (._swap_compare(list[bot_elem], list[cur_elem], compare, elem))
                list = $list.swap(list, bot_elem, cur_elem);
        }
    }
    return list;
.

method _swap_compare
    arg elem1, elem2, compare, [elem];
    
    elem = [@elem, 1][1];
    switch (compare) {
        case 'lt:
            return (elem1[elem]) < (elem2[elem]);
        case 'gt:
            return (elem1[elem]) > (elem2[elem]);
        default:
            return 0;
    }
.

method heapsort
    arg list, [sort_by];
    var heap, sort_type, sort_elem;
    
    sort_elem = [@sort_by, 1][1];
    sort_type = [@sort_by, 'gt, 'gt][2];
    switch (sort_type) {
        case 'gt:
            heap = $small_first_heap_class.new(list, sort_elem);
        default:
            return list;
    }
    list = [];
    while (heap.length()) {
        list = heap.element(1);
        heap = heap.del(1);
    }
    return list;
.

method map_to_english
    arg list, method, [args];
    
    // because I (Lynx) am lazy
    return .to_english(.map(list, method, @args));
.

method map_to_string
    arg list, method, [args];
    
    // because I (Lynx) am lazy
    return .to_string(.map(list, method, @args));
.

method flatten
    arg list;
    var toret, elem;
    
    // [[[x], x], x]   =>   [x, x, x]
    toret = [];
    for elem in (list) {
        if (type(elem) == 'list)
            toret = toret + (.flatten(elem));
        else
            toret = toret + [elem];
    }
    return toret;
.

method sum
    arg ints;
    var ret;
    
    // returns a sum of each integer in the list.
    ret = 0;
    while (ints) {
        ret = ret + (ints[1]);
        ints = delete(ints, 1);
    }
    return ret;
.

method non_alphanumeric
    // returns nun-alphanumeric in a list of characters
    return ["!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "+", "-", "=", "~", "`", "'", "{", "}", "[", "]", "|", "/", "?", "\"", "\\", ",", ".", "<", ">", ";", ":", " "];
.

method numbers
    // returns a list of numbers
    return ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
.

method alphabet
    //returns the alphabet in a list
    return ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];
.

method center_lines
    arg lines, width, [args];
    var output, line;
    
    output = [];
    for line in (lines)
        output = [@output, $string.center(line, width, @args)];
    return output;
.

method to_buffer
    arg list;
    
    // assumes this is a list of strings (for now)
    return buffer_from_strings(list);
.

parent #7791
object #7794

var 1 dbref 'daemon
var 1 child_index 5
var 1 fertile 0
var 1 manager #37
var 1 owned []
var 1 owners [#936]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 7791 buffer `[]
var 7791 ip ""
var 7791 hostname ""
var 7791 port 0
var 7791 socket 0
var 7791 active 0
var 1 inited 1
var 7794 current_receiver 0
var 7794 connections []
var 7794 interface 0
var 7794 timeout 0
var 7794 default_port 0

method new_connection
    var num, tmp;
    
    // we have a new connection.
    if ((sender() != this()) || (caller() != definer()))
        throw(~perm, "Invalid call to private method.");
    catch any {
        // Get a good dbref
        num = listlen(connections);
        tmp = (tostr(.dbref('symbol)) + "_") + tostr(num);
        while ((| get_name(tosym("connection_" + tmp)) |)) {
            num = num + 1;
            tmp = (tostr(.dbref('symbol)) + "_") + tostr(num);
        }
    
        // Create a new receiver
        current_receiver = $connection.spawn(tmp);
        current_receiver.add_writer(this());
        current_receiver.set_manager(current_receiver);
        current_receiver.initialize_connection(interface, timeout);
    
        // bind it
        (> .bind(.port(), current_receiver) <);
    
        // add it to the list
        connections = setadd(connections, current_receiver);
    } with handler {
        // switch (error()) {
        //    case ~bind:
        (| current_receiver.close() |);
        (| .stop_listening() |);
        rethrow(error());
    
        // }
    }
.

method connection_starting
    // called by $connection.connect()
    (> .perms(caller(), $connection) <);
    (> .new_connection() <);
.

method connection_ending
    // called by $connection.disconnect()
    (> .perms(caller(), $connection) <);
    (> .old_connection(sender()) <);
.

method old_connection
    arg obj;
    
    // called by $daemon.connection_ending
    (> .perms(sender(), 'this) <);
    connections = setremove(connections, obj);
.

method uninit_daemon
    (> .perms(caller(), $root) <);
    (> .reset_daemon() <);
    (| current_receiver.daemon_reset() |);
    interface = 0;
    current_receiver = 0;
    connections = [];
    timeout = -1;
    default_port = 0;
.

method init_daemon
    (> .perms(caller(), $root) <);
    interface = 0;
    current_receiver = 0;
    connections = [];
    timeout = -1;
    default_port = 0;
.

method reset_daemon
    arg [args];
    var c, cons;
    
    (> .perms(sender(), 'this) <);
    args = [@args, 'continue][1];
    cons = connections + (current_receiver ? [current_receiver] | []);
    for c in (cons) {
        (| c.receive("DAEMON RESET", 'daemon_reset) |);
        (| c.close() |);
    }
    current_receiver = 0;
    connections = [];
    if (args == 'continue)
        (> .new_connection() <);
.

method set_interface
    arg obj;
    
    (> .perms(sender(), 'manager) <);
    interface = obj;
.

method start_listening
    arg [port];
    
    (> .perms(sender(), 'manager) <);
    port = [@port, default_port][1];
    .set_port(port);
    .new_connection();
.

method stop_listening
    (> .perms(sender(), 'manager) <);
    (| .set_port(0) |);
    (| current_receiver.close() |);
    (| .reset_daemon('stop) |);
    (| .unbind(.port()) |);
.

method set_timeout
    arg seconds;
    
    (> .perms(sender(), 'manager) <);
    timeout = seconds;
.

method default_port
    return default_port;
.

method set_default_port
    arg port;
    
    (> .perms(sender(), 'manager) <);
    if (type(port) != 'integer)
        throw(~type, "Port must be submitted as an integer.");
    default_port = port;
.

method connections
    return connections;
.

method startup
    arg [args];
    var name, opt, port;
    
    (> .perms(caller(), $sys) <);
    name = tostr(.dbref('symbol));
    name = "-p" + substr(name, 1, ("_" in name) - 1);
    opt = name in args;
    port = (| toint(args[opt + 1]) |);
    (| .stop_listening() |);
    .start_listening(port || default_port);
.

parent #7794
object #7968

var 1 dbref 'http_daemon
var 1 child_index 0
var 1 fertile 0
var 1 manager #7968
var 1 owned [#9658]
var 1 owners [#936]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 7791 buffer `[]
var 7791 ip ""
var 7791 hostname ""
var 7791 port 1180
var 7791 socket 0
var 7791 active 0
var 7794 interface #7969
var 7794 current_receiver #9670
var 7794 connections [#9670]
var 7794 timeout 0
var 1 inited 1
var 7794 default_port 1180

parent #2
parent #2787
object #1204

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 1 inited 1
var 1 manager #1204
var 1 writable [#1204]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'realms_class
var 2787 name ['uniq, "Generic Realms Class Frob"]
var 2787 name_aliases []
var 1204 local #[[#7671, ['interior]], [#7672, ['interior]], [#7675, ['interior]], [#7692, ['interior]], [#7696, ['interior]], [#7703, ['interior]], [#7704, ['interior]]]

method new
    arg [args];
    
    args = [@args, ['interior]][1];
    (> $places.is_place(sender()) <);
    local = dict_add(local, sender(), args);
    return <this(), args>;
.

method destroyed
    arg frob;
    
.

method init_realms_class
    .perms(caller(), $root);
    local = #[];
.

method uninit_realms_class
    var x;
    
    .perms(caller(), $root);
    for x in (local)
        (x[1]).set_realm($realm_of_creation, 'interior);
.

method place_destroyed
    arg place;
    var x;
    
    local = dict_del(local, place);
    for x in (dict_keys(local))
        (| x.place_destroyed(place) |);
.

method local
    return local;
.

parent #30
object #7232

var 1 dbref 'reaper
var 1 child_index 0
var 1 fertile 0
var 1 manager #7232
var 1 owned [#6099, #4578, #9443, #9445, #9417, #9420, #9300, #9615, #1387, #1388, #4309, #4348, #5205, #7245, #7248, #7261]
var 1 owners [#936]
var 1 writable []
var 1 readable []
var 16 commands []
var 16 shortcuts []
var 15 verbs #[]
var 4309 user_data #[['real_name, [1, "???"]], ['email, [1, "???"]]]
var 666 current_help #534
var 666 help_dict #[["*", #534], ["help", #547], ["**", #535]]
var 922 command_aliases []
var 2787 name ['prop, "Reaper"]
var 2787 name_aliases []
var 1179 gender #1182
var 17 prose #[]
var 1178 messages #[]
var 19 contents []
var 23 location #247
var 23 obvious 1
var 28 body_parts #[]
var 30 password "*"
var 30 connected_at 0
var 30 last_command_at 0
var 30 connections []
var 30 creation_time 780375877
var 30 parsers [#2000, #2321]
var 30 filters []
var 30 action ""
var 30 prompt ""
var 30 context #[]
var 1 quota 75000
var 1 inited 1

parent #1170
object #246

var 1 child_index 0
var 1 owners [#246]
var 1 fertile 0
var 16 commands []
var 16 shortcuts []
var 15 verbs #[]
var 19 contents []
var 23 location #22
var 30 password "*"
var 30 connected_at 0
var 30 last_command_at 0
var 30 connections []
var 30 creation_time 758252662
var 30 action ""
var 1 inited 1
var 1 owned [#246]
var 1 manager #246
var 1 writable [#246]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'housekeeper

method did_disconnect
    var task_queue, task;
    
    if (caller() != $user)
        throw(~perm, "Permission denied");
    
    // because of guests
    if (valid(sender()))
        $scheduler.add_task(300, 'move_user_home, sender());
.

method _move_user_home
    arg who;
    var home, curloc;
    
    .perms(caller(), 'this);
    if (who.connected())
        return;
    curloc = who.location();
    home = who.home();
    if (curloc == home)
        return;
    curloc.sending_user_home(who);
    who.move_to(home);
.

method move_user_home
    arg who;
    var home, curloc;
    
    .perms(sender(), 'system);
    if (who.connected())
        return;
    curloc = who.location();
    home = who.home();
    if (curloc == home)
        return;
    who.move_to(home);
    curloc.did_housekeep(who);
.

parent #30
object #134

var 1 child_index 44
var 1 owners [#134, [#0]]
var 1 fertile 0
var 16 commands []
var 16 shortcuts []
var 15 verbs #[]
var 19 contents []
var 23 location #21
var 30 password "*"
var 30 connected_at 0
var 30 last_command_at 0
var 30 connections []
var 1 inited 1
var 1 owned [#134]
var 922 command_aliases []
var 30 modes #[]
var 682 letters #[]
var 682 letters_index #[]
var 682 senders 1
var 682 readers 1
var 682 notify [#47]
var 682 last_letter 0
var 679 subscribed #[[#134, 0]]
var 1179 gender #1182
var 23 obvious 1
var 17 prose #[]
var 30 prompt ""
var 1 manager #134
var 1 writable [#134]
var 1 readable ['parameters, 'methods, 'code]
var 30 parsers [#2000, #2321]
var 30 tell_traceback ['brief, 0]
var 30 context #[]
var 1 quota 75000
var 1 dbref 'guest
var 2787 name ['uniq, "Generic Guest Object"]
var 2787 name_aliases []
var 4309 user_data #[['real_name, [1, "???"]], ['email, [1, "???"]]]

method init_guest
    .perms(caller(), $root);
    .add_filter($wrap_filter);
    .set_title("a guest");
.

method logout
    arg connection;
    
    (| pass(connection) |);
    .destroy();
.

method title_cmd
    arg com, str;
    
    .perms(sender(), 'parser);
    .tell("Guests are not allowed to change their titles.");
.

parent #1170
object #282

var 1 child_index 0
var 1 owners [#936]
var 1 fertile 0
var 1 inited 1
var 282 task_index 2
var 282 task_queue [[2, 300, 784609082, #9686, #27, 'timeout, ['system], []]]
var 30 password 0
var 30 connected_at 0
var 30 last_command_at 0
var 30 connections []
var 30 creation_time 758802496
var 30 action ""
var 1 owned []
var 1 info []
var 1 manager #282
var 1 writable [#282]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'scheduler
var 282 sub_schedulers [#5264]

method remove_first_task
    var len, i, min;
    
    // sender must be an agent, or admin
    catch any {
        if (caller() != this())
            throw(~perm, "Invalid call to private method");
        len = listlen(task_queue);
        i = 1;
        while (i != len) {
            min = len;
            if (((i * 2) < len) && (((task_queue[i * 2])[2]) < ((task_queue[min])[2])))
                min = i * 2;
            if ((((i * 2) + 1) < len) && (((task_queue[(i * 2) + 1])[2]) < ((task_queue[min])[2])))
                min = (i * 2) + 1;
            task_queue = replace(task_queue, i, task_queue[min]);
            i = min;
        }
        task_queue = sublist(task_queue, 1, len - 1);
    } with handler {
        // $sys.log(traceback());
    }
    if (!task_queue)
        task_index = 1;
.

method task_queue
    // sender must be system, for now
    .perms(sender(), 'system);
    return task_queue;
.

method del_task
    arg tid;
    var task;
    
    // sender must be system, for now.
    .perms(sender(), 'system);
    if (type(tid) != 'integer)
        throw(~type, "Task Identification must be an integer");
    for task in (task_queue) {
        if ((task[1]) == tid) {
            task_queue = delete(task_queue, task in task_queue);
            return 1;
        }
    }
    throw(~tasknf, "No task found by that TID");
.

method add_task
    arg time, method, [args];
    var task, i, tid, flags;
    
    // use `@info $scheduler' for more information. 
    // [tid, time, time(), sender(), caller(), method, flags, args]
    // time is seconds from insertion time that it will be run (ie 300 == 5 mins)
    //
    if ((type(time) != 'integer) || ((type(method) != 'symbol) || (type(args) != 'list)))
        throw(~type, "Arguments are not an integer, symbol, and list.");
    if (time < 1)
        throw(~time, "Time is negative.");
    if (time > 31536000)
        throw(~time, "Try to schedule a task LESS than a year from now?");
    
    //
    task_index = task_index + 1;
    tid = task_index;
    
    // flags can be set in a system only add_task, for now set them as 'system
    flags = ['system];
    task = [tid, time, time(), sender(), caller(), method, flags, args];
    task_queue = task_queue + [task];
    i = listlen(task_queue);
    
    //
    while ((i > 1) && ((task[2]) < (((task_queue[i / 2])[2]) + ((task_queue[i / 2])[3])))) {
        task_queue = replace(task_queue, i, task_queue[i / 2]);
        i = i / 2;
    }
    task_queue = replace(task_queue, i, task);
.

method pulse
    var task, sub;
    
    // called by $sys.heartbeat
    if (caller() != $sys)
        throw(~perm, "Sender is not system");
    while (task_queue && (time() > (((task_queue[1])[2]) + ((task_queue[1])[3])))) {
        task = task_queue[1];
        ._run_task(task);
        .remove_first_task();
    }
    
    // call sub schedulers 
    for sub in (sub_schedulers)
        (| sub.pulse() |);
.

method _run_task
    arg task;
    var code, args, a;
    
    // called by $scheduler only
    if (caller() != this())
        throw(~perm, "Caller is not this");
    catch any {
        // setup the args by hand, becuase we use eval and it expects a string
        args = task[8];
        if (args) {
            for a in [1 .. listlen(args)]
                args = replace(args, a, $data.unparse(args[a]));
            args = $list.to_string(args, ",");
        } else {
            args = "";
        }
        code = ((("." + tostr(task[6])) + "(") + args) + ");";
    
        // run it through eval as the sender():
        (task[5]).eval([code], task[4]);
    } with handler {
        // bounce the errors to the person, or to the system board if it's 'system
        catch any {
            (task[4]).tell(["SCHEDULER ERROR: ", @traceback()]);
        } with handler {
            if ('system in (task[7])) {
                $channels.announce('System, traceback()[1]);
                $channels.announce('System, "task: " + ($data.unparse(task)));
            }
        }
    }
.

method sys_add_task
    arg time, method, sender, caller, flags, [args];
    var task, i, tid;
    
    // use `@info $scheduler' for more information. 
    // [tid, time, time(), sender(), caller(), method, flags, args]
    //
    if (!($sys.is_agent(sender())))
        throw(~perm, "Sender is not an agent or admin, use .add_task()");
    if ((type(time) != 'integer) || ((type(method) != 'symbol) || (type(args) != 'list)))
        throw(~type, "Arguments are not an integer, symbol, and list.");
    if (time < 1)
        throw(~time, "Time is negative.");
    if (time > 31536000)
        throw(~time, "Try to schedule a task LESS than a year from now?");
    if (!valid(sender))
        throw(~type, "The argument for sender is not a valid object");
    if (!valid(caller))
        throw(~type, "The argument for caller is not a valid object");
    if (type(flags) != 'list)
        throw(~type, "Send flags as a list of symbols");
    
    //
    task_index = task_index + 1;
    tid = task_index;
    
    // flags can be set in a system only add_task, for now set them as 'system
    task = [tid, time, time(), sender, caller, method, flags, args];
    task_queue = task_queue + [task];
    
    //
    i = listlen(task_queue);
    while ((i > 1) && ((task[2]) < (((task_queue[i / 2])[2]) + ((task_queue[i / 2])[3])))) {
        task_queue = replace(task_queue, i, task_queue[i / 2]);
        i = i / 2;
    }
    task_queue = replace(task_queue, i, task);
.

method add_sub_scheduler
    arg object;
    
    if (!($sys.is_admin(sender())))
        throw(~perm, "Only admins may add sub schedulers.");
    if (type(object) != 'dbref)
        throw(~type, "Object must be a dbref.");
    sub_schedulers = [@sub_schedulers, object];
.

method del_sub_scheduler
    arg object;
    var pos, s;
    
    if (!($sys.is_admin(sender())))
        throw(~perm, "Only admins may delete sub schedulers.");
    if (type(object) != 'dbref)
        throw(~type, "Object must be a dbref.");
    pos = object in sub_schedulers;
    if (!pos)
        throw(~objnf, "Object not a sub schedulers.");
    s = [];
    if (pos > 1)
        s = [@s, sublist(sub_schedulers, 1, pos - 1)];
    if (s < listlen(sub_schedulers))
        s = [@s, sublist(sub_schedulers, pos + 1)];
    sub_schedulers = s;
.

parent #28
object #5203

var 1 dbref 'robot
var 1 child_index 0
var 1 fertile 0
var 1 manager #5203
var 1 owned [#5203]
var 1 owners [#5203]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 2787 name ['uniq, "Robot"]
var 2787 name_aliases []
var 1179 gender #1182
var 15 verbs #[]
var 17 prose #[['short, "A giant hungry rat. His red eyes glare at you malevontly."]]
var 23 location #247
var 23 obvious 1
var 1 inited 1
var 5203 tell_filters [["* says, \"<this>, list commands\"", 'commands]]
var 28 body_parts #[]
var 19 contents []
var 16 commands []
var 16 shortcuts []

method tell
    arg text;
    var t, p;
    
    for t in (.tell_filters()) {
        p = t[1];
        p = strsub(p, "<this>", .namef());
        if (match_pattern(p, text))
            $scheduler.add_task(1, t[2], text);
    }
.

method add_tell_filter
    arg mask, method;
    
    .perms(sender());
    if ((type(mask) != 'string) || (type(method) != 'symbol))
        throw(~type, "Args must be a string and a symbol.");
    tell_filters = [@tell_filters, [mask, method]];
.

method del_tell_filter
    arg mask;
    var t, tf;
    
    .perms(sender());
    if (type(mask) != 'string)
        throw("Argument must be a string");
    tf = [];
    for t in [1 .. listlen(tell_filters)] {
        if (((tell_filters[t])[1]) == mask) {
            if (t > 1)
                tf = [@tf, @sublist(tell_filters, 1, t - 1)];
            if (t < listlen(tell_filters))
                tf = [@tf, @sublist(tell_filters, t + 1)];
            tell_filters = tf;
            return;
        }
    }
    throw(~tell_nf, "Mask not found.");
.

method tell_filters
    var t;
    
    catch ~methodnf {
        t = pass();
    } with handler {
        t = [];
    }
    return [@tell_filters, @t];
.

method good_morning
    arg text;
    
    text = $string.to_list(text, " ");
    .say("Good morning, " + (text[1]));
.

method say
    arg what;
    
    (.location()).announce((((.namef()) + " says, \"") + what) + "\"");
.

method commands
    arg text;
    var o, who, t;
    
    //"* says, \"<this>, list commands\""
    text = $string.to_list(text, " ");
    who = $object.to_dbref(text[1]);
    o = [(who.namef()) + ", my commands are:"];
    for t in (.tell_filters())
        o = [@o, (("  \"" + (t[1])) + "\" which calls ") + tostr(t[2])];
    .lsay(o);
.

method lsay
    arg what;
    
    what = [((.namef()) + " says, \"") + (what[1]), @sublist(what, 2)];
    (.location()).announce(what);
.

method follow
    arg who;
    
    if (type(who) == 'string)
        who = $object.to_dbref(who);
    if (type(who) != 'dbref)
        throw(~objnf, ("Object (" + who) + ") unknown.");
    following = who;
.

method event
    arg frob;
    
    if (class(frob) != $movement_event)
        return;
    (frob.exit()).go_through();
.

parent #1093
object #1094

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 1 inited 1
var 1 manager #1094
var 1 writable [#1094]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'wrap_filter

method filter
    arg input;
    var len, output, e, line;
    
    len = sender().linelen();
    output = [];
    input = .compress(input);
    for e in (input) {
        e = $string.wrap_line(e, len);
        output = [@output, e[1]];
        for line in (sublist(e, 2))
            output = [@output, " " + line];
    }
    return output;
.

parent #675
object #8788

var 1 dbref 'file
var 1 child_index 1
var 1 fertile 0
var 1 manager #37
var 1 owned []
var 1 owners [#37]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 1 inited 1
var 8788 content_type ""
var 8788 data 0
var 8788 header 0
var 8788 filename "Generic File"

method init_file
    (> .perms(caller(), $root) <);
    data = 0;
    header = 0;
    content_type = "text/plain";
.

method uninit_file
    (> .perms(caller(), $root) <);
    data = 0;
    header = 0;
    content_type = "text/plain";
.

method set_header
    arg new_header;
    var type, valid_types;
    
    (> .perms(sender()) <);
    if (type(new_header) != 'list)
        throw(~type, "Header must be a list of strings.");
    header = new_header;
.

method set_data
    arg new_data;
    var type, valid_types;
    
    (> .perms(sender()) <);
    type = type(new_data);
    valid_types = ['list, 'buffer];
    if (!(type in valid_types))
        throw(~type, "Data must be one of: " + ($data.unparse(valid_types)));
    data = new_data;
.

method data
    if (!('parameters in (.is_readable_by(sender()))))
        throw(~perm, ((sender().namef('xref)) + " does not have permission to see parameters on ") + (.namef('xref)));
    return data;
.

method header
    if (!('parameter in (.is_readable_by(sender()))))
        throw(~perm, ((sender().namef('xref)) + " does not have permission to see parameters on ") + (.namef('xref)));
    return header;
.

method content_type
    if (!('parameter in (.is_readable_by(sender()))))
        throw(~perm, ((sender().namef('xref)) + " does not have permission to see parameters on ") + (.namef('xref)));
    return content_type;
.

method set_content_type
    arg type;
    
    (> .perms(sender()) <);
    if (type(type) != 'string)
        throw(~type, "Content-type must be sent as a string.");
    content_type = type;
.

method filename
    arg [args];
    
    if (!args)
        return filename;
    else if ((args[1]) == 'full)
        return ((filename + " (") + (.dbref())) + ")";
.

method set_filename
    arg fname;
    var x;
    
    (> .perms(sender()) <);
    if (type(fname) != 'string)
        throw(~type, ("Filename for " + (.namef('xref))) + " must be submitted as a string.");
    for x in [1 .. strlen(fname)] {
        if ((fname[x]) in "!@#$%^&*()+-=~`'{}[]|/?\"\\,<>;: ")
            throw(~type, "Filenames cannot contain any of: !@#$%^&*()+-=~`'{}[]|/?\"\\,<>;: ");
    }
    filename = fname;
.

method find_file
    arg path;
    var child, found;
    
    if ((!('parameters in (.is_readable_by(sender())))) && (!(sender() in (.parents()))))
        throw(~perm, ((sender().dbref()) + " does not have permission to see the filesystem from ") + (.filename()));
    if (type(path) != 'list)
        path = explode(path, "/");
    if (!path)
        return 0;
    if ((listlen(path) == 1) && ((path[1]) == (.filename())))
        return;
    for child in (.children()) {
        found = child.find_file(sublist(path, 2));
        if (found)
            return found;
    }
    return 0;
.

method generate_html
    arg [args];
    var out;
    
    out = [];
    if ('parameters in (.is_readable_by(sender()))) {
        out = .data();
        if (out && (type(out) != 'buffer))
            out = ["<hr width=50% align=center>", ("<center><b>Filename: " + (.filename())) + "</b></center><P>", @out];
    }
    return (> pass(@args) <) + (out || []);
.

parent #8788
object #8789

var 1 dbref 'http_file
var 1 child_index 7
var 1 fertile 1
var 1 manager #37
var 1 owned []
var 1 owners [#37]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 8788 data 0
var 8788 header 0
var 8788 content_type "text/plain"
var 1 inited 1
var 8788 filename "generic_http_file"

method retrieve_html
    if (!('parameters in (.is_readable_by(sender()))))
        throw(~perm, ((sender().namef('xref)) + " does not have permission to get html from ") + (.namef('xref)));
    return .data();
.

method set_filename
    arg fname;
    
    if (fname in ["bin", "objects"])
        throw(~invalid, "HTTP Filenames cannot be \"bin\" or \"objects\"");
    (> pass(fname) <);
.

parent #8789
object #9292

var 1 dbref 'http_root_file
var 1 child_index 1
var 1 fertile 0
var 1 manager #37
var 1 owned []
var 1 owners [#37]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 8788 data ["<hr width=50% align=center>", "This is running ColdWeb 0.1, an experimental web server in ColdC.  You can browse objects with the path of <tt>/objects/</tt>, where anything following the slash is an object reference (either with or without the $).  Such as <tt>/objects/$root</tt>.", "<p>", "The Gatways are available in <tt>/bin/</tt>.  Currently we have a <a href=\"/bin/who\">Who Gateway</a>, a <a href=\"/bin/list_method?$http.bin_list_method()\">List Method</a> Gateway, and a <a href=\"/bin/show?$http\">Show Object</a> Gateway.", "<hr width=50% align=center>", "<center>    <a href=\"/history.html\"><b>History</b></a> |", "    <a href=\"/current.html\"><b>Current</b></a>", "</center>"]
var 8788 header 0
var 8788 content_type "text/plain"
var 1 inited 1
var 8788 filename "htroot"

parent #2485
object #2489

var 1 child_index 0
var 1 fertile 0
var 1 manager #2489
var 1 owners [#936]
var 1 writable [#2489]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 1 inited 1
var 1 dbref 'or

method unparse
    arg orlist;
    var str, x;
    
    str = "";
    for x in (orlist) {
        catch any {
            str = (str + (x.unparse())) + " || ";
        } with handler {
            str = (str + tostr(x)) + " || ";
        }
    }
    return ("(" + (str && substr(str, 1, strlen(str) - 4))) + ")";
.

method test
    arg orlist, [args];
    var val, x;
    
    val = 0;
    for x in (orlist) {
        catch ~type, ~methodnf {
            val = x.test(@args);
        } with handler {
            val = x;
        }
        if (val)
            break;
    }
    return val;
.

parent #3
object #5

var 1 owners [#936]
var 1 owned []
var 1 manager #5
var 1 writable [#5]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'false_lock_class

method new
    return <this(), []>;
.

method try
    arg lock, obj;
    
    return 0;
.

parent #2485
object #2490

var 1 child_index 0
var 1 fertile 0
var 1 manager #2490
var 1 owners [#936]
var 1 writable [#2490]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 1 inited 1
var 1 dbref 'xor

method unparse
    arg xorlist;
    var str, x;
    
    str = "";
    for x in (xorlist) {
        catch any {
            str = (str + (x.unparse())) + " ^^ ";
        } with handler {
            str = (str + tostr(x)) + " ^^ ";
        }
    }
    return ("(" + (str && substr(str, 1, strlen(str) - 4))) + ")";
.

method test
    arg xorlist, [args];
    var val, x;
    
    val = 0;
    for x in (xorlist) {
        catch ~type, ~methodnf {
            val = val ? !(x.test(@args)) | (x.test(@args));
        } with handler {
            val = val ? !x | x;
        }
    }
    return val;
.

parent #3775
object #3779

var 1 dbref 'user_db
var 1 child_index 0
var 1 fertile 0
var 1 manager #37
var 1 owned []
var 1 owners [#47]
var 1 writable [#3779]
var 1 readable ['methods, 'code]
var 790 database #[]
var 1 trusted [#30]
var 1 inited 1
var 3779 connected []
var 3775 stripped_characters "!@#$%^&*()_+-=~`'{}[]|/?\"\\,.<>;: "
var 3779 invalid_chars "$#@!^&%~"
var 3775 reserved_names ["user", "builder", "programmer", "admin", "housekeeper", "Reaper", "noone", "guest", "the", "a", "i", "an", "your", "you'r", "me", "god"]
var 3775 invalid_names ["ass", "cunt", "fuck", "shit", "damn"]

method users
    return dict_keys(.database());
.

method connected
    var x;
    
    for x in (connected) {
        if ((!valid(x)) || (| !(x.connections()) |))
            connected = setremove(connected, x);
    }
    return connected;
.

method did_connect
    .perms(caller(), $user);
    connected = [@connected, sender()];
.

method did_disconnect
    .perms(caller(), $user);
    connected = setremove(connected, sender());
.

method valid_name
    arg name;
    
    if (strlen($string.strip(name, invalid_chars)) < strlen(name))
        throw(~invname, ("Names cannot contain any of '" + invalid_chars) + "'.");
    return (> pass(name) <);
.

method match
    arg name;
    
    return (> .find(name) <);
.

parent #1431
parent #2
object #2001

var 1 child_index 0
var 1 fertile 0
var 1 manager #2001
var 1 owners [#47]
var 1 writable [#47]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 1 inited 1
var 1 dbref 'input_parser

method parse
    arg user, str, next_parser, [other_parsers];
    var line, result;
    
    // checks the incoming line to see if its a keeper, or a command.
    line = user.lines();
    if (line == 'one) {
        user.new_line(str);
        user.finish_receiving();
        return 'ok;
    } else {
        result = .parse_line(str);
        switch (result[1]) {
            case 'abort:
                user.reset_input();
                return "** Aborted **  Text thrown away.";
            case 'not_done:
                user.new_line(result[2]);
            case 'done:
                user.finish_receiving();
            case 'pass_command:
                return next_parser.parse(user, result[2], @other_parsers);
        }
        return 'ok;
    }
.

method parse_line
    arg str;
    var cmd;
    
    // do this for blank strings => ""
    if (!str) {
        return ['not_done, str];
    } else if ((str == ".") || (str == "done")) {
        return ['done];
    
        // } else if (str[1] == ">") {
        //   return ['pass_command, substr(str, 2, strlen(str) - 1)];
    } else if ((str == "abort") || (str == "@abort")) {
        return ['abort];
    } else {
        return ['not_done, str];
    }
.

parent #12
object #310

var 1 child_index 0
var 1 owners [#936]
var 1 fertile 1
var 1 inited 1
var 1 owned []
var 310 opt_rec []
var 1 manager #310
var 1 writable [#310]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'arg_opts

method from_str
    arg opt_str, [subs];
    var opts_given, opt_ret, opt, prefix, colon_pos, opt_val, match_opt, opt_type, opt_default, opt_trans_dict, opt_id;
    
    opts_given = explode(opt_str);
    opt_ret = #[];
    for opt in (opts_given) {
        switch (opt[1]) {
            case "!", "-":
                prefix = 'minus;
            case "+":
                prefix = 'plus;
            default:
                prefix = 'none;
        }
        if (prefix != 'none)
            opt = substr(opt, 2);
        colon_pos = ":" in opt;
        opt_val = prefix;
        if (colon_pos) {
            opt_val = substr(opt, colon_pos + 1);
            opt = substr(opt, 1, colon_pos - 1);
        }
        opt_id = 0;
        for match_opt in (opt_rec) {
            if (match_template(match_opt[2], opt)) {
                opt_type = match_opt[3];
                opt_default = match_opt[4];
                opt_trans_dict = match_opt[5];
                opt_id = match_opt[1];
                break;
    
                // out of for loop
            }
        }
        if (!opt_id)
            break;
        opt_val = ._get_opt_val(opt_val, opt_type, opt_default, opt_trans_dict, prefix);
        opt_val = ._val_subs(opt_val, opt_default, subs);
    
        // may throw duplicate key (which is ok)
        catch any {
            opt_ret = dict_add(opt_ret, opt_id, opt_val);
        }
    }
    
    // account for missing options:
    for match_opt in (opt_rec) {
        opt_id = match_opt[1];
        if (!(opt_id in dict_keys(opt_ret))) {
            opt_type = match_opt[3];
            opt_default = match_opt[4];
            if (opt_type == 'check_presence)
                opt_val = ['val, 0];
            else
                opt_val = opt_default;
            opt_val = ._val_subs(opt_val, opt_default, subs);
            opt_ret = dict_add(opt_ret, opt_id, opt_val);
        }
    }
    return opt_ret;
.

method _get_opt_val
    arg opt_val, opt_type, opt_default, opt_trans_dict, prefix;
    
    switch (opt_type) {
        case 'check_presence:
            opt_val = ['val, 1];
        case 'on_off_dict:
            opt_val = opt_trans_dict[prefix];
        case 'obj:
            if (opt_val)
                opt_val = ['val, (| get_name(tosym(substr(opt_val, 2))) |)];
            else
                opt_val = opt_default;
        case 'num:
            if (opt_val)
                opt_val = ['val, toint(opt_val)];
            else
                opt_val = opt_default;
        case 'obj_or_dict:
            if ((opt_val[1]) == "$") {
                // may throw namenf
                opt_val = (| get_name(tosym(substr(opt_val, 2))) |);
                opt_val = opt_val ? ['val, opt_val] | opt_default;
            } else {
                // may throw keynf
                opt_val = (| opt_trans_dict[opt_val] |) || opt_default;
            }
        default:
            opt_val = opt_default;
    }
    return opt_val;
.

method _val_subs
    arg opt_val, opt_default, subs;
    
    switch (opt_val[1]) {
        case 'sub:
            if (type(opt_val[2]) == 'integer) {
                if (((opt_val[2]) <= listlen(subs)) && ((opt_val[2]) > 0))
                    opt_val = subs[opt_val[2]];
                else
                    throw(~range, "Sub index out of range.");
            } else if (((opt_default[1]) != 'sub) || (type(opt_default[2]) == 'integer)) {
                opt_val = ((opt_default[1]) in ['sub, 'val]) ? ._val_subs(opt_default, opt_default, subs) | (opt_default[2]);
            }
        case 'val:
            opt_val = opt_val[2];
        default:
            opt_val = ((opt_default[1]) in ['sub, 'val]) ? ._val_subs(opt_default, opt_default, subs) | (opt_default[2]);
    }
    return opt_val;
.

parent #2679
object #21

var 1 child_index 0
var 1 owners [#936]
var 1 fertile 0
var 16 commands []
var 16 shortcuts []
var 15 verbs #[]
var 19 contents [#25, #28, #30, #31, #32, #33, #134, #185, #936, #24, #7292, #2250, #8598, #7248, #9552]
var 1 inited 1
var 1 owned []
var 1179 gender #1182
var 17 prose #[]
var 1 manager #21
var 1 writable [#21]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'nowhere
var 2787 name ['prop, "Nowhere"]
var 2787 name_aliases []
var 2679 exits []
var 2679 realm <#2717, ['interior]>
var 2679 coordinates #[]

parent #12
object #2451

var 1 child_index 0
var 1 fertile 0
var 1 manager #2451
var 1 owners [#47]
var 1 writable [#47]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 1 inited 1
var 1 dbref 'object

method to_dbref
    arg obj;
    var type, dbref;
    
    type = type(obj);
    switch (type) {
        case 'string:
            dbref = (| get_name(tosym(substr(obj, 2))) |);
            if (!dbref)
                dbref = (> get_name(tosym(lowercase(strsub(obj, " ", "_")))) <);
            return dbref;
        case 'dbref:
            return obj;
        default:
            return (> get_name(obj) <);
    }
.

method get_name
    arg obj, [args];
    var meth;
    
    // get_name(obj, 'method, [args]) (3rd arg must be a list)
    if (!valid(obj))
        return ("** invalid object (" + tostr(obj)) + ") **";
    meth = [@args, 'name][1];
    args = [@args, [], []][2];
    return obj.(meth)(@args);
.

method see_perms
    arg obj;
    var str, x;
    
    str = "[";
    if (obj.fertile())
        str = str + "F";
    for x in (obj.readable())
        str = str + (tostr(x)[1]);
    return str + "]";
.

parent #3
object #8

var 1 owners []
var 1 owned []
var 1 manager #8
var 1 writable [#8]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'or_lock_class

method new
    arg lhs, rhs;
    
    if ((type(lhs) != 'frob) || (type(rhs) != 'frob))
        throw(~perm, "Arguments are not both frobs.");
    return <this(), [lhs, rhs]>;
.

method try
    arg lock, obj;
    
    return ((lock[1]).try(obj)) || ((lock[2]).try(obj));
.

parent #40
object #1184

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 1 inited 1
var 40 cgender_name "Female"
var 40 gender_name "female"
var 40 pronouns #[['pr, "herself"], ['pp, "her"], ['po, "her"], ['ps, "she"], ['pq, "hers"], ['prc, "Herself"], ['ppc, "Her"], ['poc, "Her"], ['psc, "She"], ['pqc, "Hers"]]
var 40 number 'singular
var 1 manager #1184
var 1 writable [#1184]
var 1 readable ['parameters, 'methods, 'code]
var 40 context ["herself", "her", "her", "she", "hers", "Herself", "Her", "Her", "She", "Hers"]
var 1 dbref 'gender_female

parent #7801
object #9440

var 1 dbref 'notice_interface
var 1 child_index 22
var 1 fertile 1
var 1 manager #37
var 1 owned []
var 1 owners [#37]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 16 commands []
var 16 shortcuts []
var 7801 connection 0
var 1 inited 1

method connection_starting
    (> .perms(sender(), .connection()) <);
    .send("The Cold Dark has switched to port 1138, sorry for any inconvienience.");
    (.connection()).close();
.

parent #9440
object #9445

var 1 dbref 'notice_interface_2
var 1 child_index 0
var 1 fertile 0
var 1 manager #7232
var 1 owned []
var 1 owners [#7232]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 16 commands []
var 16 shortcuts []
var 7801 connection #9444
var 1 inited 1

parent #12
object #45

var 1 child_index 0
var 1 owners [#936]
var 1 fertile 0
var 1 inited 1
var 1 owned []
var 1 manager #45
var 1 writable [#45]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'integer

method n_to_nth
    arg number;
    var tens_digit_is_1, ones_digit, single_digit;
    
    if (type(number) != 'integer)
        throw(~type, "Must receive an integer");
    ones_digit = abs(number) % 10;
    tens_digit_is_1 = ((abs(number) / 10) % 10) == 1;
    single_digit = abs(number) < 10;
    if ((ones_digit in [1, 2, 3]) && (!tens_digit_is_1)) {
        switch (ones_digit) {
            case 1:
                return tostr(number) + "st";
            case 2:
                return tostr(number) + "nd";
            case 3:
                return tostr(number) + "rd";
        }
    } else {
        return tostr(number) + "th";
    }
.

method parse_range
    arg range_str;
    var r1, r2;
    
    // ("1-5") => (1, 5)      -- 1, 5
    // ("1-$") => (1, 'end)   -- 1, 'end (end number)
    // (".-3") => ('cur, 3)   -- 'cur (current number), 3
    // ("#-3") => ('bgn, 3)   -- 'bgn (beginning number), 3
    range_str = $parse.reference(range_str, "-");
    r1 = range_str[1];
    r2 = range_str[2];
    
    //
    if (!r2)
        r2 = r1;
    if (!toint(r1)) {
        if (r1 == ".")
            r1 = 'cur;
        else if (r1 == "#")
            r1 = 'bgn;
        else
            throw(~type, "Beginning range invalid.");
    } else {
        r1 = toint(r1);
    }
    
    //
    if (!toint(r2)) {
        if (r2 == "$")
            r2 = 'end;
        else
            throw(~type, "Ending range invalid.");
    } else {
        r2 = toint(r2);
    }
    return [r1, r2];
.

method to_english
    arg num;
    var num_str, sign;
    
    // 12500 => "12,500"
    // if (abs(num) < 9999)
    //  return tostr(num);
    sign = num ? abs(num) / num | 1;
    num = abs(num);
    num_str = "";
    while (num > 999) {
        num_str = ("," + substr(tostr(1000 + (num % 1000)), 2)) + num_str;
        num = num / 1000;
    }
    num_str = tostr(num) + num_str;
    return ((sign == 1) ? "" | "-") + num_str;
.

method range
    arg x, y;
    var list, element;
    
    // creates a list of every number between x and y 
    list = [];
    for element in [x .. y]
        list = list + [element];
    return list;
.

parent #3
object #2495

var 1 child_index 0
var 1 fertile 0
var 1 manager #2495
var 1 owners [#936]
var 1 writable [#2495]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 1 inited 1
var 1 dbref 'inside_lock

method test
    arg objlist, testee, [args];
    var x;
    
    for x in (objlist) {
        if (x.contains(testee))
            return 1;
    }
    return 0;
.

parent #1431
object #1432

var 1 child_index 0
var 1 fertile 0
var 1 manager #1432
var 1 owners [#47]
var 1 writable [#47]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 1 inited 1
var 1 dbref 'conference_parser

method parse
    arg user, str, next_parser, [other_parsers];
    
    if (str && ((str[1]) == ">"))
        str = substr(str, 2);
    else
        str = "say " + str;
    return next_parser.parse(user, str, @other_parsers);
.

parent #40
object #2034

var 1 child_index 0
var 1 fertile 0
var 1 manager #2034
var 1 owners [#2034]
var 1 writable [#2034, #47]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 40 cgender_name ""
var 40 gender_name ""
var 40 pronouns #[['pr, "yourselves"], ['pp, "your"], ['po, "you"], ['ps, "you"], ['pq, "yours"], ['prc, "Yourselves"], ['ppc, "Your"], ['poc, "You"], ['psc, "You"], ['pqc, "Yours"]]
var 1 inited 1
var 40 number 2
var 40 context ["yourselves", "your", "you", "you", "yours", "Yourselves", "Your", "You", "You", "Yours"]
var 1 dbref 'gender_first_person_plural

parent #3775
object #3777

var 1 dbref 'mail_db
var 1 child_index 0
var 1 fertile 0
var 1 manager #37
var 1 owned []
var 1 owners [#47]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 790 database #[]
var 1 trusted []
var 1 inited 1

method valid_recipient
    arg recip;
    
    if (recip.has_ancestor($mail_list))
        return 1;
    return 0;
.

method mail_name
    arg obj;
    
    return "*" + (obj.namef());
.

parent #1170
object #7523

var 1 dbref 'places
var 1 child_index 0
var 1 fertile 0
var 1 manager #37
var 1 owned []
var 1 owners [#37]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 1 inited 1
var 7523 default_place #21
var 7523 exit_starting_place #22
var 1 info ["Utility object for all 'Places' and items relating to places (such as exits)"]
var 7523 starting_place #140
var 7523 default_new_place #2679
var 7523 coordinate_shortcuts #[["n?orth", [0, 0]], ["s?outh", [180, 0]], ["e?ast", [90, 0]], ["w?est", [270, 0]], ["ne|northeast", [45, 0]], ["se|southeast", [135, 0]], ["nw|northwest", [225, 0]], ["sw|southwest", [315, 0]], ["up", [-1, 90]], ["d?own", [-1, -90]]]

method place
    arg which;
    
    which = tosym(tostr(which) + "_place");
    return (> get_var(which) <);
.

method is_place
    arg obj;
    
    return 1;
    if (!(obj.has_ancestor($place)))
        throw(~place, ("Object \"" + (obj.dbref())) + "\" is not a place.");
.

method set_place
    arg which, obj;
    
    .perms(sender(), 'manager);
    (> .is_place(obj) <);
    if (!(which in (.parameters())))
        throw(~place, (toliteral(which) + " is not a valid entry try one of: ") + toliteral(.parameters()));
    set_var(which, obj);
.

method coordinates
    arg str;
    var x;
    
    for x in (coordinate_shortcuts) {
        if (match_template(x[1], str))
            return x[2];
    }
    throw(~coordnf, ("Unable to find coordinate shortcut for \"" + str) + "\".");
.

method coordinate_shortcuts
    return coordinate_shortcuts;
.

method valid_coordinates
    arg radial, azimuth;
    
    if ((radial > 360) || (radial < (-1)))
        throw(~invcoord, "Radial coordinate must be from -1 to 360 degrees.");
    if ((azimuth > 90) || (azimuth < (-90)))
        throw(~invcoord, "Azimuth coordinate must be from 90 to -90 degrees.");
.

method invert_coordinates
    arg radial, azimuth;
    
    radial = radial + 180;
    if (radial > 360)
        radial = radial - 360;
    if (azimuth > 0)
        azimuth = -azimuth;
    else
        azimuth = abs(azimuth);
    return [radial, azimuth];
.

parent #12
object #740

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 1 inited 1
var 1 manager #740
var 1 writable [#740]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'set

method difference
    arg [args];
    var set, list, element;
    
    // Usage:  diff(set 1, set 2, ..., set n)
    // Returns all elements of set 1 that are not in sets 2..n
    if (!args)
        return [];
    set = args[1];
    for list in (delete(args, 1)) {
        for element in (list)
            set = setremove(set, element);
    }
    return set;
.

method contains
    arg [args];
    var super, list, element;
    
    // True if the first list given is a superset of all subsequent lists.
    // False otherwise.  [] is a superset of [] and nothing else; anything is
    // a superset of [].  If only one list is given, return true.
    super = args ? args[1] | [];
    for list in (delete(args, 1)) {
        for element in (list) {
            if (!(element in super))
                return 0;
        }
    }
    return 1;
.

method equal
    arg set1, set2;
    var element;
    
    // True if the two lists given contain the same elements.
    // False otherwise.
    while (set1) {
        element = set1[1];
        if ((!element) in set2)
            return 0;
        while (element in set2)
            set2 = setremove(set2, element);
        while (element in set1)
            set1 = setremove(set1, element);
    }
    return set2 == [];
.

parent #3775
object #3778

var 1 dbref 'place_db
var 1 child_index 0
var 1 fertile 0
var 1 manager #37
var 1 owned []
var 1 owners [#47]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 790 database #[]
var 1 trusted 1
var 1 inited 1

method place_destroyed
    // called in $place.uninit_place (incase the place is in the db)
.

parent #1170
object #888

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 1 inited 1
var 1 manager #888
var 1 writable [#888]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'login_watcher

method notify
    arg who, msg;
    var watch, user, lcont, prefix;
    
    .perms(sender(), 'this);
    prefix = "[login watcher] -> ";
    lcont = (who.location()).contents();
    who = who.namef('titled);
    for user in ($user_db.connected()) {
        if (!(user in lcont)) {
            watch = (| user.watch_logins() |);
            if (watch && ((watch == 1) || ((type(watch) == 'list) && (who in watch))))
                user.tell((((prefix + who) + " has ") + msg) + ".");
        }
    }
.

method did_connect
    .perms($user, caller());
    .notify(sender(), "connected");
.

method did_disconnect
    .perms($user, caller());
    .notify(sender(), "disconnected");
.

parent #664
object #6099

var 1 dbref 'antisocial
var 1 child_index 0
var 1 fertile 0
var 1 manager #7232
var 1 owned []
var 1 owners [#7232]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 16 commands []
var 16 shortcuts []
var 1 inited 1

method basic_antisocial_vrb
.

parent #16
object #1388

var 1 child_index 0
var 1 fertile 0
var 1 manager #7232
var 1 owners [#7232, #1387, #1388]
var 1 writable [#1388, #37]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned [#1388, #4309, #4348, #5205, #7245, #7248, #7261]
var 16 commands []
var 16 shortcuts []
var 1 inited 1
var 1 dbref 'editors

parent #1388
object #1162

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 16 commands [["@abort|abort", 'abort_cmd], ["quit|@quit", 'quit_cmd], ["list|nlist *", 'list_cmd], ["ins?ert *", 'insert_cmd], ["del?ete *", 'del_line_cmd], ["join *", 'join_cmd], ["enter", 'enter_cmd], ["help", 'help_screen]]
var 16 shortcuts [["\"*", 'add_line_cmd, [1]], ["s/*/*", 'sub_cmd, ["", 1, 2]], ["fill * @*", 'fill_cmd, ["", 1, 2]], ["fill *", 'fill_cmd, ["", 1, ""]]]
var 922 command_aliases []
var 1 inited 1
var 1162 pass_through 0
var 1 manager #1162
var 1 writable [#1162]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'generic_editor

method start_editing
    arg what;
    
    // called by user.edit_cmd
    sender().tell([("The selected editor, " + (.namef('id))) + "must define .start_editing()."]);
    return 0;
.

method parse_command
    arg str;
    var cmd, loc, result, i, j, templates, template, word, fields, obj, verb_info, subbed_str;
    
    // This method works like $user.parse_command
    // The difference is that the permissions have changed, and after checking aliases and
    // commands, and nothing was found, resorting to sender().match_command() is an option.
    if (((sender().editor()) != this()) || (caller() != $user_input))
        throw(~perm, "Invalid access to parse_command.");
    
    // remove leading spaces, abort on blank line
    subbed_str = str;
    while (subbed_str && ((subbed_str[1]) == " "))
        subbed_str = substr(subbed_str, 2);
    if (!subbed_str)
        return sender().editing();
    
    // sub the string through command aliases first
    subbed_str = .match_command_aliases(subbed_str);
    
    // Check commands on this.
    cmd = .match_command(subbed_str);
    if (cmd)
        return .(cmd[1])(sender().editing(), @cmd[2]);
    
    // if we're passing unknowns on to user.parse_command()...
    if (pass_through) {
        sender().tell("(Still editing.)");
        sender().run_with_users_perms(sender(), 'parse_command, str);
    } else {
        sender().tell("I don't understand that.");
    }
    return sender().editing();
.

method abort_cmd
    arg editing, com;
    
    .perms(sender(), 'parser);
    if (type(editing) == 'dict) {
        if (editing['changed])
            (editing['user]).tell("Threw away changes and cleared editor variables.");
        else
            (editing['user]).tell("No changes to throw away. Cleared editor variables.");
    } else {
        (| $admin_2.tell(((.namef('id)) + ": editing corrupeted, == ") + ($data.unparse(editing))) |);
    }
    return 0;
.

method quit_cmd
    arg editing, com;
    
    .perms(sender(), 'parser);
    if (editing['changed]) {
        (editing['user]).tell("Changes have been made. Save first, or abort to cancel.");
        return editing;
    } else {
        (editing['user]).tell("Quiting editor.");
        return 0;
    }
.

method adjust
    arg text, [how];
    var line;
    
    for line in [1 .. listlen(text)] {
        if ('spaces in how)
            text = replace(text, line, " " + (text[line]));
        if ('numbers in how)
            text = replace(text, line, (($string.right(tostr(line), 3)) + " :") + (text[line]));
    }
    return text;
.

method list_cmd
    arg editing, com, rest;
    var line, text;
    
    .perms(sender(), 'parser);
    if (com == "list") {
        (editing['user]).tell(editing['text]);
    } else {
        text = $generic_editor.adjust(editing['text], 'numbers);
        for line in [1 .. listlen(text)] {
            if (line == ((editing['cur_line]) - 1))
                (editing['user]).tell((strsub($string.right(tostr(line), 3), " ", "_") + "_:") + ((editing['text])[line]));
            else if (line == (editing['cur_line]))
                (editing['user]).tell((strsub($string.right(tostr(line), 3), " ", "^") + "^:") + ((editing['text])[line]));
            else
                (editing['user]).tell(text[line]);
        }
    }
    return editing;
.

method insert_cmd
    arg editing, com, [args];
    var line, text;
    
    // re-position and (eventually/optionally) add text
    .perms(sender(), 'parser);
    line = [@args, ""][1];
    text = [@args, "", ""][2];
    if (!line) {
        (editing['user]).tell(["Syntax: ins*ert line [text]", "!   You must supply a line number."]);
        return editing;
    }
    if (line != "$")
        line = toint(line);
    else
        line = listlen(editing['text]) + 1;
    if (!line) {
        (editing['user]).tell(["Syntax: ins*ert line [text]", "!   You must supply a line number greater than or equal to 1."]);
        return editing;
    }
    if (line > (listlen(editing['text]) + 1))
        line = listlen(editing['text]) + 1;
    editing = $dict.replace(editing, 'cur_line, line);
    ._show_line(editing);
    return editing;
.

method _show_line
    arg editing;
    var line;
    
    line = (editing['cur_line]) - 1;
    if (line)
        (editing['user]).tell((strsub($string.right(tostr(line), 3), " ", "_") + "_:") + ((editing['text])[line]));
    else
        (editing['user]).tell("____");
    line = line + 1;
    if (line <= listlen(editing['text]))
        (editing['user]).tell((strsub($string.right(tostr(line), 3), " ", "^") + "^:") + ((editing['text])[line]));
    else
        (editing['user]).tell("^^^^");
    return editing;
.

method insert_line
    arg editing, line;
    
    // insert line at editing['cur_line]
    // assumes editing['cur_line] is within 1 .. listlen(editing['text])
    .perms(sender(), 'this);
    editing = $dict.replace(editing, 'text, insert(editing['text], editing['cur_line], line));
    editing = $dict.replace(editing, 'cur_line, (editing['cur_line]) + 1);
    editing = $dict.replace(editing, 'changed, 1);
    return editing;
.

method add_line_cmd
    arg editing, line;
    
    // "*
    .perms(sender(), 'parser);
    editing = .insert_line(editing, line);
    
    // ._show_line(editing);
    (editing['user]).tell(("Added line " + tostr((editing['cur_line]) - 1)) + ".");
    return editing;
.

method delete_line
    arg editing;
    
    // delete line at editing['cur_line]
    // assumes editing['cur_line] is within 1 .. listlen(editing['text])
    .perms(sender(), 'this);
    editing = $dict.replace(editing, 'text, delete(editing['text], editing['cur_line]));
    editing = $dict.replace(editing, 'changed, 1);
    editing = $dict.replace(editing, 'cur_line, $list.min(editing['cur_line], listlen(editing['text])));
    return editing;
.

method del_line_cmd
    arg editing, com, line;
    
    // del?ete line_num
    .perms(sender(), 'parser);
    line = toint(line) || (editing['cur_line]);
    if (line <= (editing['cur_line])) {
        editing = $dict.replace(editing, 'cur_line, line);
        (editing['user]).tell(((("Removed line " + tostr(editing['cur_line])) + ": \"") + ((editing['text])[line])) + "\".");
        editing = .delete_line(editing);
    } else {
        (editing['user]).tell("Line number out of range.");
    }
    
    //._show_line(editing);
    return editing;
.

method sub_cmd
    arg editing, com, was, is;
    
    // s/from/to/
    editing = $dict.replace(editing, 'text, replace(editing['text], (editing['cur_line]) - 1, strsub((editing['text])[(editing['cur_line]) - 1], was, is)));
    ._show_line(editing);
    return editing;
.

method fill_cmd
    arg editing, com, range, [col];
    var start, current, stop, new_text, idx;
    
    col = toint([@col, "75"][1]) || 75;
    if ("-" in range) {
        start = toint(range);
        if (!start) {
            (editing['user]).tell("Must supply a valid range, such as 10, 2-3, or 1-$.");
            return editing;
        }
        range = substr(range, strlen(tostr(start)) + 2);
        if ((!range) || (range == "$"))
            stop = listlen(editing['text]);
        else
            stop = toint(range);
    } else {
        if (!range)
            start = editing['cur_line];
        else
            start = toint(range);
        if (!start) {
            (editing['user]).tell("Must supply a valid range, such as 10, 2-3, or 1-$.");
            return editing;
        }
        stop = start;
    }
    
    // actual change:
    new_text = editing['text];
    current = start;
    while (current <= stop) {
        if (strlen(new_text[current]) > col) {
            idx = col;
            while (idx && (((new_text[current])[idx]) != " "))
                idx = idx - 1;
            if (!idx) {
                idx = col + 1;
                while ((idx < strlen(new_text[current])) && (((new_text[current])[idx]) != " "))
                    idx = idx + 1;
                if (idx == strlen(new_text[current]))
                    idx = col;
            }
            new_text = insert(new_text, current + 1, substr(new_text[current], idx + 1));
            new_text = replace(new_text, current, substr(new_text[current], 1, idx));
            stop = stop + 1;
        }
        current = current + 1;
    }
    editing = $dict.replace(editing, 'text, new_text);
    editing = $dict.replace(editing, 'cur_line, stop + 1);
    new_text = $generic_editor.adjust(editing['text], 'numbers);
    for current in [start .. stop - 1]
        (editing['user]).tell(new_text[current]);
    ._show_line(editing);
    return editing;
.

method join_cmd
    arg editing, com, range;
    var start, stop, current, new_text;
    
    new_text = editing['text];
    start = toint(range);
    range = substr(range, strlen(tostr(start)) + 2);
    stop = toint(range);
    if (range == "$")
        stop = listlen(new_text);
    if ((!start) || (!stop)) {
        (editing['user]).tell("Syntax: join <range>");
        (editing['user]).tell("!   You must supply a range of lines to join, such as 3-4 or 1-$");
        return editing;
    }
    stop = $list.min(stop, listlen(new_text));
    
    // actual change:
    while (start < stop) {
        new_text = replace(new_text, start, (new_text[start]) + (new_text[start + 1]));
        new_text = delete(new_text, start + 1);
        stop = stop - 1;
    }
    editing = $dict.replace(editing, 'text, new_text);
    editing = $dict.replace(editing, 'cur_line, stop + 1);
    ._show_line(editing);
    return editing;
.

method enter_cmd
    arg editing, com;
    
    (editing['user]).read('done_entering, editing);
    return editing;
.

method done_entering
    arg text, editing;
    
    if (sender() != (editing['user]))
        throw(~perm, "Invalid access to done_entering.");
    if (listlen(text)) {
        if (listlen(text) > 1)
            (editing['user]).tell(((("Added lines " + tostr(editing['cur_line])) + " .. ") + tostr(((editing['cur_line]) + listlen(text)) - 1)) + ".");
        else
            (editing['user]).tell(("Added line " + tostr(editing['cur_line])) + ".");
        while (text) {
            editing = $dict.replace(editing, 'text, insert(editing['text], text[1], editing['cur_line]));
            editing = $dict.replace(editing, 'cur_line, (editing['cur_line]) + 1);
            text = delete(test, 1);
        }
    }
.

method help_msg
    var msg;
    
    msg = [];
    msg = msg + ["  ins?ert *    set line number"];
    msg = msg + ["  del?ete *    delete line"];
    msg = msg + ["  \"*           insert text"];
    msg = msg + ["  abort        cancel changes and exit editor"];
    msg = msg + ["  quit         exit if no changes made since last save"];
    msg = msg + ["  list|nlist   list text without|with numbers"];
    msg = msg + ["  s/*/*        str sub: replace first with second in current line."];
    msg = msg + ["  fill * [@*]  wrap lines (@ col, def: 75)"];
    msg = msg + ["  join *       concatonates a range of lines"];
    return msg;
.

method help_screen
    arg editing, com;
    
    // l?ook
    .perms(sender(), 'this);
    (editing['user]).tell(.help_msg());
.

parent #1162
object #758

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 16 commands [["compile", 'compile_cmd], ["refresh", 'refresh_cmd]]
var 16 shortcuts []
var 1 inited 1
var 922 command_aliases []
var 1 manager #758
var 1 writable [#758]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'code_editor

method start_editing
    arg what;
    var ref, obj, method, code;
    
    // called by $user_input.edit_cmd
    ref = $parse.reference(what);
    obj = (| sender().match_environment(ref[1]) |);
    if (!obj) {
        sender().tell(what + " does not describe an editable method.");
        return 0;
    }
    method = tosym(ref[2]);
    catch any {
        code = sender().run_with_users_perms(obj, 'list_method, method, 2);
    } with handler {
        if (error() == ~methodnf) {
            code = [];
        } else {
            sender().tell(("You cannot edit " + what) + ".");
            sender().tell("Error: " + ((traceback()[1])[2]));
            return 0;
        }
    }
    sender().tell(("Now editing " + what) + ".");
    code = $generic_editor.adjust(code, 'spaces);
    
    // user doing editing, obj to be programmed, method to be programmed, code, current line
    // number, changes made
    return #[['user, sender()], ['obj, obj], ['method, method], ['text, code], ['cur_line, 1], ['changed, 0]];
.

method compile_cmd
    arg editing, cmd;
    var errors, last_edit;
    
    .perms(sender(), 'parser);
    catch any {
        last_edit = (" // Edited: " + ($time.ldate('mdy, 'dash))) + "/";
        last_edit = (last_edit + ($time.ltime('12hr, '_ampm))) + " ";
        last_edit = (last_edit + "by: ") + ((editing['user]).namef('ref));
        errors = (editing['user]).run_with_users_perms(editing['obj], 'compile, (editing['text]) + [last_edit], editing['method]);
        if (errors) {
            (editing['user]).tell(errors);
        } else {
            (editing['user]).tell("Method compiled.");
    
            // clear modified flag
            editing = $dict.replace(editing, 'changed, 0);
        }
    } with handler {
        (editing['user]).tell("An error occurred attempting to compile.");
        (editing['user]).tell("The error was " + ((traceback()[1])[2]));
    }
    return editing;
.

method refresh_cmd
    arg editing, com;
    var code;
    
    // re-loads method if not changed
    .perms(sender(), 'parser);
    if (editing['changed]) {
        (editing['user]).tell("Changes have been made. Compile first to refresh.");
    } else {
        catch any {
            code = (editing['user]).run_with_users_perms(editing['obj], 'list_method, editing['method], 2);
        } with handler {
            (editing['user]).tell("Unable to list method into buffer, error was " + ((traceback()[1])[2]));
            return editing;
        }
        editing = $dict.replace(editing, 'text, code);
        (editing['user]).tell("Done.");
    }
    return editing;
.

method help_msg
    var msg;
    
    msg = [];
    msg = msg + ["The code editor allows you to modify and re-compile methods."];
    msg = msg + ["It includes these commands it inherits from the generic editor:"];
    msg = msg + pass();
    msg = msg + [""];
    msg = msg + ["And adds the following:"];
    msg = msg + ["  compile      compile and store current text"];
    msg = msg + ["  refresh      re-load compiled method"];
    msg = msg + [""];
    return msg;
.

parent #7794
object #7810

var 1 dbref 'finger_daemon
var 1 child_index 0
var 1 fertile 0
var 1 manager #37
var 1 owned []
var 1 owners [#37]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 7791 buffer `[]
var 7791 ip ""
var 7791 hostname ""
var 7791 port 1179
var 7791 socket 0
var 7791 active 0
var 7794 interface #7811
var 7794 current_receiver #9532
var 7794 connections [#9226, #9532]
var 7794 timeout 0
var 1 inited 1

parent #1170
object #2742

var 1 child_index 0
var 1 fertile 0
var 1 manager #37
var 1 owned []
var 1 owners [#47]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 1 inited 1
var 1 dbref 'world

method daylight
    // should eventually return something like 'day 'night 'dusk 'dawn
    return 'day;
.

parent #2
object #1142

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 1 inited 1
var 1 manager #1142
var 1 writable [#1142]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'wearable_class

method new
    arg name, desc;
    
    if (type(name) != 'string)
        throw(~test, "test reason.");
.

parent #12
object #51

var 1 child_index 0
var 1 owners [#936]
var 1 fertile 0
var 1 inited 1
var 1 owned []
var 1 manager #51
var 1 writable [#51]
var 1 readable ['parameters, 'methods, 'code]
var 51 quotes [["\"Abandon all hope, ye who enter here.\""], ["\"Pull out Wedge, your not doing any more good back there.\"", "     - Luke Skywalker, StarWars"], ["\"God is in the details.\""], ["\"I don't practice what I preach because I'm not the type of person", "I'm preaching to.\"", "     - Bob Dobbs"], ["\"I haven't shaved for six years.  I seem to be cursed with a thin", "beard.\"", "     - Calvin, Age 6 (of Calvin & Hobbes)"], ["\"I may be a Dreamer, but I'm not the only one.\"", "     - John Lennon"], ["\"C code.  C code run.  Run, Code, Run!  Please!?\"", "     - Anonymous C hacker."], ["\"They who dream by day are cognizant of many things which escape", "those who dream only by night.\"", "     - Edgar Allan Poe"], ["\"The good die first, and they whose hearts are dry as a summer dust", "burn to the socket.\"", "     - William Wordsworth"], ["\"Banning guns to prevent murder is like banning word processors to", "prevent libel.\"", "     - Unknown"]]
var 1 dbref 'code

method set_obj_param
    arg obj, param, val;
    var set_code;
    
    // set param on obj to val
    if (!((sender() == $root) || ($sys.is_admin(sender()))))
        throw(~perm, "Sender not admin or $root");
    if (!valid(obj))
        throw(~objnf, ("Object " + ($data.unparse(obj))) + " is not a valid object.");
    if (!(param in (obj.parameters())))
        throw(~parmnf, ((("Parameter " + ($data.unparse(param))) + " is not a parmater on ") + ($data.unparse(obj))) + ".");
    if ('__set_any in ($obj.methods()))
        throw(~methexist, "Method '__set_any already defined on target object.");
    
    // Copy _set_any to obj
    set_code = .list_method('_set_var);
    obj.compile(set_code, '__set_var);
    
    // Set and delete method
    catch any {
        obj.__set_var(param, val);
        obj.del_method('__set_var);
    } with handler {
        obj.del_method('__set_var);
        rethrow(error());
    }
.

method _set_var
    arg param, val;
    
    if (sender() != $code)
        throw(~perm, "Sender not $code");
    return set_var(param, val);
.

method quotes
    return quotes;
.

method add_random_quote
    arg quote, [from];
    
    if (!($sys.is_admin(sender())))
        throw(~perm, "Sender is not an owner");
    if (type(quote) != 'string)
        throw(~type, "Quote must be given as a string.");
    quote = ("\"" + quote) + "\"";
    quote = $string.wrap_line(quote, 70);
    quote = from ? [@quote, "     - " + (from[1])] | quote;
    quotes = quotes + [quote];
.

method generate_listing
    arg who, [args];
    var meths, methval, input, output, element, header, title, cols, x, z, len, line, linea;
    
    // called by one of the who_cmds, does all the grunge work.
    title = [@args, "Connected Users"][1];
    meths = [@args, [['namef, 'titled], ['time_poll], ['realm_name]], [['namef, 'titled], ['time_poll], ['realm_name]]][2];
    header = [@args, ["Name", "Times", "Location"], ["Name", "Times", "Location"], ["Name", "Times", "Location"]][3];
    cols = [@args, [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]][4];
    
    // get values using $list.map
    element = $list.map(who, (meths[1])[1], @sublist(meths[1], 2));
    input = [];
    for x in (element) {
        input = [@input, [x]];
        if (strlen(x) > (cols[1]))
            cols = replace(cols, 1, strlen(x));
    }
    for x in [2 .. listlen(meths)] {
        methval = $list.map(who, (meths[x])[1], @sublist(meths[x], 2));
        for z in [1 .. listlen(methval)] {
            if (strlen(methval[z]) > (cols[x]))
                cols = replace(cols, x, strlen(methval[z]));
            input = replace(input, z, [@input[z], methval[z]]);
        }
    }
    
    // the header.
    len = (| sender().linelen() |) || 79;
    line = "";
    linea = "";
    for x in [1 .. listlen(cols)] {
        line = line + pad(header[x], (cols[x]) + 2);
        linea = linea + pad(pad("", strlen(header[x]), "-"), (cols[x]) + 2);
    }
    output = [((("--- " + title) + " (") + tostr(listlen(input))) + ") ---"];
    output = [@output, $string.trim(pad(line, len))];
    output = [@output, $string.trim(pad(linea, len))];
    
    // tell the rest:
    for x in (input) {
        line = "";
        for z in [1 .. listlen(cols)]
            line = line + pad(x[z], (cols[z]) + 2);
        output = [@output, pad(line, len)];
    }
    return [@output];
.

method random_quote
    var which;
    
    which = random(listlen(quotes));
    if (which)
        return quotes[which];
    return [];
.

method valid_email
    arg email;
    var host, user, ip, tmp;
    
    email = explode(email, "@");
    if (listlen(email) != 2)
        return ['invalid, email, ""];
    
    // if we want we can do something overly extensive with this, but we will not
    user = email[1];
    host = email[2];
    if (toint(host[1])) {
        tmp = hostname(host);
        if (tmp == "-1")
            return ['invip, user, host];
    } else {
        tmp = ip(host);
        if (tmp == "-1")
            return ['invhostname, user, host];
    }
    return ['valid, user, host];
.

method unparse_command
    arg command;
    var x, line;
    
    // command should be passed as a list, and can either be a command
    // or shortcut.  This will return a string.
    if (listlen(command) == 2)
        return toliteral(command[1]);
    line = "";
    for x in (command[3]) {
        if (type(x) == 'string)
            line = (line + (line ? " " | "")) + x;
        else
            line = ((line + (line ? " " | "")) + "%") + tostr(x);
    }
    return ((("\"" + (command[1])) + "\" => \"") + line) + "\"";
.

method parse_name
    arg name;
    
    // used to parse $named names and aliases.
    name = explode(name, ",");
    if (!name)
        throw(~name, "Emtpy name.");
    return [name[1], sublist(name, 2)];
.

method generate_family_listing
    arg obj, [type];
    var line, obj, colx, col, family, x, out;
    
    type = [@type, 'children][1];
    family = obj.(type)();
    if (!family) {
        out = ["** None **"];
    } else {
        col = ((| sender().linelen() |) || 79) / 8;
        colx = col * 3;
        line = pad(" Name", colx + 2) + pad(" Perms", col - 2);
        out = [(line + pad("Size ", -col)) + "Manager"];
        for obj in (family) {
            line = " " + (obj.namef('xref));
            line = pad(line, colx + 2);
            line = line + pad(" " + ($object.see_perms(obj)), col - 2);
            line = line + pad(tostr(obj.size()) + " ", -col);
            line = line + pad($object.get_name(obj.manager(), 'namef, ['xref]), colx);
            out = [@out, line];
        }
    }
    return out;
.

parent #30
object #31

var 1 child_index 0
var 1 owners [#936]
var 1 fertile 0
var 16 commands [["@par?ents *", 'parents_cmd], ["@dest?roy *", 'destroy_cmd], ["@child?ren|@kids *", 'children_cmd], ["@build *", 'build_cmd]]
var 16 shortcuts []
var 15 verbs #[]
var 19 contents []
var 23 location #21
var 30 password "*"
var 30 connected_at 0
var 30 last_command_at 0
var 30 connections []
var 1 inited 1
var 1 owned []
var 922 command_aliases []
var 30 modes #[]
var 682 letters #[]
var 682 letters_index #[]
var 682 senders 1
var 682 readers [#47]
var 682 notify [#47]
var 682 last_letter 0
var 679 subscribed #[[#31, 0]]
var 1179 gender #1182
var 23 obvious 1
var 17 prose #[]
var 30 prompt ""
var 1 manager #31
var 1 writable [#31]
var 1 readable ['parameters, 'methods, 'code]
var 30 parsers [#2000, #2321]
var 30 tell_traceback ['brief, 0]
var 30 context #[]
var 1 quota 75000
var 1 dbref 'builder
var 2787 name ['uniq, "Generic Builder"]
var 2787 name_aliases []
var 4309 user_data #[['real_name, [1, "???"]], ['email, [1, "???"]]]

method dig_cmd
    arg com, exitname, prep, roomname;
    var egoing, ecoming, exits, here, there;
    
    here = .location();
    there = $nowhere;
    if (roomname && ((roomname[1]) == "$")) {
        // later check the $room_db setup
        there = (| $object.to_dbref(roomname) |);
        if (!there)
            $parse.tell_error(("No room found by the name \"" + roomname) + "\".");
    } else {
        there = ($room_utils.default_type()).spawn();
        there.set_name(roomname);
        .tell(("Created new room \"" + (there.namef('ref))) + "\".");
    }
    
    //
    exits = explode(exitname, "|");
    if (listlen(exits) == 0)
        $parse.tell_error("No exits specified!");
    if (listlen(exits) > 1) {
        if (listlen(exits) > 2)
            $parse.tell_error("Invalid format, too many exits specified");
        ecoming = $exit.spawn();
        ecoming.set_name(exits[2]);
        catch any {
            ecoming.attach(there);
            ecoming.link(here);
            .tell(((("Linked " + (here.namef('ref))) + " to ") + (there.namef('ref))) + ".");
        } with handler {
            ecoming.destroy();
            .tell("Could not make exit from there to here: " + ((traceback()[1])[2]));
        }
    }
    egoing = $exit.spawn();
    egoing.set_name(exits[1]);
    catch any {
        egoing.attach(here);
        egoing.link(there);
        .tell(((("Linked " + (there.namef('ref))) + " to ") + (here.namef('ref))) + ".");
    } with handler {
        egoing.destroy();
        .tell("Couldn't make exit from here to there: " + ((traceback()[1])[2]));
        return;
    }
    .tell("Place successfully Created and Linked.");
.

method children_cmd
    arg verb, what;
    var line, kid, colx, col, kids, x;
    
    what = .match_env_nice(what);
    kids = what.children();
    if (!kids) {
        .tell(("Children of " + (what.namef('xref))) + ": ** None **");
    } else {
        col = (.linelen()) / 8;
        colx = col * 3;
        line = (listlen(kids) > 1) ? "Children" | "Child";
        .tell(((line + " of ") + (what.namef('ref))) + ":");
        line = pad(" Name", colx + 2) + pad(" Perms", col - 2);
        .tell((line + pad("Size ", -col)) + "Manager");
        for kid in (kids) {
            line = " " + (kid.namef('xref));
            line = pad(line, colx + 2);
            line = line + pad(" " + ($object.see_perms(kid)), col - 2);
            line = line + pad(tostr(kid.size()) + " ", -col);
            line = line + pad($object.get_name(kid.manager(), 'namef, ['xref]), colx);
            .tell(line);
        }
    }
.

method parents_cmd
    arg verb, what;
    var line, par, colx, col, parents, x;
    
    what = .match_env_nice(what);
    parents = what.parents();
    col = (.linelen()) / 8;
    colx = col * 3;
    line = "Parent" + ((listlen(parents) > 1) ? "s" | "");
    .tell(((line + " of ") + (what.namef('ref))) + ":");
    line = pad(" Name", colx + 2) + pad(" Perms", col - 2);
    .tell((line + pad("Size ", -col)) + "Manager");
    for par in (parents) {
        line = " " + (par.namef('xref));
        line = pad(line, colx + 2);
        line = line + pad(" " + ($object.see_perms(par)), col - 2);
        line = line + pad(tostr(par.size()) + " ", -col);
        line = line + pad($object.get_name(par.manager(), 'namef, ['xref]), colx);
        .tell(line);
    }
.

method destroy_cmd
    arg destroy, what;
    var syntax;
    
    if (sender() != this())
        throw(~perm, "Sender not this.");
    syntax = "@destroy <object>";
    what = .match_env_nice(what, syntax);
    catch any {
        what.destroy();
        .tell("Destroyed.");
    } with handler {
        $parse.tell_error((traceback()[1])[2], syntax);
    }
.

method _build_ask_roomname
    arg name, there;
    var x, exit;
    
    .perms(sender(), 'this);
    name = (| $code.parse_name(@name) |);
    if (!name) {
        .tell("Invalid room name.");
        $builder._build_destroy_stuff(there, []);
    } else {
        there = ['new, ($places.place('default_new)).spawn()];
        (there[2]).set_name(name[1]);
        for x in (name[2])
            (there[2]).add_name_alias(x);
        .tell(("  Created place " + ((there[2]).namef('ref))) + ".");
        .prompt("Exit name: ", '_build_ask_exitname, there, []);
    }
.

method build_cmd
    arg cmd, str;
    var there, exit, x;
    
    .perms(sender(), 'this);
    if (!str) {
        .prompt("Name of new room: ", '_build_ask_roomname, []);
    } else if ("-aliases" in str) {
        .tell("Radial/Azimuth Coordinate shortcuts:");
        .tell(" Shortcut            Radial Azimuth");
        for x in ($places.coordinate_shortcuts())
            .tell(((" " + pad(x[1], 20)) + pad(tostr((x[2])[1]), 7)) + tostr((x[2])[2]));
    } else {
        str = explode(str);
        there = .match_env_nice(str[listlen(str)]);
        catch any {
            $places.is_place(there);
        } with handler {
            return .tell((traceback()[1])[2]);
        }
        .prompt("Exit Name: ", '_build_ask_exitname, ['old, there], []);
    }
.

method _build_destroy_stuff
    arg there, exits;
    var success, x;
    
    .perms(sender(), 'this);
    if (there && ((there[1]) == 'new)) {
        success = (| (there[2]).destroy() |);
        if (success)
            .tell("Destination room sucessfully destroyed.");
        else
            .tell("Unable to destroy destination room: " + ($data.unparse(there[2])));
    }
    for x in [1 .. listlen(exits)] {
        success = (| (exits[x]).destroy() |);
        if (success)
            .tell(("Exit " + tostr(x)) + " sucessfully destroyed.");
        else
            .tell("Unable to destroy exit: " + ($data.unparse(exits[x])));
    }
.

method _build_ask_exitname
    arg name, there, exits;
    var x, y;
    
    name = (| $code.parse_name(@name) |);
    if ((!name) && (!exits)) {
        .tell("Invalid exit name.");
        ._build_destroy_stuff(there, exits);
        return;
    } else if (name) {
        exits = [@exits, $exit.spawn()];
        y = listlen(exits);
        (exits[y]).set_name(name[1]);
        for x in (name[2])
            (exits[y]).set_name_alias(x);
        .tell(("  Created exit " + ((exits[y]).namef('ref))) + ".");
        if (y < 2)
            .prompt("Returning exit name: ", '_build_ask_exitname, there, exits);
        else
            .prompt("Coordinates (radial,azimuth): ", '_build_ask_coordinates, there, exits);
    } else {
        .prompt("Coordinates (radial,azimuth): ", '_build_ask_coordinates, there, exits);
    }
.

method _build_ask_coordinates
    arg coord, there, exits;
    var err, radial, azimuth;
    
    .perms(sender(), 'this);
    err = "Invalid coordinates.  You must use either radial/azimuth coordinates or use coordinate aliases (use @build -aliases to get a listing of aliases).";
    coord = coord[1];
    if (!coord) {
        .tell(err);
        ._build_destroy_stuff(there, exits);
        return;
    } else {
        catch ~coordnf, ~invcoord {
            if ($string.is_numeric(coord)) {
                coord = explode(coord, ",");
                if (listlen(coord) != 2) {
                    .tell(err + "  Seperate actual radial/azimuth coordinates by a comma.");
                    ._build_destroy_stuff(there, exits);
                    return;
                }
                radial = toint(coord[1]);
                azimuth = toint(coord[2]);
            } else {
                coord = $places.coordinates(coord);
                radial = coord[1];
                azimuth = coord[2];
            }
            $places.valid_coordinates(radial, azimuth);
        } with handler {
            .tell((traceback()[1])[2]);
            ._build_destroy_stuff(there, exits);
            return;
        }
        .tell(((("  Using coordinates: Radial: " + tostr(radial)) + " Azimuth: ") + tostr(azimuth)) + ".");
    }
    ._build_done(there, exits, [radial, azimuth]);
.

method _build_done
    arg there, exits, coord;
    var here, x;
    
    .perms(sender(), 'this);
    here = .location();
    catch any {
        (exits[1]).attach(here, there[2], @coord);
    } with handler {
        .tell("Unable to attach exit because: ");
        .tell((traceback()[1])[2]);
        ._build_destroy_stuff(there, exits);
    }
    
    // second exit
    if (listlen(exits) == 2) {
        catch any {
            (exits[2]).attach(there[2], here, @$places.invert_coordinates(@coord));
        } with handler {
            .tell("Unable to attach return exit because: ");
            .tell((traceback()[1])[2]);
            ._build_destroy_stuff([], [exits[2]]);
        }
    }
    .tell("Finished building extension.");
    .tell("Use `@prose` to set long and short prose descriptions.");
.

parent #675
object #10

var 1 child_index 0
var 1 owners [#936]
var 1 fertile 0
var 1 inited 1
var 1 owned []
var 1 manager #10
var 1 writable [#10]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'lock_parser

method parse
    arg s, env;
    var stack, lock, n, m, obj, len;
    
    stack = [];
    while (1) {
        // Look for valid prefixes.
        while (1) {
            while (s && ((s[1]) == " "))
                s = substr(s, 2);
            if (!s)
                throw(~parse, "String ends unexpectedly.");
            if ((s[1]) == "(") {
                stack = stack + ['open];
                s = substr(s, 2);
            } else if ((s[1]) == "!") {
                stack = stack + ['not];
                s = substr(s, 2);
            } else {
                break;
            }
        }
    
        // Look for an object obj_name.
        for n in [1 .. strlen(s)] {
            if ((s[n]) in ")&|") {
                n = n - 1;
                break;
            }
        }
        m = n;
        while (m && ((s[m]) == " "))
            m = m - 1;
        if (!m)
            throw(~parse, "Null object obj_name.");
        obj = (> env.match_environment(substr(s, 1, m)) <);
        lock = $object_lock_class.new(obj);
        stack = stack + [lock];
        s = substr(s, n + 1);
    
        // Loop until no more reduction to be done.
        while (1) {
            // Process negations, ands, ors.
            while (1) {
                len = listlen(stack);
                if (len < 2)
                    break;
                if ((stack[len - 1]) == 'not) {
                    lock = $not_lock_class.new(stack[len]);
                    stack = sublist(stack, 1, len - 2) + [lock];
                } else if ((stack[len - 1]) == 'and) {
                    lock = $and_lock_class.new(stack[len - 2], stack[len]);
                    stack = sublist(stack, 1, len - 3) + [lock];
                } else if ((stack[len - 1]) == 'or) {
                    lock = $or_lock_class.new(stack[len - 2], stack[len]);
                    stack = sublist(stack, 1, len - 3) + [lock];
                } else {
                    break;
                }
            }
    
            // Close parens, if necessary; otherwise stop.
            if ((!s) || ((s[1]) != ")"))
                break;
            while (s && ((s[1]) == ")")) {
                len = listlen(stack);
                if ((len < 2) || ((stack[len - 1]) != 'open))
                    throw(~parse, "Misplaced right parenthesis.");
                stack = sublist(stack, 1, len - 2) + [stack[len]];
                s = substr(s, 2);
                while (s && ((s[1]) == " "))
                    s = substr(s, 2);
            }
        }
    
        // Are we done?
        if (!s) {
            if (listlen(stack) > 1)
                throw(~parse, "Unmatched left parentheses.");
            return stack[1];
        }
    
        // No, we're at a conjunction.
        if ((s[1]) == "&") {
            stack = stack + ['and];
            s = substr(s, 2);
        } else if ((s[1]) == "|") {
            stack = stack + ['or];
            s = substr(s, 2);
        } else {
            throw(~parse, "Illegal character following right parenthesis.");
        }
    }
.

parent #31
object #32

var 1 child_index 33
var 1 owners [#936]
var 1 fertile 0
var 16 commands [["@show *", 'show_cmd], ["@list|@nlist *", 'list_cmd], ["@program *", 'program_cmd], ["@d?isplay *", 'display_cmd], ["@dump *", 'dump_cmd], ["@id *", 'id_cmd], ["@go *", 'go_cmd], ["@mcom?mands *", 'mcommands_cmd], ["@info *", 'info_cmd], ["@descend?ants *", 'descendants_cmd], ["@which *", 'which_cmd], ["@mv|@move|@cp|@copy *", 'copy_move_cmd], ["@del-m?ethod|@delm?ethod|@dm *", 'del_method_cmd], ["@add-m?ethod|@addm?ethod|@am *", 'add_method_cmd], ["@teval *", 'tick_eval_cmd], ["@eval *", 'eval_cmd], ["@ancestor?s|@ascend *", 'ancestors_cmd], ["@add-c?ommand|@ac *", 'add_command_cmd], ["@del-c?ommand|@dc *", 'del_command_cmd], ["@as * eval *", 'eval_as_cmd], ["@def?iner * this|as * eval *", 'eval_as_to_cmd]]
var 16 shortcuts [[";*", 'eval_cmd, ["eval", 1]]]
var 15 verbs #[]
var 19 contents []
var 23 location #21
var 30 password "*"
var 30 connected_at 0
var 30 last_command_at 0
var 30 connections []
var 1 inited 1
var 1 owned []
var 32 eval_prefix 0
var 922 command_aliases []
var 30 modes #[]
var 682 letters #[]
var 682 letters_index #[]
var 682 senders 1
var 682 readers [#47]
var 682 notify [#47]
var 682 last_letter 0
var 679 subscribed #[[#32, 0]]
var 1179 gender #1182
var 23 obvious 1
var 17 prose #[]
var 30 prompt ""
var 1 manager #32
var 1 writable [#32]
var 1 readable ['parameters, 'methods, 'code]
var 30 parsers [#2000, #2321]
var 30 tell_traceback ['brief, 0]
var 30 context #[]
var 1 quota 75000
var 1 dbref 'programmer
var 2787 name ['uniq, "Generic Programmer"]
var 2787 name_aliases []
var 4309 user_data #[['real_name, [1, "???"]], ['email, [1, "???"]]]
var 9398 setting_templates #[["@list-options", 'string]]
var 32 eval_tick_offset 0

method init_programmer
    .perms(caller(), $root);
    .set_tell_traceback('verbose, 4);
.

method uninit_programmer
    .perms(caller(), $root);
.

method eval_cmd
    arg com, str;
    var result, vars, pkeys, v, evalp, adjust, ticks, time;
    
    .perms(sender(), 'this);
    evalp = .eval_prefix();
    pkeys = dict_keys(evalp);
    adjust = !str;
    vars = ("var " + ($list.to_string(pkeys, ", "))) + "; ";
    for v in (pkeys)
        vars = (vars + (evalp[v])) + "; ";
    
    // perform escape substitution
    str = .eval_subs(str);
    
    // Evaluate the line.
    if (str && ((str[1]) == ";"))
        str = substr(str, 2);
    else
        str = ((vars + " return ") + str) + ";";
    time = time();
    ticks = tick();
    result = .eval([str]);
    ticks = (tick() - ticks) - eval_tick_offset;
    time = time() - time;
    if (adjust && ((result[1]) != 'errors)) {
        eval_tick_offset = eval_tick_offset + ticks;
        .tell(("Eval tick offset adjusted by " + tostr(ticks)) + " ticks.");
        return;
    }
    
    // Display the errors, or the result.
    if ((result[1]) == 'errors) {
        .tell(result[2]);
    } else {
        .tell("=> " + ($data.unparse(result[2], 'full)));
        .tell(((("[ ticks: " + tostr(ticks)) + " seconds: ") + tostr(time)) + " ]");
    }
.

method program_cmd
    arg com, [args];
    var syntax, obj, ref, add_hist, why, x;
    
    .perms(sender(), 'this);
    syntax = "Syntax: `@program <obj>.<method>`";
    args = explode(args[1]);
    if (!args)
        $parse.tell_error("You must give an object and method to program", syntax);
    ref = $parse.reference(args[1]);
    obj = .match_env_nice(ref[1], syntax);
    ref = (ref[2]) || ($parse.tell_error("No method name given.", syntax));
    why = "";
    add_hist = 1;
    for x in [2 .. listlen(args)] {
        if (match_begin("-edited", args[x])) {
            if (!($sys.is_admin(this())))
                .tell("!  Only administrators can compile without history comments.");
            else
                add_hist = 0;
        } else {
            why = (why + " ") + (args[x]);
        }
    }
    args = ['compile, obj, tosym(ref), add_hist, why];
    if (!(obj.is_writable_by(this()))) {
        .tell("!  You cannot program that object; ignoring code.");
        args = replace(args, 1, 'ignore);
    }
    .read('programming_done, @args);
    .tell(((("-- Enter text for " + (obj.dbref())) + ".") + ref) + " --");
.

method show_cmd
    arg com, name;
    var obj;
    
    .perms(sender(), 'this);
    if (!name)
        $parse.tell_error("Must specify an object to show.", com + " <object>");
    obj = .match_env_nice(name);
    if (!(| .tell(obj.show()) |))
        .tell("Permission denied.");
.

method _move_method
    arg syn, ref1, ref2, [opts];
    var line, code;
    
    .perms(sender(), 'this);
    catch any {
        ref1 = $parse.reference(ref1);
        ref2 = $parse.reference(ref2);
        if ((!(ref1[2])) || (!(ref2[2])))
            $parse.tell_error("You must define both a method to be copied from, and one to be copied to.", syn);
        ref1 = replace(ref1, 1, .match_env_nice(ref1[1]));
        ref1 = replace(ref1, 2, tosym(ref1[2]));
        ref2 = replace(ref2, 1, .match_env_nice(ref2[1]));
        ref2 = replace(ref2, 2, tosym(ref2[2]));
        code = (ref1[1]).list_method(ref1[2]);
    
        // Parse Options
        if (opts && ("-edited" in ($list.to_string(opts[1])))) {
            if (!($sys.is_system(sender())))
                .tell("!  Sorry, only admins can turn off the edited messages.");
        } else {
            line = (" // " + ($time.ldate('mdy, 'dash))) + "/";
            line = ((line + ($time.ltime('24hr))) + " ") + (.namef('ref));
            line = (((line + ", moved from ") + ((ref1[1]).dbref())) + ".") + tostr(ref1[2]);
            code = [@code, line];
        }
    
        // delete the old method, compile the new one.
        (ref1[1]).del_method(ref1[2]);
        (ref2[1]).compile(code, ref2[2]);
    
        // cool, we made it.
        line = ((("Method " + ((ref1[1]).dbref())) + ".") + tostr(ref1[2])) + " moved to ";
        line = (((line + ((ref2[1]).dbref())) + ".") + tostr(ref2[2])) + ".";
        .tell(line);
    } with handler {
        switch (error()) {
            case ~methodnf:
                line = (traceback()[1])[2];
                line = substr(line, 1, strlen(line) - 1);
                $parse.tell_error(((line + " on ") + ((ref1[1]).namef('ref))) + ".", syn);
            case ~perm:
                $parse.tell_error("You cannot write on that object.", syn);
            case ~stop:
                rethrow(error());
            default:
                // they are men, they can deal with the tracebacks
                $parse.tell_error([(traceback()[1])[2], traceback()[2], traceback()[3]], syn);
        }
    }
.

method del_method_cmd
    arg com, what;
    var syntax, obj, ref, res;
    
    .perms(sender(), 'this);
    syntax = ("Syntax: `" + com) + " <obj>.<method>`";
    what = explode(what);
    if (!what)
        $parse.tell_error("You must give an object and a method to delete", syntax);
    ref = $parse.reference(what[1]);
    obj = .match_env_nice(ref[1], syntax);
    ref = (ref[2]) || ($parse.tell_error("No method name given.", syntax));
    res = (| obj.del_method(tosym(ref)) |);
    if (type(res) == 'error) {
        switch (res) {
            case ~methodnf:
                .tell("!  No such method");
            default:
                .tell("!  You do not have the perms to modify that object");
        }
    } else {
        .tell("Method removed.");
    }
.

method move_cmd
    arg com, [args];
    var syn;
    
    .perms(sender(), 'this);
    syn = ("`" + com) + " [from] <$obj.ref> [to] <$obj.ref>`";
    
    // figure up args
    args = explode(@args);
    if (args && ((args[1]) == "from"))
        args = delete(args, 1);
    if ((listlen(args) > 1) && ((args[2]) == "to"))
        args = delete(args, 2);
    if (listlen(args) < 2)
        $parse.tell_error("Not enough arguments sent.", syn);
    
    // what type is it (method/parameter)
    if (("." in (args[1])) && ("." in (args[2])))
        return ._move_method(syn, @args);
    else if (("," in (args[1])) && ("," in (args[2])))
        return ._move_parameter(syn, @args);
    else
        $parse.tell_error("You must define both methods, or both parameters.", syn);
.

method list_cmd
    arg com, str;
    var code, nums, line, ref, syntax, ancestor, opt;
    
    .perms(sender(), 'this);
    nums = com == "@nlist";
    syntax = com + " <object>.<method>";
    
    // figure out the object/reference
    catch any {
        ref = $parse.full_reference(str);
        if ((ref[1]) != 'method)
            $parse.tell_error("You must submit an object.method() reference", syntax);
        ancestor = (ref[2]).find_method(ref[3]);
        code = ancestor.list_method(ref[3]);
        if (nums) {
            code = $list.numbered_text(code);
        } else {
            for line in [1 .. listlen(code)]
                code = replace(code, line, "  " + (code[line]));
        }
    } with handler {
        switch (error()) {
            case ~methodnf:
                line = ((((ref[2]).dbref()) + ".") + tostr(ref[3])) + "()";
                $parse.tell_error(line + " not found.", syntax);
            default:
                $parse.tell_error((traceback()[1])[2], syntax);
        }
        $parse.tell_error((traceback()[1])[2], syntax);
    }
    opt = (.setting("@list-options")) || "";
    line = ((((ancestor.dbref()) + ".") + tostr(ref[3])) + " ") + opt;
    if (nums)
        .tell("--- Method " + line);
    else
        .tell("@program " + line);
    .tell(code);
    .tell(".");
.

method copy_move_cmd
    arg com, [args];
    var syn, how, line;
    
    .perms(sender(), 'this);
    syn = ("`" + com) + " [from] <$obj.ref> [to] <$obj.ref>`";
    
    // figure up args
    args = explode(@args);
    args = [@args, ""];
    args = setremove(args, "from");
    args = setremove(args, "to");
    if (listlen(args) != 3)
        $parse.tell_error("Send two object references.", syn);
    how = (com in ["@mv", "@move"]) ? 'move | 'copy;
    catch ~namenf {
        args = [$parse.full_reference(args[1], sender()), args[2], args[3]];
        args = [args[1], $parse.full_reference(args[2], sender()), args[3]];
        if ((((args[1])[1]) != ((args[2])[1])) && (((args[2])[1]) != 'unknown))
            $parse.tell_error(((((("Cannot " + tostr(how)) + ((((args[1])[1]) == 'unknown) ? " an object" | ("from a " + tostr((args[1])[1])))) + " to ") + "a ") + tostr((args[2])[1])) + ".", syn);
        else if (((args[1])[1]) == 'method)
            ._copy_move_method(syn, how, @args);
        else if (((args[1])[1]) == 'parameter)
            .tell("Parameters are currently unsupported, sorry!");
        else
            $parse.tell("You must specify a full reference for the source object.", syn);
    } with handler {
        $parse.tell_error((traceback()[1])[2], syn);
    }
.

method display_cmd
    arg com, disp_ref;
    var to_show;
    
    // display method/parameter info for an object
    // to_show is a list as follows:
    // [$object, 'param | 'meth | 'none, "pattern", [opts]]
    .perms(sender(), 'this);
    to_show = ._parse_disp_ref(disp_ref);
    if (to_show) {
        if ((to_show[4])['header])
            ._disp_obj_header(to_show[1], to_show[4]);
        ._disp_obj_detail(@to_show);
        .tell($string.center(" + Finis + ", .linelen(), "-"));
    }
.

method id_cmd
    arg verb, obj;
    
    .perms(sender(), 'this);
    obj = .match_env_nice(obj);
    .tell((((((((obj.namef('xref)) + " ") + ($object.see_perms(obj))) + " ") + ($data.unparse(obj.parents()))) + " ") + tostr(obj.size())) + " bytes");
.

method dump_cmd
    arg com, args;
    var opts, obj, dbref, x, pdbref, par, data, readable, me, code, syn, tail;
    
    .perms(sender(), 'this);
    syn = [["Options can be:", "    +/-n     -- nice formatting", "    +/-t     -- textdump formatting", "    +/-m     -- show/don't show methods", "    +/-p     -- show/don't show parameters", "Flags default to \"-n +m +p\""], com + " [options] <object>"];
    opts = #[["n", [0, 0]], ["t", [1, 0]], ["m", [1, 0]], ["p", [1, 0]], ["e", [0, 0]]];
    args = $parse.options(args, opts);
    if (!(args[1]))
        $parse.tell_error(@syn);
    obj = .match_env_nice((args[1])[1]);
    me = this();
    dbref = obj.dbref();
    opts = args[2];
    readable = obj.is_readable_by(me);
    data = (| obj.data() |);
    if ((opts["p"])[1]) {
        if (!data) {
            .tell(" *** Parameters are unreadable by you ***");
        } else {
            if ((opts["n"])[1]) {
                .tell("Object: " + (obj.namef('ref)));
                .tell("Parents: " + ($list.to_english($list.map(obj.parents(), 'namef))));
                .tell(("Size: " + tostr(obj.size())) + " bytes");
            } else {
                // I'm not sure how the latest drivers handle dbrefs vs objnums
                for x in (obj.parents())
                    .tell("parent " + (x.dbref()));
                .tell("object " + dbref);
                .tell("");
            }
            for par in (data) {
                if (type(par[2]) == 'string) {
                    .tell((" *** " + ((par[1]).dbref())) + "'s parameters are unreadable by you ***");
                } else {
                    pdbref = (| (par[1]).dbref() |) || toliteral(par[1]);
                    for x in (par[2])
                        .tell((((("var " + pdbref) + " ") + tostr(x[1])) + " ") + ($data.unparse(x[2])));
                }
            }
        }
    }
    if ((opts["m"])[1]) {
        .tell("");
        if (!('code in readable)) {
            .tell((" *** " + dbref) + "'s methods are unreadable by you ***");
        } else {
            if ((opts["e"])[1])
                tail = " -edited";
            else
                tail = "";
            for x in (obj.methods()) {
                code = obj.list_method(x);
                if ((opts["n"])[1])
                    .tell(((("@program " + dbref) + ".") + tostr(x)) + tail);
                else
                    .tell("method " + tostr(x));
                for x in [1 .. listlen(code)]
                    code = replace(code, x, "    " + (code[x]));
                .tell(code);
                .tell([".", ""]);
    
                // this can get long
                pause();
            }
        }
    }
.

method add_method_cmd
    arg com, what;
    var syntax, obj, ref, res;
    
    .perms(sender(), 'this);
    syntax = "Syntax: `@add-method <obj>.<method>`";
    what = explode(what);
    if (!what)
        $parse.tell_error("You must give an object and a method to add", syntax);
    ref = $parse.reference(what[1]);
    obj = .match_env_nice(ref[1], syntax);
    ref = (ref[2]) || ($parse.tell_error("No method name given.", syntax));
    res = (| obj.compile([""], tosym(ref)) |);
    if (res != [])
        .tell("!  You do not have the perms to modify that object");
    else
        .tell("Method added.");
.

method descendants_cmd
    arg verb, what;
    var thing;
    
    thing = .match_env_nice(what);
    if (!thing)
        return;
    .tell(("Descendants of " + (thing.namef('ref))) + ":");
    .tell(thing._display_descendants());
    .tell("---");
.

method ancestors_cmd
    arg verb, what;
    var thing;
    
    thing = .match_env_nice(what);
    if (!thing)
        return;
    .tell(("Ancestors of " + (thing.namef('ref))) + ":");
    .tell(thing._display_ancestors());
    .tell("---");
.

method _parse_disp_ref
    arg disp_ref;
    var sep_pos, sep, obj, obj_name, to_show, opts, ref, pattern, which_det;
    
    opts = explode(disp_ref);
    if (!opts)
        return [];
    ref = opts[1];
    opts = $list.to_string(sublist(opts, 2));
    sep_pos = (":" in ref) || (("." in ref) || ((";" in ref) || ("," in ref)));
    if (sep_pos) {
        obj_name = substr(ref, 1, sep_pos - 1) || (.namef('ref));
        sep = substr(ref, sep_pos, 1);
        pattern = substr(ref, sep_pos + 1) || "*";
        obj = .match_env_nice(obj_name);
        if (sep in [";", ":"]) {
            opts = ($string.trim(opts)) + " anc:";
            if ((opts[1]) == "$") {
                opts = opts + (explode(opts)[1]);
                opts = substr(opts, strlen(explode(opts)[1]) + 1);
            } else {
                opts = opts + ",";
            }
        }
        if ((pattern[1]) == "_")
            opts = "pri" + opts;
        which_det = #[[":", 'meth], [".", 'meth], [";", 'param], [",", 'param]][sep];
        opts = $display_opts.from_str(opts, obj, $list.last(obj.ancestors()));
        return [obj, which_det, pattern, opts];
    } else {
        obj = .match_env_nice(ref);
        opts = $display_opts.from_str(opts, obj, $list.last(obj.ancestors()));
        return [obj, 'none, "", opts];
    }
.

method _disp_obj_detail
    arg obj, which_det, pattern, opts;
    var details, info, detail, len, show_private, param;
    
    .perms(sender(), 'this);
    len = .linelen();
    if (which_det == 'meth) {
        info = obj.method_info(opts['max_parent], $misc, '_display_filter, [pattern], (opts['show_private]) ? [] | ["_*"]);
        details = [["Methods:", ""], ["Lines $parent.method(args)", "First comment or return value"]];
        for detail in (info)
            details = [@details, [(((((((((detail[4]) ? "+" | " ") + ($string.right(tostr(detail[5]), 4))) + " ") + (((detail[1]) != obj) ? (detail[1]).id() | "")) + ".") + tostr(detail[2])) + "(") + (detail[3])) + ")", detail[6]]];
        for detail in (details)
            .tell(pad((pad(detail[1], len / 2) + " ") + (detail[2]), len));
    } else if (which_det == 'param) {
        info = obj.parameter_info(opts['max_parent]);
        details = ["Parameter(s)"];
        for detail in (info) {
            param = tostr(detail[2]);
            if (match_pattern(pattern, param) != 0) {
                detail = (((("  " + (((detail[1]) != obj) ? (detail[1]).namef('id) | "")) + ",") + param) + ": ") + ($data.unparse(detail[3]));
                if ((opts['chop_props]) && (strlen(detail) > (len - 1)))
                    detail = $string.chop(detail, len);
                details = [@details, detail];
            }
        }
        .tell(details);
    }
.

method mcommands_cmd
    arg cmd, what;
    var obj, coms, c, len, line, emote, opts;
    
    // returns all commands in a nice format.
    // god this is getting ugly.
    .perms(sender(), 'this);
    
    // options
    opts = explode(what);
    what = opts[1];
    opts = sublist(opts, 2);
    if (opts && match_begin("-emote", "-e"))
        emote = 1;
    
    //
    if (what == "")
        what = .ancestors();
    else
        what = [.match_env_nice(what)];
    for obj in (what) {
        if ((obj.has_ancestor($has_commands)) || (obj.has_ancestor($has_verbs))) {
            .tell(("Commands on " + (obj.namef('ref))) + ":");
            coms = [];
            coms = coms + ((| obj.shortcuts() |) || []);
            coms = coms + ((| obj.commands() |) || []);
            len = ((.linelen()) - 5) / 2;
            if (!emote) {
                for c in (coms) {
                    line = ("  " + ($string.left(("\"" + (c[1])) + "\"", len))) + "  ";
                    .tell(line + ($data.unparse(c[2])));
                }
            } else {
                for c in (coms) {
                    // they aren't always a _cmd but fk.
                    .tell((((";" + (.dbref())) + ".del_command(") + ($data.unparse(c[2]))) + ")");
                    line = (((";" + (.dbref())) + ".add_command(\"") + (c[1])) + "\", ";
                    .tell((line + ($data.unparse(c[2]))) + ")");
                }
            }
            if ((| obj.verbs() |)) {
                for c in ($dict.to_list(obj.verbs())) {
                    line = ("  " + ($string.left(("\"" + (c[1])) + "\"", len))) + " ";
                    line = line + ((((c[2])[2]) == 'remote) ? "rmt " | "    ");
                    line = line + ($data.unparse((c[2])[1]));
                    .tell(line);
                }
            }
            if (obj == $has_commands)
                break;
        } else {
            .tell(("Object " + (obj.namef('ref))) + " has no commands.");
        }
    }
.

method _disp_obj_header
    arg obj, opts;
    var line, lines, objs, line_len, extra_str;
    
    // Display header info for obj
    .perms(sender(), 'this);
    line_len = .linelen();
    
    // Object:
    line = "Object: " + (obj.namef('ref));
    if (obj.fertile())
        line = line + " (Fertile)";
    .tell(line);
    
    // Owners:
    if (opts['header]) {
        objs = obj.owners();
        line = $list.to_english($list.map(objs, 'namef, 'ref));
        .tell(("Owner" + ((listlen(objs) > 1) ? "s: " | ": ")) + line);
        .tell(("Size: " + ($integer.to_english(obj.size()))) + " bytes");
    
        // Parents: [parents]
        objs = obj.parents();
        if (objs) {
            line = $list.to_english($list.map(objs, 'namef, 'ref));
            if (!(opts['chop_head_data]))
                line = $string.chop(line, line_len - 9);
            .tell(("Parent" + ((listlen(objs) > 1) ? "s: " | ": ")) + line);
        }
        objs = obj.children();
        if (objs) {
            line = $list.to_english($list.map(objs, 'namef, 'ref));
            if (!(opts['chop_head_data]))
                line = $string.chop(line, line_len - 10);
            .tell(((listlen(objs) > 1) ? "Children: " | "Child: ") + line);
        }
        if (obj.has_ancestor($located))
            .tell("Location: " + ((obj.location()).namef('ref)));
    }
.

method go_cmd
    arg com, where;
    var loc, r;
    
    if (sender() != this())
        throw(~perm, "Sender not this");
    loc = (| .match_environment(where) |);
    if (!loc) {
        catch any {
            loc = $room_db.match_room(where);
        } with handler {
            switch (error()) {
                case ~ambig:
                    // check aliases for the hell of it
                    for r in ((traceback()[1])[3]) {
                        if (r.name_match(where)) {
                            loc = r;
                            break;
                        }
                    }
                    if (!loc)
                        $parse.tell_error("Several rooms match that name: " + ($list.to_english($list.map((traceback()[1])[3], 'namef))));
                default:
                    $parse.tell_error((traceback()[1])[2]);
            }
        }
    }
    (.location()).announce((.namef()) + " @go'd elsewhere", this());
    .move_to(loc);
    (.location()).announce((.namef()) + " @go'd here", this());
    .tell("You @go'd");
.

method info_cmd
    arg com, obj;
    var info;
    
    .perms(sender(), 'this);
    obj = .match_env_nice(obj);
    info = obj.info();
    if (!info)
        return .tell("No information about " + (obj.namef('ref)));
    .tell("-----");
    .tell(info);
    .tell("-----");
.

method eval_subs
    arg code;
    var idx, ret_code, sub;
    
    ret_code = "";
    while (code) {
        idx = "^" in code;
        if (!idx) {
            return ret_code + code;
        } else if ((idx == strlen(code)) || (substr(code, idx + 1, 1) == "^")) {
            ret_code = ret_code + substr(code, 1, idx);
            code = substr(code, idx + 1);
            if (code && ((code[1]) == "^"))
                code = substr(code, 2);
        } else {
            if (idx > 1) {
                ret_code = ret_code + substr(code, 1, idx - 1);
                code = substr(code, idx + 1);
            } else {
                code = substr(code, 2);
            }
            idx = 1;
            while ((idx <= strlen(code)) && (!((code[idx]) in " =.()[]=<>?|&!*+-/';\"")))
                idx = idx + 1;
            sub = .match_env_nice(substr(code, 1, idx - 1));
            ret_code = ret_code + (sub.dbref());
            code = substr(code, idx);
        }
    }
    return ret_code;
.

method eval_prefix
    .perms(sender(), 'this);
    return $dict.union(#[["me", "me = this();"], ["here", "here = me.location()"]], eval_prefix || #[]);
.

method del_command_cmd
    arg cmd, str;
    var syn, cmdref, ref;
    
    .perms(sender(), 'this);
    syn = ("`" + cmd) + " <command reference> [from] <object>`";
    if (!str)
        $parse.tell_error("No arguments specified.", syn);
    if ((str[1]) == "\"") {
        str = substr(str, 2);
        cmdref = substr(str, 1, ("\"" in str) - 1);
        str = explode(substr(str, ("\"" in str) + 1));
    } else if ((str[1]) == "'") {
        str = explode(str);
        cmdref = tosym(substr(str[1], 2));
    }
    if (!cmdref)
        $parse.tell_error("Command references can either be templates or symbols.", syn);
    if (!str)
        $parse.tell_error("Invalid object reference.", syn);
    ref = .match_env_nice(str[listlen(str)]);
    catch any {
        ref.del_command(cmdref);
    } with handler {
        switch (error()) {
            case ~perm:
                $parse.tell_error(strsub((traceback()[1])[2], "%O", ((traceback()[1])[3]).namef('xref)), syn);
            default:
                $parse.tell_error((traceback()[1])[2], syn);
        }
    }
    .tell(((("Command " + ((type(cmdref) == 'symbol) ? "for method " | "with template ")) + toliteral(cmdref)) + " deleted from ") + (ref.namef('xref)));
.

method programming_done
    arg code, status, obj, meth, hist, why;
    var last_edit, errors;
    
    .perms(caller(), $input);
    if (status == 'ignore)
        return .tell("Finished ignoring input.");
    if (hist) {
        last_edit = (" // " + ($time.ldate('mdy, 'dash))) + "/";
        last_edit = (last_edit + ($time.ltime('24hr))) + " ";
        last_edit = last_edit + (.namef('ref));
        if (why)
            last_edit = (last_edit + ":") + why;
        code = code + [last_edit];
    }
    catch any {
        errors = obj.compile(code, meth);
        if (errors)
            .tell(errors);
        else
            .tell("Method compiled.");
    } with handler {
        switch (error()) {
            case ~perm:
                $parse.tell_error("!  You cannot program that object.");
            default:
                $parse.tell_error("!  " + ((traceback()[1])[2]));
        }
    }
.

method tick_eval_cmd
    arg com, str;
    
    .eval_cmd(com, (";var ticks,x,y,z; ticks = ticks_left(); " + str) + " ; return ticks-ticks_left()-4;");
.

method which_cmd
    arg which, cmdstr;
    var cmd, cmds, parent, pcmds, matches, smatches, template, syn, len, line;
    
    // searches all commands for str and returns obj.method for said command
    .perms(sender(), 'this);
    syn = ("`" + which) + " <template>`";
    if (!cmdstr)
        $parse.tell_error("No template given.", syn);
    matches = [];
    smatches = [];
    template = explode(cmdstr)[1];
    for parent in (.ancestors()) {
        pcmds = (| parent.commands() |);
        if (pcmds) {
            for cmd in (pcmds) {
                if (cmdstr in ($string.strip(cmd[1], "?")))
                    matches = [@matches, [cmd[1], parent, cmd[2]]];
    
                //            else if (match_begin(cmd[1], template))
                //                 matches = [@matches, [cmd[1], parent, cmd[2]]];
            }
        }
    
        // do shortcuts seperately so we can note the difference
        pcmds = (| parent.shortcuts() |);
        if (pcmds) {
            for cmd in (pcmds) {
                if (cmdstr in ($string.strip(cmd[1], "?")))
                    smatches = [@smatches, [cmd[1], parent, cmd[2], cmd[3]]];
    
                //            else if (match_begin(cmd[1], template))
                //                smatches = [@smatches, [cmd[1], parent, cmd[2], cmd[3]]];
            }
        }
        if (parent == $has_commands)
            break;
    }
    if ((!matches) && (!smatches)) {
        .tell(("No commands found matching the template \"" + cmdstr) + "\".");
        return;
    }
    len = (.linelen()) / 2;
    .tell(("Commands matching the template \"" + cmdstr) + "\":");
    for cmd in (matches) {
        line = ("  " + pad($code.unparse_command(delete(cmd, 2)), len)) + "  ";
        .tell((((line + ((cmd[2]).dbref())) + ".") + tostr(cmd[3])) + "()");
    }
    for cmd in (smatches) {
        line = ("  " + pad($code.unparse_command(delete(cmd, 2)), len)) + "  ";
        .tell((((line + ((cmd[2]).dbref())) + ".") + tostr(cmd[3])) + "()");
    }
.

method _copy_move_method
    arg syn, how, ref1, ref2, opts;
    var line, code, type;
    
    .perms(sender(), 'this);
    catch any {
        code = (ref1[2]).list_method(ref1[3]);
        if (opts && ("-edited" in opts)) {
            if (!($sys.is_system(sender())))
                .tell("!  Only admins can turn off the edited messages.");
        } else {
            line = (" // " + ($time.ldate('mdy, 'dash))) + "/";
            line = ((line + ($time.ltime('24hr))) + " ") + (.namef('ref));
            line = (((line + ", moved from ") + ((ref1[2]).dbref())) + ".") + tostr(ref1[3]);
            code = [@code, line];
        }
        if (how == 'move)
            (ref1[2]).del_method(ref1[3]);
        (ref2[2]).compile(code, ref2[3]);
        line = ($string.capitalize(tostr(ref1[1]))) + " ";
        line = (((line + ((ref1[2]).dbref())) + ".") + tostr(ref1[3])) + " ";
        line = (line + ((how == 'move) ? "moved" | "copied")) + " ";
        line = (((line + ((ref2[2]).dbref())) + ".") + tostr(ref2[3])) + ".";
        .tell(line);
    } with handler {
        switch (error()) {
            case ~methodnf:
                line = (traceback()[1])[2];
                line = substr(line, 1, strlen(line) - 1);
                $parse.tell_error(((line + " on ") + ((ref1[1]).namef('ref))) + ".", syn);
            case ~perm:
                $parse.tell_error("You cannot write on that object.", syn);
            case ~stop:
                rethrow(error());
            default:
                // they are men, they can deal with the tracebacks
                .tell("Error encountered:");
                .tell_traceback(traceback());
        }
    }
.

method add_command_cmd
    arg cmd, str;
    var syn, sref, ref, template;
    
    .perms(sender(), 'this);
    syn = ("`" + cmd) + " <template> [for] <object.method>`";
    if (!str)
        $parse.tell_error("No arguments specified.", syn);
    if ((str[1]) != "\"")
        $parse.tell_error("No template given (must be enclosed in quotes).", syn);
    str = substr(str, 2);
    sref = explode(substr(str, ("\"" in str) + 1));
    template = substr(str, 1, ("\"" in str) - 1);
    sref = sref[listlen(sref)];
    ref = (| $parse.full_reference(sref, this()) |);
    if (!ref)
        $parse.tell_error(("\"" + sref) + "\" is an invalid object.method() reference.", syn);
    if (!(ref[3]))
        $parse.tell_error(("No method specified on " + ((ref[2]).dbref())) + ".", syn);
    if (!template)
        $parse.tell_error("No template specified.", syn);
    catch any {
        (ref[2]).add_command(template, ref[3]);
    } with handler {
        .tell_traceback(traceback());
        switch (error()) {
            case ~perm:
                $parse.tell_error(strsub((traceback()[1])[2], "%O", ((traceback()[1])[3]).namef('xref)), syn);
            default:
                $parse.tell_error((traceback()[1])[2], syn);
        }
    }
    .tell(((((("Command " + template) + " added for the method ") + toliteral(ref[3])) + " on ") + ((ref[2]).namef('xref))) + ".");
.

method eval_as_cmd
    arg cmd, objname, prep, line;
    var obj, result;
    
    (> .perms(sender(), 'this) <);
    line = line + ";";
    obj = .match_env_nice(objname);
    result = obj.eval([line]);
    if ((result[1]) == 'errors)
        .tell(result[2]);
    else
        .tell((("eval as " + (obj.dbref())) + " => ") + ($data.unparse(result[2])));
.

method eval_as_to_cmd
    arg cmd, objname, this, targetname, eval, line;
    var obj, target, result;
    
    (> .perms(sender(), 'this) <);
    line = line + ";";
    obj = .match_env_nice(objname);
    target = .match_env_nice(targetname);
    result = obj.eval([line], target);
    if ((result[1]) == 'errors)
        .tell(result[2]);
    else
        .tell((((((((cmd + " ") + objname) + " ") + this) + " ") + targetname) + " eval => ") + ($data.unparse(result[2])));
.

parent #1387
object #26

var 26 source #22
var 26 dest #22
var 26 lock <#4, []>
var 1 child_index 119
var 1 owners [#936]
var 1 fertile 1
var 15 verbs #[["@lock %this with *", ['lock_vrb, 'remote]]]
var 1 inited 1
var 1 owned []
var 1179 gender #1182
var 17 prose #[]
var 1 manager #26
var 1 writable [#26]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'exit
var 2787 name ['uniq, "Generic Exit"]
var 2787 name_aliases []

method init_exit
    .perms($root, caller());
    source = $places.place('default);
    dest = source;
    source.add_exit(0, 0);
    lock = $true_lock_class.new();
.

method uninit_exit
    .perms(caller(), $root);
    (| source.del_exit() |);
    (| source.did_detach() |);
    (| dest.did_detach() |);
    source = 0;
    dest = 0;
    lock = 0;
.

method environment
    return [this()] + setremove(source.environment(), this());
.

method invoke
    var actor, here;
    
    if (!valid(.dest()))
        $parse.tell_error((((.name()) + " has an invalid destination, notify the manager (") + ((.manager()).namef('ref))) + ").", "", actor);
    if (lock.try(sender()))
        sender().move_to(.dest());
    else
        sender().tell((.name()) + " is locked.");
    
    // Send an event
    (.source()).announce_event($movement_event.new('departure, sender()));
    (.dest()).announce_event($movement_event.new('arrival, sender()));
.

method lock_vrb
    arg cmd, this, prep, str;
    
    .perms(sender());
    catch ~objnf, ~parse {
        lock = $lock.parse(str, sender());
        sender().tell("Locked.");
    } with handler {
        switch (error()) {
            case ~objnf:
                sender().tell("Object not found in lock string.");
            case ~parse:
                sender().tell("Invalid lock string.");
        }
    }
.

method attach
    disallow_overrides;
    arg source_place, dest_place, radial, azimuth;
    
    // radial/azimuth coordinates.
    .perms(sender());
    (> $places.is_place(source_place) <);
    (> $places.is_place(dest_place) <);
    if (source_place == source)
        return;
    (> source_place.will_attach('source, sender()) <);
    (> dest_place.will_attach('dest, sender()) <);
    (| source.del_exit() |);
    source = source_place;
    dest = dest_place;
    source_place.add_exit(radial, azimuth);
    (| source_place.did_attach('source, sender()) |);
    (| dest_place.did_attach('dest, sender()) |);
.

method dest
    return dest;
.

method source
    return source;
.

method place_destroyed
    arg place;
    
    .perms(caller(), $place);
    .destroy();
.

parent #12
object #49

var 1 child_index 0
var 1 owners [#936]
var 1 fertile 0
var 1 inited 1
var 49 secs_per_year 31536000
var 49 mins_per_hour 60
var 49 secs_per_week 604800
var 49 secs_per_day 86400
var 49 created_on 758611955
var 49 hours_per_day 24
var 49 days_per_year 365
var 49 year_begin 0
var 49 secs_per_min 60
var 49 days [""]
var 49 months #[["Jan", "January"], ["Feb", "February"], ["Mar", "March"], ["Apr", "April"], ["May", "May"], ["Jun", "June"], ["Jul", "July"], ["Aug", "August"], ["Sep", "September"], ["Oct", "October"], ["Nov", "November"], ["Dec", "December"]]
var 49 standard 0
var 49 secs_per_hour 3600
var 1 owned []
var 1 manager #49
var 1 writable [#49]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'time_root

method init_time
    .perms(caller(), $root);
    secs_per_min = 60;
    secs_per_hour = 3600;
    secs_per_day = 86400;
    secs_per_week = 604800;
    secs_per_year = 31536000;
    created_on = 0;
    mins_per_hour = 60;
    hours_per_day = 24;
    days_per_year = 365;
    year_begin = 0;
    days = [""];
    months = [""];
    standard = 0;
.

method time
    return .convert();
.

method ctime
    arg [time];
    
    time = [@time, .time()][1];
    if (!standard)
        return "still working on this";
    else
        return ctime(time);
.

method hr_min_sec
    arg [time];
    
    // returns a list: ["hh", "mm", "ss"]
    return [tostr(.hour()), tostr(.minute()), tostr(.second())];
.

method hour
    arg [time];
    
    // either send a pre-converted time, or nothing.
    time = time ? time[1] | (standard ? time() | (.convert()));
    return ((time % secs_per_year) % secs_per_day) / secs_per_hour;
.

method convert
    arg [time];
    
    // converts time into whatever time based off created_on
    return ([@time, time()][1]) - created_on;
.

method minute
    arg [time];
    
    // either send a pre-converted time, or nothing.
    time = time ? time[1] | (standard ? time() | (.convert()));
    return (((time % secs_per_year) % secs_per_day) % secs_per_hour) / secs_per_min;
.

method second
    arg [time];
    
    // either send a pre-converted time, or nothing.
    time = time ? time[1] | (standard ? time() | (.convert()));
    return (((time % secs_per_year) % secs_per_day) % secs_per_hour) % secs_per_min;
.

method year
    arg [time];
    
    // either send a pre-converted time, or nothing.
    // returns years since 'created_on;
    // prolly not right.
    time = time ? time[1] | (standard ? time() | (.convert()));
    return (time / secs_per_year) + year_begin;
.

method day
    arg [time];
    
    // either send a pre-converted time, or nothing.
    // returns days since 'created_on;
    // prolly not right.
    time = time ? time[1] | (standard ? time() | (.convert()));
    return time / secs_per_day;
.

method minute_str
    arg [args];
    
    // will call $integer.int_to_name
    return 'null;
.

method hour_str
    arg [args];
    
    // will call $integer.int_to_name
    return 'null;
.

method second_str
    arg [args];
    
    // will call $integer.int_to_name
    return 'null;
.

method day_str
    arg [time];
    
    time = [@time, .time()][1];
    return tostr(.day());
.

method months
    return months;
.

method days
    return days;
.

method secs_per_min
    return secs_per_min;
.

method secs_per_hour
    return secs_per_hour;
.

method secs_per_day
    return secs_per_day;
.

method secs_per_week
    return secs_per_week;
.

method secs_per_year
    return secs_per_year;
.

parent #49
object #334

var 1 child_index 0
var 1 owners [#936]
var 1 fertile 0
var 1 inited 1
var 49 created_on 695533749
var 49 hours_per_day 21
var 49 days_per_year 345
var 49 year_begin 425
var 49 secs_per_min 60
var 49 secs_per_hour 4320
var 49 secs_per_day 90720
var 49 secs_per_week 453600
var 49 secs_per_year 41731200
var 49 mins_per_hour 72
var 49 standard 0
var 1 owned []
var 1 manager #334
var 1 writable [#334]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'dark_time

method paradise_time
    arg [args];
    var time, hour, mde;
    
    // args: terran time() == output of server builtin.
    //       'seconds      == with seconds
    //       'no_mde       == with morning/day/evening hour pre-pension
    if (args && (type(args[1]) == 'integer)) {
        time = .convert(args[1]);
        args = delete(args, 1);
    } else {
        time = .time();
    }
    hour = .hour(time);
    mde = (hour > 7) ? (hour > 14) ? "eh " | "dh " | "mh ";
    if (args && ('no_mde in args))
        mde = "";
    hour = hour % 7;
    hour = (hour == 0) ? 7 | hour;
    if (args && ('seconds in args))
        return ((((mde + tostr(hour)) + ":") + pad(tostr(.minute(time)), 2, "0")) + ":") + pad(tostr(.second(time)), 2, "0");
    else
        return ((mde + tostr(hour)) + ":") + pad(tostr(.minute(time)), 2, "0");
.

method ilraitheen_time
    arg [args];
    var time;
    
    // args: terran time() == output of server builtin.
    //       'seconds      == with seconds
    if (args && (type(args[1]) == 'integer)) {
        time = .convert(args[1]);
        args = delete(args, 1);
    } else {
        time = .time();
    }
    if (args && (type(args[1]) == 'symbol))
        return (((tostr(.hour(time)) + ":") + pad(tostr(.minute(time)), 2, "0")) + ":") + pad(tostr(.second(time)), 2, "0");
    else
        return (tostr(.hour(time)) + ":") + pad(tostr(.minute(time)), 2, "0");
.

parent #310
object #720

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 1 inited 1
var 310 opt_rec [['max_parent, "anc", 'obj_or_dict, ['sub, 1], #[["^", ['sub, 1]], [",", ['sub, 2]]]], ['show_private, "pri?vate", 'on_off_dict, ['val, 0], #[['plus, ['val, 1]], ['minus, ['val, 0]], ['none, ['val, 1]]]], ['header, "head?er", 'on_off_dict, ['val, 1], #[['plus, ['val, 1]], ['minus, ['val, 0]], ['none, ['val, 1]]]], ['chop_head_data, "hchop", 'on_off_dict, ['val, 0], #[['plus, ['val, 1]], ['minus, ['val, 0]], ['none, ['val, 1]]]], ['chop_props, "pchop", 'on_off_dict, ['val, 1]], ['chop_props, "pchop", 'on_off_dict, ['val, 1], #[['plus, ['val, 1]], ['minus, ['val, 0]], ['none, ['val, 1]]]]]
var 1 manager #720
var 1 writable [#720]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'display_opts

method set_opts
    // opt rec format:
    // ['id,"template",type,default,#[translation_dictionary]]
    // opt types:
    // 'check_presence, 'on_off_dict, 'obj, 'num, 'obj_or_dict
    // sub2 = $list.last(obj.ancestors())
    opt_rec = [];
    opt_rec = opt_rec + [['max_parent, "anc", 'obj_or_dict, ['sub, 1], #[["^", ['sub, 1]], [",", ['sub, 2]]]]];
    opt_rec = opt_rec + [['chop_head_data, "chop", 'on_off_dict, ['val, 0], #[['plus, 1], ['minus, 0], ['none, 1]]]];
    opt_rec = opt_rec + [['show_private, "pri?vate", 'on_off_dict, ['val, 0], #[['plus, 1], ['minus, 0], ['none, 1]]]];
    opt_rec = opt_rec + [['header, "head?er", 'on_off_dict, ['val, 1], #[['plus, 1], ['minus, 0], ['none, 1]]]];
.

parent #1204
object #2717

var 1 child_index 0
var 1 fertile 0
var 1 manager #2717
var 1 owned []
var 1 owners [#47]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 1 inited 1
var 1 dbref 'realm_of_creation
var 2787 name ['prop, "<Creation>"]
var 1204 local #[]

parent #7794
object #7799

var 1 dbref 'login_daemon
var 1 child_index 0
var 1 fertile 0
var 1 manager #37
var 1 owned []
var 1 owners [#37]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 7791 buffer `[]
var 7791 ip ""
var 7791 hostname ""
var 7791 port 0
var 7791 socket 0
var 7791 active 0
var 7794 interface #7800
var 7794 current_receiver 0
var 7794 connections []
var 1 inited 1
var 7794 default_port 1138

parent #40
object #2032

var 1 child_index 0
var 1 fertile 0
var 1 manager #2032
var 1 owners [#2032]
var 1 writable [#2032, #47]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 40 cgender_name ""
var 40 gender_name ""
var 40 pronouns #[['pr, "yourself"], ['pp, "your"], ['po, "you"], ['ps, "you"], ['pq, "yours"], ['prc, "Yourself"], ['ppc, "Your"], ['poc, "You"], ['psc, "You"], ['pqc, "Yours"]]
var 1 inited 1
var 40 number 1
var 40 context ["yourself", "your", "you", "you", "yours", "Yourself", "Your", "You", "You", "Yours"]
var 1 dbref 'gender_first_person

parent #2485
object #2487

var 1 child_index 0
var 1 fertile 0
var 1 manager #2487
var 1 owners [#936]
var 1 writable [#2487]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 1 inited 1
var 1 dbref 'false

method unparse
    arg dummy;
    
    return "0";
.

method test
    arg [args];
    
    return 0;
.

parent #1170
object #465

var 1 child_index 0
var 1 owners [#936]
var 1 fertile 0
var 1 inited 1
var 465 channels ['all, 'chatter, 'Darkurthe, 'System, 'Admins, 'Logins]
var 1 blessed [#86]
var 465 tuners #[['all, 0], ['chatter, 1], ['Darkurthe, 1], ['System, 1], ['Admins, 1], ['Logins, 1]]
var 465 senders #[['all, 'admins], ['chatter, 1], ['Darkurthe, 1], ['System, 'admins], ['Admins, 1], ['Logins, 1]]
var 465 owners #[[#47, 5]]
var 465 channel_owner #[['all, #47], ['chatter, #37], ['Darkurthe, #37], ['System, #47], ['Admins, #37], ['Logins, #47]]
var 465 listeners #[['all, 'connected], ['chatter, [#37, #2084, #2277, #4312, #5427, #5507, #7474]], ['Darkurthe, [#37, #2005, #2389, #4312]], ['System, [#2008, #2116, #2084, #2277, #2537, #2652, #4312, #4562, #5507, #7275, #7474, #7756, #37]], ['Admins, [#2008, #2116, #2005, #2277, #37, #4312, #2015]], ['Logins, [#37, #2116, #2277, #2015]]]
var 465 max_channels_owned 3
var 1 owned []
var 1 manager #465
var 1 writable [#465]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted [#246]
var 1 dbref 'channels

method __admins
    return $sys.system();
.

method del_channel
    arg channel;
    var c;
    
    if ((sender() != (channel_owner[channel])) && (!(.is_writable_by(sender()))))
        throw(~perm, "Sender is not the owner of the channel");
    ._del_channel(channel);
    c = owners[sender()];
    if (c == 1)
        owners = dict_del(owners, sender());
    else
        owners = dict_add(owners, sender(), c - 1);
.

method validate_channel
    arg channel, [rest];
    var x, chars;
    
    // receives a string, returns a symbol if valid
    chars = $string.strip($string.non_alphanumeric(), "-_");
    for x in [1 .. strlen(chars)] {
        if ((chars[x]) in channel)
            throw(~type, "Channel name can only contain alphanumeric characters");
    }
    if (!channel)
        throw(~type, "Channel cannot be blank");
    if (!rest) {
        channel = .match_channel(channel);
        if (!channel)
            throw(~channenf, "Channel does not exist");
        if (listlen(channel) > 1)
            throw(~ambig, "Channel matches all of: " + ($data.unparse(channel)));
        channel = channel[1];
    } else {
        channel = tosym(channel);
    }
    return channel;
.

method all_owners
    if (!(.is_writable_by(sender())))
        throw(~perm, "Sender not an owner");
    return owners;
.

method all_listeners
    if (!(.is_writable_by(sender())))
        throw(~perm, "Sender not an owner");
    return listeners;
.

method all_senders
    if (!(.is_writable_by(sender())))
        throw(~perm, "Sender not an owner");
    return senders;
.

method listeners
    arg channel;
    var ret;
    
    // if (!.is_writable_by(sender()))
    //   throw(~perm, "Sender not an owner");
    if (type(listeners[channel]) == 'symbol)
        ret = .(tosym("__" + tostr(listeners[channel])))();
    else
        ret = listeners[channel];
    if (!((sender() == this()) || (sender() in ret)))
        return [];
    else
        return ret;
.

method senders
    arg channel;
    
    if (sender() != this())
        throw(~perm, "Sender not an owner");
    if (type(senders[channel]) == 'symbol)
        return .(tosym("__" + tostr(senders[channel])))();
    return senders[channel];
.

method match_channel
    arg channel_name;
    var channel_matches, channel;
    
    channel_matches = [];
    channel = tosym(channel_name) in channels;
    if (channel)
        return [channels[channel]];
    for channel in (channels) {
        if (match_begin(tostr(channel), channel_name))
            channel_matches = [@channel_matches, channel];
    }
    return channel_matches;
.

method allow_send_to
    arg channel, who, [caller];
    var senders;
    
    senders = .senders(channel);
    if (senders == 0)
        throw(~locked, "Channel is locked");
    if (senders == 1)
        return 1;
    if (type(senders) == 'list) {
        if (who in senders)
            return 1;
    }
    if (who == (channel_owner[channel]))
        return 1;
    if ((channel == 'System) && caller)
        return (caller[1]) in senders;
    return 0;
.

method allow_tune_in
    arg channel, who;
    
    if ((.senders(channel)) == 0)
        throw(~locked, "Channel is locked");
    if ((tuners[channel]) == 1)
        return 1;
    if (type(tuners[channel]) == 'list) {
        if (who in (tuners[channel]))
            return 1;
    }
    if (who == (channel_owner[channel]))
        return 1;
    return 0;
.

method channels
    return channels;
.

method set_channel
    arg channel_str, [args];
    var channel, allowed, senders, listeners;
    
    // args: channel_str, allowed, senders, listeners
    // channel setup:  #[['namef, [[allowed], [senders], owner, [listeners]]]];
    channel = .validate_channel(channel_str);
    
    // basic checks
    if (!(channel in channels))
        throw(~perm, "That channel doesn't exist");
    if ((sender() != (channel_owner[channel])) && (!(.is_writable_by(sender()))))
        throw(~perm, "You are not the owner of the channel");
    
    // get the settings
    allowed = [@args, 1][1];
    senders = [@args, 1, 1][2];
    listeners = [@args, [sender()], [sender()], [sender()]][3];
    if ((type(senders) == 'symbol) || (type(listeners) == 'symbol))
        throw(~type, "Cannot use symbols");
    
    // send it off
    ._set_channel(channel, allowed, senders, sender(), listeners);
.

method _del_user_from_channel
    arg channel, who;
    var data;
    
    if (sender() != this())
        throw(~perm, "Sender is not this");
    listeners = dict_add(listeners, channel, setremove(listeners[channel], who));
.

method _add_user_to_channel
    arg channel, who;
    var data;
    
    if (sender() != this())
        throw(~perm, "Sender is not this");
    listeners = dict_add(listeners, channel, (listeners[channel]) + [who]);
.

method tune_out
    arg channel;
    
    if (!(sender() in (listeners[channel])))
        throw(~putz, "You are not tuned into that channel.");
    ._del_user_from_channel(channel, sender());
.

method tune_in
    arg channel;
    
    if (!(channel in channels))
        throw(~chnlnf, "Channel is not available, create it first");
    if (!(.allow_tune_in(channel, sender())))
        throw(~perm, "That is a restricted channel.");
    if (sender() in (listeners[channel]))
        throw(~putz, "You are already tuned into that channel");
    ._add_user_to_channel(channel, sender());
.

method __connected
    return $user_db.connected();
.

method _del_channel
    arg channel;
    
    if (sender() != this())
        throw(~perm, "Sender is not this");
    tuners = dict_del(tuners, channel);
    channels = setremove(channels, channel);
    senders = dict_del(senders, channel);
    channel_owner = dict_del(channel_owner, channel);
    listeners = dict_del(listeners, channel);
.

method new_channel
    arg channel, allowed, senders, owner, listeners;
    var c;
    
    if (!(.is_writable_by(caller())))
        throw(~perm, "Sender not an owner");
    
    // send channel as a string
    channel = .validate_channel(channel, 'no_search);
    if (channel in channels)
        throw(~perm, "That channel already exists");
    if (((| owners[sender()] |) == max_channels_owned) && (!(.is_writable_by(sender()))))
        throw(~perm, ("You can only have " + tostr(max_channels_owned)) + " channels at a time.");
    ._set_channel(channel, allowed, senders, owner, listeners);
    
    // increment ownership
    c = (owner in dict_keys(owners)) ? (owners[owner]) + 1 | c;
    owners = dict_add(owners, owner, c);
.

method init_channels
    if (sender() != $root)
        throw(~perm, "Sender is not $root.");
    tuners = #[['sys, 1], ['all, 0], ['wiz, 1]];
    channels = ['sys, 'all, 'wiz];
    senders = #[['sys, 'admins], ['all, 'admins], ['wiz, 1]];
    owners = #[[$core, 3]];
    channel_owner = #[['sys, $core], ['all, $core], ['wiz, $core]];
    listeners = #[['sys, []], ['all, 'connected], ['wiz, []]];
    max_channels_owned = 3;
.

method valid_channel
    arg channel;
    
    channel = .validate_channel(channel);
    if (!(channel in channels))
        throw(~chnlnf, "Channel doesn't exist");
    return 1;
.

method all_tuners
    return tuners;
.

method _set_channel
    arg name, tune, send, owner, who;
    
    if (sender() != this())
        throw(~perm, "Sender is not this");
    channels = [@channels, name];
    tuners = dict_add(tuners, name, tune);
    senders = dict_add(senders, name, send);
    channel_owner = dict_add(channel_owner, name, owner);
    listeners = dict_add(listeners, name, who);
.

method announce
    arg channel, text;
    var status, who, person, id, x;
    
    if (type(channel) == 'string)
        channel = .validate_channel(channel);
    if (!(channel in channels))
        throw(~chnlnf, "Channel doesn't exist");
    if (!(.allow_send_to(channel, sender(), caller())))
        throw(~perm, "Sender is not allowed to send to that channel.");
    for person in (.listeners(channel)) {
        id = (("<" + tostr(channel)) + " - ") + (sender().namef());
        id = (id + ((sender() in (.listeners(channel))) ? "" | ((!(sender().has_ancestor($user))) ? "" | " (tuned out)"))) + "> ";
        (| person.tell(id + text) |);
    }
.

parent #49
object #333

var 1 child_index 0
var 1 owners [#936]
var 1 fertile 0
var 1 inited 1
var 49 secs_per_min 60
var 49 secs_per_hour 3600
var 49 secs_per_day 86400
var 49 secs_per_week 604800
var 49 secs_per_year 31536000
var 49 created_on 0
var 49 mins_per_hour 60
var 49 hours_per_day 24
var 49 days_per_year 365
var 49 year_begin 0
var 49 days ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
var 49 months #[["Jan", ["January", 1, 31]], ["Feb", ["February", 2, 28]], ["Mar", ["March", 3, 31]], ["Apr", ["April", 4, 30]], ["May", ["May", 5, 31]], ["Jun", ["June", 6, 30]], ["Jul", ["July", 7, 31]], ["Aug", ["August", 8, 31]], ["Sep", ["September", 9, 30]], ["Oct", ["October", 10, 31]], ["Nov", ["November", 11, 30]], ["Dec", ["December", 12, 31]]]
var 49 standard 1
var 1 owned []
var 1 manager #333
var 1 writable [#333]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'time

method elapsed
    arg time, [flags];
    var str, t;
    
    // compares args[1] with time() and returns hh:mm elapsed
    // will eventually make flags do things like 'long etc.  For now its
    // just your own time, rather than time().
    flags = [@flags, 'time_unparsed][1];
    str = "";
    switch (flags) {
        case 'long:
            return .to_english(time);
        case 'time_parsed:
            time = time % 356400;
            str = str + pad(tostr(time / 3600), -2, "0");
            str = (str + ":") + pad(tostr((time % 3600) / 60), -2, "0");
            return str;
        default:
            time = (time() - time) % 356400;
            str = str + pad(tostr(time / 3600), -2, "0");
            str = (str + ":") + pad(tostr((time % 3600) / 60), -2, "0");
            return str;
    }
.

method dhms
    arg secs, [long];
    var ret_str, x;
    
    if (long)
        long = 1;
    if (secs > 86400) {
        x = secs / 86400;
        ret_str = tostr(x) + (long ? " day" + ((x < 2) ? "" | "s") | "d");
    } else if (secs > 3600) {
        x = secs / 3600;
        ret_str = tostr(x) + (long ? " hr" + ((x < 2) ? "" | "s") | "h");
    } else if (secs > 60) {
        x = secs / 60;
        ret_str = tostr(x) + (long ? " min" + ((x < 2) ? "" | "s") | "m");
    } else {
        ret_str = tostr(secs) + (long ? " sec" + ((secs < 2) ? "" | "s") | "s");
    }
    return ret_str;
.

method month_str
    arg [args];
    var month, m, time, option;
    
    // args[1] = time (opt); args[2] == 'num, 'long, 'short;
    if (args && (type(args[1]) != 'integer)) {
        time = time();
        option = [@args, 'long][1];
    } else {
        time = [@args, time()][1];
        option = [@args, 'long, 'long][2];
    }
    if (type(time) == 'integer)
        month = substr(ctime(time), 5, 3);
    else
        month = substr(time, 5, 3);
    
    // special case:
    switch (option) {
        case 'short:
            return month;
        case 'num:
            return tostr(((.months())[month])[2]);
        default:
            return ((.months())[month])[1];
    }
.

method year_str
    arg [time];
    var how;
    
    // (time, how) time defaults to time(), how defaults to long
    how = [@time, 'long, 'long][2];
    time = [@time, .time()][1];
    if (how == 'long)
        return substr(ctime(time), 21);
    return substr(ctime(time), 23);
.

method ldate
    arg [args];
    var time, ctime, how, options, sep, hrs, mins, secs;
    
    // takes a bunch of numbers and returns info depending upon what the symbol is
    // time is optional, so is how for that matter.
    // options are listed to the right of the descriptions.
    // How:     'long     -- Monday, January 10th, 1994 (default)
    //          'short    -- Mon, Jan 10, 94
    //          'dmy      -- 10/01/94 (ie: DD/MM/YY) ['slash | 'dash]
    //          'mdy      -- 01/10/94 (ie: MM/DD/YY) ['slash | 'dash]
    //          'ymd      -- 94/10/01 (ie: YY/MM/DD) ['slash | 'dash]
    args = [@args, 'long];
    if (type(args[1]) != 'integer) {
        time = time();
        how = args[1];
        args = delete(args, 1);
    } else {
        time = args[1];
        how = args[2];
        args = sublist(args, 3);
    }
    
    // figure options first
    options = [@args, 0][1];
    sep = "/";
    if (options) {
        switch (options) {
            case 'dash:
                sep = "-";
            case 'slash:
                sep = "/";
        }
    }
    
    // figure actual time
    switch (how) {
        case 'long:
            return ((((((.day_str(time)) + ", ") + (.month_str(time))) + " ") + (.month_day_str(time, 'num))) + ", ") + (.year_str(time));
        case 'noyear:
            return ((((.day_str(time)) + ", ") + (.month_str(time))) + " ") + (.month_day_str(time, 'num));
        case 'short:
            ctime = ctime(time);
            return (((pad(ctime, 3) + ",") + pad(substr(ctime, 4), 7)) + ", `") + (.year_str(time, 'short));
        case 'dmy:
            return (((tostr(.month_day_str(time)) + sep) + (.month_str(time, 'num))) + sep) + (.year_str(time, 'short));
        case 'mdy:
            return (((tostr(.month_str(time, 'num)) + sep) + tostr(.month_day_str(time))) + sep) + (.year_str(time, 'short));
        case 'ymd:
            return ((((.year_str(time, 'short)) + sep) + tostr(.month_str(time, 'num))) + sep) + tostr(.month_day_str(time, 'num));
    }
.

method ltime
    arg [args];
    var time, ctime, how, options, sep1, sep2, ampm, hrs, mins, secs;
    
    // takes a bunch of numbers and returns info depending upon what the symbol is
    // time is optional, so is how for that matter.  Uses '12hr '_ampm for default
    // options are listed after the descriptions.
    //          '24hr     -- 24:00 ['a_m_p_m|'ampm|'_ampm|'ap|'no_ampm]
    //          '12hr     -- 12:00 ['a_m_p_m|'ampm|'_ampm|'ap|'no_ampm]
    //          '24hr_sec -- 24:00:00 ['a_m_p_m|'ampm|'_ampm|'ap|'no_ampm]
    //          '12hr_sec -- 12:00:00 ['a_m_p_m|'ampm|'_ampm|'ap|'no_ampm]
    //          'long     -- twelve thirty four pm['a_m_p_m|'ampm|'_ampm|'no_ampm]
    //          'hour     -- Twelve o'clock
    // BTW, incase your wondering, ltime stands for Lynx Time; i'm a bastard 8b
    args = [@args, '12hr];
    if (type(args[1]) != 'integer) {
        time = time();
        how = args[1];
        args = delete(args, 1);
    } else {
        time = args[1];
        how = args[2];
        args = sublist(args, 3);
    }
    
    // figure options first
    options = [@args, '_ampm][1];
    sep1 = "/";
    sep2 = ":";
    ampm = ["", ""];
    if (options) {
        switch (options) {
            case 'dash:
                sep1 = "-";
            case 'slash:
                sep1 = "/";
            case 'a_m_p_m:
                ampm = [" a.m.", " p.m."];
            case 'ampm:
                ampm = ["am", "pm"];
            case '_ampm:
                ampm = [" am", " pm"];
            case 'ap:
                ampm = ["a", "p"];
            case 'no_ampm:
                ampm = ["", ""];
        }
    }
    
    // figure actual time
    switch (how) {
        case '24hr:
            return substr(.ctime(time), 12, 5);
        case '24hr_sec:
            return substr(.ctime(time), 12, 8);
        case '12hr:
            time = .hr_min_sec(time);
            hrs = toint(time[1]);
            ampm = (hrs < 12) ? ampm[1] | (ampm[2]);
            hrs = hrs % 12;
            hrs = (hrs == 0) ? 12 | hrs;
            return ((tostr(abs(hrs)) + sep2) + (time[2])) + ampm;
        case '12hr_sec:
            time = .hr_min_sec(time);
            hrs = toint(time[1]);
            ampm = (hrs < 12) ? ampm[1] | (ampm[2]);
            hrs = hrs % 12;
            hrs = (hrs == 0) ? 12 | hrs;
            return ((((tostr(hrs) + sep2) + (time[2])) + sep2) + (time[3])) + ampm;
    }
.

method day_str
    arg [args];
    var day, days, d, time, option;
    
    if (args && (type(args[1]) != 'integer)) {
        time = time();
        option = [@args, 'long][1];
    } else {
        time = [@args, time()][1];
        option = [@args, 'long, 'long][2];
    }
    if (type(time) == 'integer)
        day = explode(ctime(time))[1];
    else
        day = explode(time)[1];
    days = .days();
    switch (option) {
        case 'num:
            return .month_day_str();
        case 'short:
            return day;
        default:
            for d in (days) {
                if (match_begin(d, day))
                    return d;
            }
    }
.

method month_day_str
    arg [time];
    
    time = .ctime([@time, .time()][1]);
    return substr(time, 9, 2);
.

method hr_min_sec
    arg [time];
    var ctime;
    
    ctime = .ctime(@time);
    return [substr(ctime, 12, 2), substr(ctime, 15, 2), substr(ctime, 18, 2)];
.

method time_stamp
    return ((.ldate('mdy, 'dash)) + "/") + ($time.ltime('24hr_sec));
.

method to_english
    arg time, [reftime];
    var times, words, x, seconds, ctime, months, month, year, days, out;
    
    // most of this was stolen from MOO (und ve are evil)
    if (time < 1)
        return "0 seconds";
    reftime = reftime || time();
    ctime = (type(reftime) == 'integer) ? ctime(reftime) | reftime;
    words = ["year", "month", "day", "hour", "minute", "second"];
    times = [];
    seconds = [60, 60, 24];
    for x in (seconds) {
        times = [time % x, @times];
        time = time / x;
    }
    months = 0;
    month = ((.months())[substr(ctime, 5, 3)])[2];
    year = toint(.year_str(reftime));
    days = ((.months())[substr(ctime, 5, 3)])[3];
    while (time >= (days + ((month == 2) && (((year % 4) == 0) && (!((year % 400) in [100, 200, 300])))))) {
        time = time - days;
        months = months + 1;
        month = month + 1;
        if (month > 12) {
            year = year + 1;
            month = 1;
        }
    }
    times = [months / 12, months % 12, time, @times];
    out = [];
    for x in [1 .. listlen(words)] {
        if ((times[x]) > 0)
            out = [@out, ((tostr(times[x]) + " ") + (words[x])) + (((times[x]) == 1) ? "" | "s")];
    }
    return $list.to_english(out);
.

method date
    arg [args];
    var time, opt;
    
    time = [@args, time()][1];
    opt = [@args, 'long, 'long][2];
    if (type(time) != 'integer)
        throw(~type, "Time must be submitted as an integer.");
    switch (opt) {
        case 'short:
            return ctime(time);
        default:
            return ((.ltime(time)) + ", ") + (.ldate(time));
    }
.

parent #664
object #7459

var 1 dbref 'programmer_interface
var 1 child_index 0
var 1 fertile 0
var 1 manager #7459
var 1 owned []
var 1 owners [#47]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 16 commands []
var 16 shortcuts []
var 1 inited 1

parent #32
object #33

var 1 child_index 11
var 1 owners [#936]
var 1 fertile 0
var 16 commands [["@copy * to *", 'copy_cmd], ["@task?s", 'tasks_cmd], ["@del-t?ask|@kill *", 'del_task_cmd], ["@backup", 'backup_cmd], ["@shutdown *", 'shutdown_cmd], ["@grep from * for *", 'grep_cmd], ["@egrep from * for *", 'grep_cmd], ["@adjust user|att?itude * to *", 'adjust_user_cmd], ["@log *", 'log_cmd]]
var 16 shortcuts []
var 15 verbs #[]
var 19 contents []
var 23 location #21
var 30 password "*"
var 30 connected_at 0
var 30 last_command_at 0
var 30 connections []
var 1 inited 1
var 1 owned []
var 32 eval_prefix #[["me", "me = this()"], ["here", "here = this().location()"]]
var 33 shutdown_started 0
var 922 command_aliases []
var 30 modes #[]
var 682 letters #[]
var 682 letters_index #[]
var 682 senders 1
var 682 readers [#47]
var 682 notify [#47]
var 682 last_letter 0
var 679 subscribed #[[#33, 0]]
var 1179 gender #1182
var 23 obvious 1
var 17 prose #[]
var 30 prompt ""
var 1 manager #33
var 1 writable [#33]
var 1 readable ['parameters, 'methods, 'code]
var 30 parsers [#2000, #2321]
var 30 tell_traceback ['verbose, 4]
var 30 context #[]
var 1 quota 75000
var 1 dbref 'admin
var 2787 name ['uniq, "Generic Admin"]
var 2787 name_aliases []
var 4309 user_data #[['real_name, [1, "???"]], ['email, [1, "???"]]]

method init_admin
    if (caller() != $root)
        throw(~perm, "Caller is not $root.");
    $sys.new_admin();
.

method uninit_admin
    if (caller() != $root)
        throw(~perm, "Caller is not $root.");
    $sys.admin_going_away();
.

method copy_cmd
    arg sspec, tspec;
    var mode, parsed, sobj, smtd, code, tobj, tmtd, errors;
    
    // @copy dbref.method  to dbref[.method]
    if (!(.is_writable_by(sender())))
        throw(~perm, "Sender is not an owner.");
    
    // 'mode will hold the copy mode, for possible copying of commands and verbs.
    // currently only handles methods.
    mode = 'method;
    parsed = explode(sspec, ".");
    if (listlen(parsed) != 2) {
        .tell(("! \"" + sspec) + "\" is not a reference to the source method.");
        return;
    }
    sobj = $parse.object_match(parsed[1]);
    if (!sobj)
        return;
    smtd = tosym(parsed[2]);
    catch ~methodnf, ~perm {
        code = sobj.list_method(smtd);
    } with handler {
        switch (error()) {
            case ~methodnf:
                .tell(((("! " + (sobj.id())) + " does not define a method ") + toliteral(smtd)) + ".");
            case ~perm:
                .tell(("! " + (sobj.id())) + " is not readable by you.");
        }
        return;
    }
    parsed = explode(tspec, ".");
    if (listlen(parsed) != 2)
        tmtd = smtd;
    else
        tmtd = tosym(parsed[2]);
    tobj = $parse.object_match(parsed[1]);
    if (!tobj)
        return;
    catch ~perm {
        errors = tobj.compile(code, tmtd);
        if (errors) {
            // This should never happen.
            .tell(errors);
        } else {
            .tell((((((toliteral(smtd) + " successfully copied from ") + (sobj.id())) + " to ") + (tobj.id())) + ((smtd != tmtd) ? " as " + toliteral(tmtd) | "")) + ".");
        }
    } with handler {
        .tell(((("! Permission denied to @copy " + tostr('mode)) + " to ") + (tobj.id())) + ".");
    }
.

method del_task_cmd
    arg com, task;
    var syn;
    
    .perms(sender(), 'parser);
    syn = ("`" + com) + " <TID>' (use @tasks to get a TID)";
    task = toint(task);
    if (!task)
        $parse.tell_error("Tasks must be given as an integer", syn);
    catch any {
        $scheduler.del_task(task);
    } with handler {
        $parse.tell_error((traceback()[1])[2], syn);
    }
    .tell(("Task number " + tostr(task)) + " deleted.");
.

method tasks_cmd
    arg com;
    var output, task, task_queue, line, len_c1, time, args;
    
    .perms(sender(), 'parser);
    task_queue = $scheduler.task_queue();
    len_c1 = $list.nth_element_maxlength(1, task_queue);
    len_c1 = (len_c1 > 5) ? len_c1 + 1 | 5;
    output = [];
    time = (($time.ltime('12hr_sec, 'ampm)) + " ") + ($time.ldate('long));
    .tell("=====[ Queued Tasks at: " + time);
    .tell((pad("TID", len_c1) + pad("Exec Time", 20)) + "Task");
    .tell((pad("---", len_c1) + pad("---------", 20)) + "----");
    if (task_queue) {
        for task in (task_queue) {
            // this is broken down like this, because I HATE wrapped lines.
            line = pad(tostr(task[1]), len_c1);
            time = (task[2]) + (task[3]);
            time = (($time.ldate(time, 'dmy, 'dash)) + " ") + ($time.ltime(time, '12hr_sec, 'ampm));
            line = line + pad(time, 20);
            line = (((line + ($data.unparse(task[4]))) + ".") + tostr(task[6])) + "(";
            args = $data.unparse(task[8]);
            line = (line + substr(args, 2, strlen(args) - 2)) + ")";
            .tell($string.chop(line, .linelen()));
        }
    } else {
        .tell("***  NO QUEUED TASKS ****");
    }
.

method backup_cmd
    arg com;
    
    .perms(sender(), 'parser);
    .tell("Starting backup.");
    $sys.do_backup(this());
    .tell("Done.");
.

method shutdown_cmd
    arg com, [why];
    var time;
    
    .perms(sender(), 'parser);
    why = why[1];
    time = toint(why);
    if (time || (why && ((why[1]) == "0")))
        why = $list.to_string(sublist(explode(why), 2));
    else
        time = 5;
    if (why) {
        .tell([(("Shutdown the server in " + tostr(time)) + " minutes because: ") + why, "[yes|no]"]);
        .read_line('_shutdown_ask, why, time);
    } else {
        .tell("Why do you want to shutdown the server?");
        .read_line('_shutdown_why, time);
    }
.

method _shutdown_why
    arg str, time;
    
    if (sender() != this())
        throw(~perm, "Sender is not this.");
    if (!str)
        return .tell("I guess you just don't want to shutdown...");
    .tell([(("Shutdown the server in " + tostr(time)) + " minutes because: ") + (str[1]), "[yes|no]"]);
    .read_line('_shutdown_ask, @str, time);
.

method _shutdown_ask
    arg str, why, time;
    
    str = str[1];
    if (sender() != this())
        throw(~perm, "Sender is not this.");
    if (match_begin("no", str))
        return .tell("I didn't think so...");
    .tell("Ok...");
    if (time)
        shutdown_started = time * 60;
    ._shutdown(why);
.

method _shutdown
    arg why;
    var line1, line2;
    
    if (sender() != this())
        throw(~perm, "Sender is not this");
    
    //
    if (shutdown_started >= 120)
        shutdown_started = shutdown_started - 120;
    else if (shutdown_started >= 60)
        shutdown_started = shutdown_started - 60;
    else
        shutdown_started = 0;
    
    //
    if (shutdown_started > 0) {
        line1 = " *** SERVER WILL BE SHUTDOWN IN ";
        line1 = line1 + uppercase($time.elapsed(shutdown_started, 'long));
        if (why)
            line1 = line1 + " because:";
        line2 = (" *** " + why) + " ***";
        $channels.announce('all, line1 + " ***");
        if (why)
            $channels.announce('all, line2);
        $scheduler.add_task(120, '_shutdown, why);
    } else {
        $sys.shutdown(why);
    }
.

method _grep
    arg what, obj, [type];
    var method, found, findings, what;
    
    findings = [];
    for method in (obj.methods()) {
        found = (| $string.search_pat(what, obj.list_method(method), 1, @type) |);
        if (found)
            findings = findings + [[obj, method, found]];
        pause();
    }
    return findings;
.

method adjust_user_cmd
    arg com, com, who, com, what;
    var promos, wp, name, kpromos;
    
    .perms(sender(), 'parser);
    what = explode(what);
    what = what[listlen(what)];
    promos = #[["user", ['user, $user]], ["builder", ['builder, $builder]], ["programmer", ['programmer, $programmer]], ["admin", ['admin, $admin]]];
    kpromos = dict_keys(promos);
    who = .match_env_nice(who);
    wp = who.parents();
    if (!(what in kpromos))
        $parse.tell_error(("Promote to any of: " + ($list.to_english(kpromos))) + ".");
    (| who.chparents([(promos[what])[2]]) |);
    who.tell((((((.namef()) + " has made you ") + ($string.a_or_an(what))) + " ") + what) + ".");
    if ($guest in wp) {
        who.set_password("password");
        (| who.del_filter($wrap_filter) |);
        who.tell("!  Your password is currently \"password\".  ");
        who.tell("!  Please change it immediately with the @password command.");
        who.tell("!  Characters with unchanged passwords before they disconnect will be destroyed.");
        who.set_title("");
    }
    if (what == "admin")
        (| who.set_dbref(tosym(who.namef())) |);
    .tell((((((who.namef()) + " is now ") + ($string.a_or_an(what))) + " ") + what) + ".");
.

method grep_cmd
    arg com, prep_from, from, prep_for, what;
    var found, x;
    
    .perms(sender(), 'parser);
    .tell("Searching...");
    if (com == "@grep") {
        if (("^" in what) != 1)
            what = "*" + what;
        if (what && (("$" in what) != strlen(what)))
            what = what + "*";
    }
    from = .match_env_nice(from);
    found = .grep(what, from, @(com == "@grep") ? [] | ['regexp]);
    for x in (found)
        .tell((((((x[1]).dbref()) + ".") + tostr(x[2])) + " : ") + tostr((x[3])[1]));
    .tell("--- + Finis + ---");
.

method egrep_cmd
    arg what;
    var found, x;
    
    .perms(sender(), 'parser);
    .tell("Searching...");
    found = .grep(what, 'regexp);
    for x in (found)
        .tell((((((x[1]).name_str()) + ".") + tostr(x[2])) + " : ") + tostr((x[3])[1]));
    .tell("--- + Finis + ---");
.

method grep
    arg what, from, [type];
    var object, method, found, findings, count, total;
    
    findings = [];
    count = 0;
    total = 0;
    for object in ([from, @from.descendants()]) {
        found = ._grep(what, object, @type);
        if (found)
            findings = findings + [@found];
        count = count + 1;
        total = total + 1;
        if (count == 50) {
            .tell(tostr(total) + " Objects Searched...");
            count = 0;
        }
        pause();
    }
    
    // fix later
    .tell(tostr(total) + " Objects Searched.");
    return findings;
.

method log_cmd
    arg com, [line];
    
    .perms(sender(), 'parser);
    if (!(line[1])) {
        return $changes_log.read_cmd("", "");
    } else {
        line = line[1];
        line = (($time.ldate('mdy, 'dash)) + "]: ") + line;
        line = ((((.namef()) + " [") + ($time.ltime('24hr))) + "/") + line;
        $changes_log.add_text([line], this(), 'dont_even_think_it);
        .tell("Thank you for your donation.");
    }
.


parent #1431
object #2000

var 1 child_index 0
var 1 fertile 0
var 1 manager #2000
var 1 owners [#47]
var 1 writable [#47]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 1 inited 1
var 1 dbref 'command_parser

method parse
    arg user, str, next_parser, [other_parsers];
    var loc, cmdstr, cmd, obj;
    
    // Match commands on user/room.
    loc = user.location();
    
    // trim the string
    cmdstr = str;
    while (cmdstr && ((cmdstr[1]) == " "))
        cmdstr = substr(cmdstr, 2);
    if (str) {
        // Check commands on this.
        cmd = user.match_command(cmdstr);
        if (cmd)
            return [user, cmd[1], @cmd[2]];
    
        // Check commands on location.
        cmd = loc.match_command(cmdstr);
        if (cmd)
            return [loc, cmd[1], @cmd[2]];
    
        // Try exit names.
        for obj in (loc.exits()) {
            if ((obj.match_name(str)) || (obj.match_name_aliases(str)))
                return [obj, 'invoke];
        }
    }
    
    // no luck.
    return next_parser.parse(user, str, @other_parsers);
.

parent #1431
object #2294

var 1 child_index 0
var 1 fertile 0
var 1 manager #2294
var 1 owners [#47]
var 1 writable [#47]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 1 inited 1
var 1 dbref 'command_aliases_parser

method parse
    arg user, str, next_parser, [other_parsers];
    var alias, match, i, result;
    
    for alias in (user.command_aliases()) {
        match = match_pattern(alias[1], str);
        if (match != 0) {
            str = alias[2];
            for i in [1 .. listlen(match)]
                str = strsub(str, "%" + tostr(i), match[i]);
            break;
        }
    }
    result = next_parser.parse(user, str, @other_parsers);
    if ((match != 0) && (result == 'failed))
        return ("Command converted to \"" + str) + "\" but not understood.";
    return result;
.

parent #2250
object #7292

var 1 dbref 'reaper_log
var 1 child_index 0
var 1 fertile 0
var 1 manager #37
var 1 owned []
var 1 owners [#37]
var 1 writable []
var 1 readable ['methods, 'code]
var 7261 public ['readable]
var 1032 text []
var 2787 name ['prop, "Reaper Logfile"]
var 2787 name_aliases []
var 1179 gender #1182
var 15 verbs #[]
var 17 prose #[]
var 1178 messages #[]
var 23 location #21
var 23 obvious 1
var 1 inited 1

parent #1
object #0

var 0 admins []
var 0 new_user_class #33
var 0 starting_room #140
var 0 exit_starting_room #22
var 0 server_port 1138
var 0 current_receiver #9687
var 0 backup_interval 3600
var 0 last_backup 784609118
var 0 startup_time 784609072
var 1 child_index 1
var 1 owners [#936]
var 1 fertile 0
var 1 inited 1
var 0 startup_objects []
var 0 agents [#246, #0, #282, #27, #1, #7794]
var 0 default_heartbeat_interval 5
var 0 default_port 1138
var 1 owned [#9686, #9687]
var 0 user_starting_quota 75000
var 0 server_address #[['ip, ""], ['hostname, "somewhere"]]
var 1 manager #0
var 1 writable [#0]
var 1 readable ['parameters, 'methods, 'code]
var 0 anonymous_class #134
var 1 info ["The system object has special server-granted permissions, and performs tasks which require these permisions. It receives the 'heartbeat message, as well as being pivitol in such tasks as generating new connections and creating objects."]
var 1 dbref 'sys
var 0 system_email_addresses #[['default, "somebody@somewhere"]]
var 0 core_version "1.0"

method startup
    arg args;
    var opt, str, obj;
    
    args = sublist(args, 3);
    catch any {
        if (sender() != 0)
            throw(~perm, "Sender is not the server.");
    
        // Get rid of any lingering connection objects.
        for obj in ($old_connection.children()) {
            catch any {
                obj.destroy();
            } with handler {
                .log($parse.traceback(traceback(), -1, ""));
            }
        }
    
        // Look for a port specification -- this will go away
        opt = "-p" in args;
        if (opt) {
            server_port = opt ? (| toint(args[ind + 1]) |) | default_port;
            args = (| delete(args, opt) |);
            args = (| delete(args, opt) |);
        }
    
        // Bind to the port.
        catch ~socket, ~bind {
            bind(server_port, $sys);
        } with handler {
            .log(("Can't bind to port " + tostr(server_port)) + ", exiting...");
            shutdown();
        }
    
        // Initialize variables and log startup message.
        .new_connection();
        log((("Server starting on port " + tostr(server_port)) + " ") + ($time.date()));
    
        // Set up five-second heartbeat.
        set_heartbeat_freq(default_heartbeat_interval);
    
        // set the startup time.
        startup_time = time();
    
        // tell objects who should know, that we are up.
        for obj in (startup_objects) {
            .log(("Calling " + (obj.dbref())) + ".startup()");
            (| obj.startup(@args) |);
        }
    } with handler {
        .log(("Startup ERROR at " + ctime()) + ":");
        .log($parse.traceback(traceback(), -1, ""));
    }
.

method uptime
    return time() - startup_time;
.

method startup_time
    return startup_time;
.

method new_connection
    // will move this to the new network heirarchy
    if ((sender() != this()) || (caller() != definer()))
        throw(~perm, "Invalid call to private method.");
    current_receiver = $old_connection.spawn();
    current_receiver.set_manager(current_receiver);
    bind(server_port, current_receiver);
.

method new_user_class
    return new_user_class;
.

method set_new_user_class
    arg obj;
    
    if (!(.is_admin(sender())))
        throw(~perm, "Sender not an admin.");
    if (!(obj.has_ancestor($user)))
        throw(~type, "Argument is not a user object.");
    new_user_class = obj;
.

method create_user
    arg name, password, email, [type];
    var user;
    
    if ((!(| .perms(caller(), $old_connection) |)) && (!(| .perms(sender(), 'system) |)))
        throw(~perm, "caller and sender are not allowed to call this method.");
    type = [@type, 'new_user_class][1];
    catch any {
        user = .(type)().spawn(name);
        user.set_name(name);
        if (type == 'new_user_class)
            user.set_password(password);
        else
            user.set_password(crypt(substr(crypt("", substr(name, 1, 2)), 1, random(13))) + "12");
        user.set_manager(user);
        user.set_email(email);
        user.chown([user]);
    } with handler {
        // Failed to initialize the child; destroy it.
        if (!(| user.destroy() |)) {
            (| user.uninitialize() |);
            (| del_name(user.dbref('symbol)) |);
            (| del_name(tosym(name)) |);
            (| destroy(user) |);
        }
        rethrow(error());
    }
    return user;
.

method connection_starting
    // will move this to the new network heirarchy
    if (caller() != $old_connection)
        throw(~perm, "Caller is not $old_connection.");
    .new_connection();
.

method admins
    return admins;
.

method is_admin
    arg obj;
    
    return (obj == $sys) || (obj in admins);
.

method binary_dump
    if (!($sys.is_admin(sender())))
        throw(~perm, "Sender is not an admin.");
    return binary_dump();
.

method shutdown
    arg [why];
    var line1, line2;
    
    if ((!($sys.is_admin(sender()))) || (definer() != this()))
        throw(~perm, "Sender is not an admin.");
    why = [@why, ""][1];
    
    // tell everybody everything
    line1 = "*** SHUTDOWN called by " + (sender().namef('ref));
    if (why) {
        line1 = line1 + " because:";
        line2 = ("*** " + why) + " ***";
    }
    .log(line1 + " ***");
    $channels.announce('all, line1 + " ***");
    if (why) {
        .log(line2);
        $channels.announce('all, line2);
    }
    return shutdown();
.

method change_sender_parents
    arg parents;
    var p;
    
    if (caller() != $root)
        throw(~perm, "Caller is not $root.");
    (> chparents(sender(), parents) <);
.

method spawn_sender
    arg suffix, manager, [owners];
    var namestr;
    
    (> .perms(caller(), $root, $sys) <);
    if (!owners)
        owners = [manager];
    namestr = (tostr(sender().dbref('symbol)) + "_") + suffix;
    return .create([sender()], tosym(namestr), manager, owners);
.

method assign_dbref
    arg name;
    var keepers, x;
    
    (> .perms(caller(), $root, $sys) <);
    if (type(name) != 'symbol)
        throw(~type, "Name must be given as a symbol.");
    
    // don't run this for now--tosym is fucked.
    if (0) {
        // yeah, we change it to a string, but they don't have to know that.
        name = tostr(name);
    
        // lowercase all names:
        name = lowercase(name);
    
        // If it isn't a keeper toss the good old error
        keepers = "abcdefghijklmnopqrstuvwxyz1234567890_";
        for x in [1 .. strlen(name)] {
            if (!((name[x]) in keepers))
                throw(~type, "Name has one or more non-alphanumeric characters.");
        }
        name = tosym(name);
    }
    
    // make sure nobody has it yet
    if ((| get_name(name) |) != ~namenf)
        throw(~perm, "Name already assigned to " + (get_name(name).namef('ref)));
    
    // woo woo, i'm filled with joy, lets give them the name.
    set_name(name, sender());
.

method destroy_sender
    (> .perms(caller(), $root) <);
    del_name(sender().dbref('symbol));
    destroy(sender());
.

method is_system
    arg obj;
    
    return (obj in admins) || (obj in agents);
.

method log
    arg text;
    var l;
    
    if ((!(| .perms(sender(), 'system) |)) && (!(| .perms(caller(), 'system) |)))
        throw(~perm, "NOT");
    if (type(text) == 'list) {
        for l in (text)
            .log(l);
    } else {
        log((($time.time_stamp()) + "> ") + text);
    }
.

method connect
    arg [args];
    
    (> .perms(caller(), $network_root) <);
    (> connect(@args) <);
.

method heartbeat
    if (sender() != 0)
        throw(~perm, "Sender is not the server.");
    
    // personally I prefer more granularity, so changed it.
    // if (time() / backup_interval > last_backup / backup_interval)
    if (time() > (last_backup + backup_interval))
        .do_backup(this());
    $scheduler.pulse();
.

method do_backup
    arg who;
    var line, name;
    
    .perms(sender(), 'system);
    catch any {
        name = who.namef('ref);
        .log(("BACKUP (" + name) + ") ");
        line = (("It is: " + ($time.ltime())) + " -- BACKUP -- called by ") + name;
        $channels.announce('System, line);
    }
    last_backup = time();
    pause();
    pause();
    .text_dump();
.

method backup_interval
    return backup_interval;
.

method set_backup_interval
    arg val;
    
    if (!(.is_admin(sender())))
        throw(~perm, "Sender not an admin");
    backup_interval = val;
.

method sender_data
    var output, i;
    
    if (caller() != $root)
        throw(~perm, "Caller is not $root.");
    return data(sender());
.

method get_system_email
    arg what;
    var email;
    
    // email directory for system services, such as arch admins.
    email = (| system_email_addresses[what] |);
    if (!email)
        email = (| system_email_addresses['default] |) || "<no email set>";
    return email;
.

method new_admin
    if (caller() != $admin)
        throw(~perm, "Caller is not $admin.");
    admins = setadd(admins, sender());
.

method admin_going_away
    if (caller != $admin)
        throw(~perm, "Caller is not $admin.");
    admins = setremove(admins, sender());
.

method add_startup_object
    arg obj;
    
    (> .perms(sender(), 'manager) <);
    startup_objects = setadd(startup_objects, obj);
.

method agents
    return agents;
.

method text_dump
    .perms(sender(), 'this);
    pause();
    return text_dump();
.

method del_startup_object
    arg obj;
    
    (> .perms(sender(), 'manager) <);
    startup_objects = setremove(startup_objects, obj);
.

method server_address
    arg [type];
    
    type = [@type, 'hostname][1];
    return server_address[type];
.

method user_starting_quota
    return user_starting_quota;
.

method execute
    arg script, args, [background];
    
    (> .perms(sender(), @admins) <);
    (> run_script(script, args, @background) <);
.

method anonymous_class
    return anonymous_class;
.

method create
    arg parents, name, manager, [owners];
    var new;
    
    .perms(sender(), 'system);
    new = create(parents);
    catch any {
        new.set_dbref(name);
        new.initialize();
        new.set_manager(manager);
        new.chown([@owners, [new]][1]);
    } with handler {
        // Failed to initialize the child; destroy it.
        if (!(| new.destroy() |)) {
            (| new.uninitialize() |);
            (| del_name(new.dbref('symbol)) |);
            (| del_name(tosym(name)) |);
            (| destroy(new) |);
        }
        rethrow(error());
    }
    return new;
.

method system
    return admins + agents;
.

method run_script
    arg script, args, [background];
    
    .perms(sender(), @admins);
    (> run_script(script, args, @background) <);
.

method bind
    arg port, obj;
    
    (> .perms(caller(), $network_root) <);
    (> bind(port, obj) <);
.

method deassign_dbref
    arg name;
    
    if (caller() != $root)
        throw(~perm, "Caller is not $root.");
    del_name(name);
.

method del_system_email
    arg key;
    
    (> .perms(sender(), 'manager) <);
    system_email_addresses = dict_del(system_email_addresses, key);
.

method add_system_email
    arg key, email;
    
    (> .perms(sender(), 'manager) <);
    if (type(key) != 'symbol)
        throw(~type, "Key is not a symbol.");
    if (type(email) != 'string)
        throw(~type, "Email address is not a string.");
    system_email_addresses = dict_add(system_email_addresses, key, email);
.

method compile
    arg code, name;
    var line;
    
    (> .perms(sender()) <);
    line = ("SYSTEM: ." + tostr(name)) + "() MODIFIED";
    line = (line + " by ") + (sender().namef('ref));
    .log(line);
    return (> pass(code, name) <);
.

method unbind
    arg port, obj;
    
    (> .perms(caller(), $network_root) <);
    (> unbind(port) <);
.

method version
    arg [args];
    var ver;
    
    args = [@args, 'driver][1];
    switch (args) {
        case 'driver:
            ver = version();
            return (((tostr(ver[1]) + ".") + tostr(ver[2])) + "-") + tostr(ver[3]);
        case 'core:
            return core_version;
    }
.

method startup_objects
    return startup_objects;
.

method last_backup
    return last_backup;
.

method foobar
    .do_backup();
    .shutdown();
.

parent #9440
object #9443

var 1 dbref 'notice_interface_1
var 1 child_index 0
var 1 fertile 0
var 1 manager #7232
var 1 owned []
var 1 owners [#7232]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 16 commands []
var 16 shortcuts []
var 7801 connection #9442
var 1 inited 1

parent #12
object #44

var 1 child_index 0
var 1 owners [#936]
var 1 fertile 0
var 1 inited 1
var 1 owned []
var 44 boolean_strs [["yes", "true", "1", "on"], ["no", "false", "0", "off"]]
var 1 manager #44
var 1 writable [#44]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'parse

method reference
    arg string, [sep];
    var middle, ref;
    
    // receives: "<object><seperator><method/param>"
    // returns ["<object>", "<method/param>"]
    // seperator defaults to a period.
    sep = [@sep, "."][1];
    middle = sep in string;
    if (!middle)
        ref = [string, ""];
    else if (middle == 1)
        ref = [sender().namef(['dbref]), substr(string, 2)];
    else
        ref = [substr(string, 1, middle - 1), substr(string, middle + 1)];
    
    // assumes "()" will appear at the end of the reference if at all,
    // and strips it off if present
    if ("()" in (ref[2]))
        ref = [ref[1], substr(ref[2], 1, ("()" in (ref[2])) - 1)];
    return ref;
.

method object_match
    arg name, [who];
    var msg;
    
    // .object_match("name"[, who])
    // -> 0        name was the empty string
    // -> ~objnf   nothing matched name
    // -> ~ambig   more than one object matched name
    // Attempt to match an object name with who.match_environment().  If one is found, return it.  Else, print a message and return one of the above false values.
    // 'who' defaults to sender().
    who = who ? who[1] | sender();
    if (!name) {
        (| who.tell("You must give the name of something.") |);
        return 0;
    }
    catch ~objnf, ~ambig {
        return who.match_environment(name);
    } with handler {
        switch (error()) {
            case ~objnf:
                msg = ("I don't see any \"" + name) + "\" here.";
            case ~ambig:
                msg = ("I don't know which \"" + name) + "\" you mean.";
        }
        (| who.tell(msg) |);
        return error();
    }
.

method tell_error
    arg problem, [args];
    var who, syntax, line;
    
    // arg 1 == error
    // arg 2 (opt) == syntax
    // arg 3 (opt) == who
    // arg 4 (opt) == subbing object (in place of 'Object') -- string.
    syntax = [@args, 0][1];
    who = [@args, sender(), sender()][2];
    if (syntax)
        who.tell(("=> Syntax: `" + syntax) + "`");
    if (problem) {
        if (type(problem) == 'string) {
            problem = $string.wrap_line(problem, (| who.linelen() |) || 79, "!  ", 1);
        } else {
            for line in [1 .. listlen(problem)]
                problem = replace(problem, line, "!  " + (problem[line]));
        }
        who.tell(problem);
    }
    throw(~stop, "", 'no_traceback);
.

method usage
    arg method, [dbref];
    var code, extracted;
    
    // .usage(method[, dbref])
    // Extract initial comments from the given method, returning them as a list of strings.
    // Throw ~methodnf if dbref does not define method.
    // dbref defaults to sender.
    dbref = dbref ? dbref[1] | sender();
    dbref = dbref.find_method(method);
    code = dbref.list_method(method);
    extracted = [];
    if ((code[1]) == "disallow_overrides;")
        code = delete(code, 1);
    if (("arg " in (code[1])) == 1)
        code = delete(code, 1);
    if (("var " in (code[1])) == 1)
        code = delete(code, 1);
    while (!(code[1]))
        code = delete(code, 1);
    while (("//" in (code[1])) == 1) {
        extracted = [@extracted, strsub(code[1], "//", "")];
        code = delete(code, 1);
    }
    return extracted;
.

method match
    arg string;
    var loc, obj;
    
    // called by $user.match_* methods, simply parses up the basic me/here/$*
    if (string == "me")
        return sender();
    if (string == "here")
        return sender().location();
    if (string && ((string[1]) == "$")) {
        obj = todbref(substr(string, 2));
        if (!valid(obj))
            throw(~objnf, "No such object " + string);
        return obj;
    } else {
        return 0;
    }
.

method boolean
    arg str;
    
    if (str in (boolean_strs[1]))
        return 1;
    else if (str in (boolean_strs[2]))
        return 0;
    else
        throw(~unknown, "Boolean flag not recognized.");
.

method full_reference
    arg str, [args];
    var sep, defobj, middle, ref, type;
    
    defobj = [@args, sender()][1];
    if ("()" in str)
        str = substr(str, 2, ("()" in str) - 1);
    if ("." in str) {
        type = 'method;
        sep = ".";
    } else if ("," in str) {
        type = 'parameter;
        sep = ",";
    } else {
        type = 'unknown;
        sep = ".";
    }
    middle = sep in str;
    if (!middle)
        ref = [(> $object.to_dbref(str) <), ""];
    else if (middle == 1)
        ref = [defobj, substr(str, 2)];
    else
        ref = [(> $object.to_dbref(substr(str, 1, middle - 1)) <), substr(str, middle + 1)];
    return [type, ref[1], (ref[2]) ? tosym(ref[2]) | 0];
.

method traceback
    arg traceback, [args];
    var line, out, pre, lines, cur, x, error;
    
    // $parse.traceback(traceback(), lines, pre);
    // -1 lines represents the full error
    // pre is set to "! " unless otherwise specified.
    lines = [@args, -1][1];
    pre = [@args, "! ", "! "][2];
    error = [@args, 0, 0, 0][3];
    
    //
    out = [(pre + "=> ") + ((traceback[1])[2])];
    pre = pre + "   ";
    
    //
    if (error == 0)
        out = [@out, (pre + "Thrown by ") + (._traceback(@sublist(traceback[2], 2)))];
    else
        out = [@out, (((pre + "Error ") + toliteral(error)) + " thrown by ") + (._traceback(@sublist(traceback[2], 2)))];
    
    //
    for x in [1 .. listlen(traceback) - 2] {
        if ((x <= lines) || (lines == (-1))) {
            line = ($data.unparse((traceback[x + 2])[1])) + ": ";
            line = line + (._traceback(@sublist(traceback[x + 2], 2)));
            out = [@out, pre + line];
        }
    }
    return out;
.

method _traceback
    arg what, [more];
    var line;
    
    if (more)
        return (((((($data.unparse(more[1])) + ".") + tostr(what)) + "() (") + ($data.unparse(more[2]))) + ") line ") + tostr(more[3]);
    else
        return tostr(what);
.

method options
    arg line, [defaults];
    var loc, opt, x, out, defs;
    
    // this will not pay attention to groupings with quotes, should add
    // the functionality in later.
    // templates: #[["opt", [0/1, 0/1]]]; / #[['opt, [bool, value]]]; 
    defaults = [@defaults, #[]][1];
    if (!(("-" in line) || ("+" in line)))
        return [explode(line), defaults];
    line = explode(line);
    out = line;
    for x in [1 .. listlen(line)] {
        if (((line[x])[1]) in ["-", "+"]) {
            out = setremove(out, line[x]);
            opt = substr(line[x], 2);
            defs = (| defaults[opt] |) || [0, ""];
            defs = [((line[x])[1]) in ["+"], defs[2]];
            if (defs[2]) {
                if (listlen(line) >= (x + 1)) {
                    defs = [defs[1], line[x + 1]];
                    out = setremove(out, line[x + 1]);
                }
            }
            defaults = dict_add(defaults, opt, defs);
        }
    }
    return [out, defaults];
.

parent #2485
object #2488

var 1 child_index 0
var 1 fertile 0
var 1 manager #2488
var 1 owners [#936]
var 1 writable [#2488]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 1 inited 1
var 1 dbref 'and

method unparse
    arg andlist;
    var str, x;
    
    str = "";
    for x in (andlist) {
        catch any {
            str = (str + (x.unparse())) + " && ";
        } with handler {
            str = (str + tostr(x)) + " && ";
        }
    }
    return ("(" + (str && substr(str, 1, strlen(str) - 4))) + ")";
.

method test
    arg andlist, [args];
    var val, x;
    
    val = 0;
    for x in (andlist) {
        catch ~type, ~methodnf {
            val = x.test(@args);
        } with handler {
            val = x;
        }
        if (!val)
            break;
    }
    return val;
.

parent #12
object #46

var 1 child_index 0
var 1 owners [#936]
var 1 fertile 0
var 1 inited 1
var 1 owned []
var 1 manager #46
var 1 writable [#46]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'dict

method map_method
    arg ls, what;
    var x, dict;
    
    // args[1] == list of objects
    // args[2] == symbol for method on objects
    // it will create a dictionary out of the two.
    dict = #[];
    
    // Get list's method(whatever) and add it to the dictionary
    for x in [1 .. listlen(ls)]
        dict = dict_add(dict, ls[x], (ls[x]).(what)());
    return dict;
.

method merge
    arg [args];
    var x, dict, z, tule, dz, axz, keys;
    
    // merges all dictionaries into a single one, if they have the same key's --
    // basing off of args[1] (this should be the longest list (i know, bad Lynx).
    dict = args[1];
    keys = dict_keys(args[1]);
    for x in [2 .. listlen(args)] {
        for z in (keys) {
            dz = dict[z];
            axz = (args[x])[z];
            if (type(dict[z]) == 'list)
                tule = dz;
            else
                tule = [dz];
            tule = [@tule, axz];
            dict = dict_add(dict, z, tule);
        }
    }
    return dict;
.

method to_list
    arg dict;
    var list, x, k;
    
    // merges into an associated list.
    k = dict_keys(dict);
    list = [];
    for x in (k)
        list = [@list, [x, dict[x]]];
    return list;
.

method merge_to_list
    arg [args];
    var x, dict, z, tule, dz, axz, keys, list;
    
    // merges all dictionaries into a single list, where each related key
    // is merged with all it's other values as a sublist
    // basing off of args[1] (this should be the longest list (i know, bad Lynx).
    dict = .merge(@args);
    list = [];
    for z in (dict_keys(dict))
        list = [@list, dict[z]];
    return list;
.

method union
    arg dict1, dict2;
    var key;
    
    // like union() but for dictionaries.  adds any keys from dict2 that don't
    // already exist in dict1 to dict1 and returns the result.  Order of keys in
    // result is not guaranteed.
    for key in (dict1)
        dict2 = dict_add(dict2, key[1], key[2]);
    return dict2;
.

method values
    arg dict;
    var list, x, k;
    
    // returns values same as dict_keys() returns keys.
    k = dict_keys(dict);
    list = [];
    for x in (k)
        list = [@list, dict[x]];
    return list;
.

method replace
    arg dict, key, value;
    
    dict = (> dict_del(dict, key) <);
    dict = (> dict_add(dict, key, value) <);
    return dict;
.

method apply
    arg tdict, list;
    var x;
    
    // Apply a translation-dict to a list
    for x in [1 .. listlen(list)] {
        catch ~keynf {
            list = replace(list, x, tdict[list[x]]);
        }
    }
    return list;
.

method apply_to_keys
    arg tdict, dict;
    var x, newdict;
    
    // Apply a t-dict to the keys of a dict
    newdict = #[];
    for x in (dict) {
        catch ~keynf {
            x = replace(x, 1, tdict[x[1]]);
        }
        newdict = dict_add(newdict, @x);
    }
    return newdict;
.

method apply_to_values
    arg tdict, dict;
    var x, newdict;
    
    // Apply a t-dict to the values of a dict
    newdict = #[];
    for x in (dict) {
        catch ~keynf {
            x = replace(x, 2, tdict[x[2]]);
        }
        newdict = dict_add(newdict, @x);
    }
    return newdict;
.

method invert
    arg dict;
    var inverted, x;
    
    // Invert a dict (keys<->values)
    inverted = #[];
    for x in (dict_keys(dict))
        inverted = dict_add(inverted, dict[x], x);
    return inverted;
.

method add_elem
    arg dict, key, elem;
    var value;
    
    // same as old dict_add_elem
    value = (| dict[key] |);
    if ((type(value) != 'list) && (type(value) != 'error))
        throw(~type, ((("Value for key " + ($data.unparse(key))) + " (") + ($data.unparse(value))) + ") is not a list.");
    if (value)
        value = [@value, elem];
    else
        value = [elem];
    return dict_add(dict, key, value);
.

parent #24
object #984

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 15 verbs #[]
var 23 location #840
var 1 inited 1
var 1179 gender #1182
var 23 obvious 1
var 17 prose #[]
var 1 manager #984
var 1 writable [#984]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'nothing
var 2787 name ['prop, "nothing whatsoever"]
var 2787 name_aliases []

parent #12
object #9615

var 1 dbref 'base_evaluator
var 1 child_index 0
var 1 fertile 0
var 1 manager #9615
var 1 owned []
var 1 owners [#2277]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 1 inited 1

parent #40
object #1182

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 1 inited 1
var 40 cgender_name "Neuter"
var 40 gender_name "neuter"
var 40 pronouns #[['pr, "itself"], ['pp, "its"], ['po, "it"], ['ps, "it"], ['pq, "its"], ['prc, "Itself"], ['ppc, "Its"], ['poc, "It"], ['psc, "It"], ['pqc, "Its"]]
var 40 number 'singular
var 1 manager #1182
var 1 writable [#1182]
var 1 readable ['parameters, 'methods, 'code]
var 40 context ["itself", "its", "it", "it", "its", "Itself", "Its", "It", "It", "Its"]
var 1 dbref 'gender_neuter


parent #2679
object #140

var 1 child_index 0
var 1 owners [#936]
var 1 fertile 0
var 16 commands []
var 16 shortcuts []
var 15 verbs #[]
var 19 contents [#592]
var 1 inited 1
var 169 messages #[['housekeeper, #[['public, 1], ['text, "%N is absorbed by one of the couches"]]]]
var 1 owned []
var 1179 gender #1182
var 17 prose #[['short, ["The quiet bood warm void of creation surrounds you."]]]
var 1 manager #140
var 1 writable [#140]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'creation
var 2787 name ['prop, "Creation"]
var 2787 name_aliases []
var 2679 exits []
var 2679 realm <#2717, ['interior]>
var 2679 coordinates #[]

parent #1377
object #35

var 35 templates #[["l?ook at %this", [#17]], ["l?ook %this", [#17]], ["take|get %this", [#24]], ["drop %this", [#24]], ["erase * on|from %this", [#7248]], ["erase %this", [#7248]], ["read|nread %this", [#7248]], ["write on %this", [#7248]], ["write at * on %this", [#7248]], ["write * on %this", [#7248]], ["copy from %this to *", [#7248]], ["@public on %this is *", [#7261]]]
var 1 child_index 0
var 1 owners [#936]
var 1 fertile 0
var 1 inited 1
var 1 owned []
var 1 manager #35
var 1 writable [#35]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'verb_cache

method add_template
    arg template;
    
    if (caller() != $has_verbs)
        throw(~perm, "Caller is not $has_verbs.");
    templates = $dict.add_elem(templates, template, sender());
.

method del_template
    arg template;
    
    if (caller() != $has_verbs)
        throw(~perm, "Caller is not $has_verbs.");
    templates = $dict.del_elem(templates, template, sender());
.

method templates
    return dict_keys(templates);
.

parent #40
object #1183

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 1 inited 1
var 40 cgender_name "Male"
var 40 gender_name "male"
var 40 pronouns #[['pr, "himself"], ['pp, "his"], ['po, "him"], ['ps, "he"], ['pq, "his"], ['prc, "Himself"], ['ppc, "His"], ['poc, "Him"], ['psc, "He"], ['pqc, "His"]]
var 40 number 'singular
var 1 manager #1183
var 1 writable [#1183]
var 1 readable ['parameters, 'methods, 'code]
var 40 context ["himself", "his", "him", "he", "his", "Himself", "His", "Him", "He", "His"]
var 1 dbref 'gender_male

parent #1170
object #4348

var 1 dbref 'motd
var 1 child_index 0
var 1 fertile 0
var 1 manager #7232
var 1 owned []
var 1 owners [#7232, #1387, #1388]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 1 inited 1
var 1 info ["The Message of the Day object.  Called by $old_connection and $fingerd.", "This builds a motd from different parameters, called by $motd.build().", "Parameters can be:", "", "     'long             -- long title.", "     'short            -- short title.", "     'title            -- server title.", "     'name             -- server name.", "     'notes            -- connection notes.", "     'quote            -- random quote.", "     'admins           -- list of admins.", "     'connected        -- currently connected users.", "     'version          -- ColdMUD driver version."]
var 4348 server_name "a Cold Dark Core World"
var 4348 notes []
var 4348 server_title "Virtual Environment Server"

method build
    arg [args];
    var output, out;
    
    output = [];
    if (!args)
        args = ['long, 'quote];
    if ((args[1]) == 'default)
        args = ['name, "", 'title, "", "", 'quote, "", 'notes, "", 'admins, 'connected, 'version];
    while (args) {
        if (type(args[1]) == 'string) {
            output = output + [""];
        } else {
            switch (args[1]) {
                case 'long:
                    args = insert(args, ((args[1]) in args) + 1, 'title);
                    args = replace(args, (args[1]) in args, 'long_name);
                    continue;
                case 'short:
                    args = insert(args, ((args[1]) in args) + 1, 'title);
                    args = replace(args, (args[1]) in args, 'name);
                    continue;
                case 'title:
                    out = $string.center(server_title, 79);
                    output = output + [out];
                case 'name:
                    out = $string.center(("+ " + server_name) + " +", 79);
                    output = output + [out];
                case 'notes:
                    out = $list.center_lines(notes, 79);
                    output = output + out;
                case 'quote:
                    out = $list.center_lines($code.random_quote(), 79);
                    output = output + out;
                case 'admins:
                    out = $list.to_english($list.map($sys.admins(), 'namef));
                    out = $string.center("Administrators: " + out, 79);
                    output = output + [out];
                case 'connected:
                    out = "Currently Connected users: ";
                    out = out + tostr(listlen($user_db.connected()));
                    out = $string.center(out, 79);
                    output = output + [out];
                case 'version:
                    out = "ColdMUD Version " + ($sys.version());
                    out = $string.center(out, 79);
                    output = output + [out];
            }
        }
        args = delete(args, 1);
    }
    return output;
.

method set_motd
    arg what, value;
    
    .perms(sender());
    if (!(what in (.parameters())))
        throw(~motd, (toliteral(what) + " is not a valid motd parameter, try one of: ") + toliteral(.parameters()));
    if (!(type(value) in ['string, 'list]))
        throw(~motd, "Value must be sent as a string or a list of strings.");
    set_var(what, value);
.

method build_html
    arg [args];
    var output, out;
    
    output = [("<head><title>" + server_name) + "</title></head>", "<body>"];
    if (!args)
        args = ['name, 'title, 'quote, "", 'notes, 'admins, 'connected, 'version, 'help];
    while (args) {
        if (type(args[1]) == 'string) {
            output = output + ["<br>"];
        } else {
            switch (args[1]) {
                case 'title:
                    output = output + ["<h3>", @server_title, "</h3>"];
                case 'name:
                    //                  output = output + ["<h1>" + server_name + "</h1>"];
                    output = output + ["<img src=\"http://sticky.usu.edu/~brandon/tCD.gif\" alt=\"The Cold Dark\">"];
                case 'notes:
                    output = (output + notes) + ["<br>"];
                case 'quote:
                    output = output + ["<tt>", @$code.random_quote(), "</tt>"];
                case 'admins:
                    out = $list.to_english($list.map($sys.admins(), 'namef));
                    output = output + [("Administrators: " + out) + "<br>"];
                case 'connected:
                    out = "<a href=\"/bin/who\">Currently Connected users</a>: ";
                    out = out + tostr(listlen($user_db.connected()));
                    output = output + [out + "<br>"];
                case 'version:
                    out = "<a href=\"http://www.declab.usu.edu:8080/ColdMUD/\">ColdMUD</a> Version " + ($list.to_string(version(), "."));
                    output = output + [out + "<br>"];
                case 'help:
                    out = "</center><hr width=50% align=center><center>Click <a href=\"telnet://recumbent.declab.usu.edu:1138\"><b>here</b></a> to enter <a href=\"telnet://recumbent.declab.usu.edu:1138\">the Cold Dark</a>.";
                    output = output + [out];
            }
        }
        args = delete(args, 1);
    }
    return ["<center>", @output, "</center>", "</body>"];
.

method server_name
    return server_name;
.

method server_title
    return server_title;
.

parent #12
object #1408

var 1 child_index 0
var 1 fertile 0
var 1 manager #1408
var 1 owners [#1408]
var 1 writable [#1408, #47]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 1 inited 1
var 1 dbref 'buffer

method to_list
    arg buf;
    var idx, list;
    
    list = [];
    for idx in [1 .. buffer_len(buf)]
        list = list + [buffer_retrieve(buf, idx)];
    return list;
.

method from_list
    arg list;
    var buf, x;
    
    buf = `[];
    for x in [1 .. listlen(list)]
        buf = buffer_add(buf, list[x]);
    return buf;
.

parent #7801
object #7800

var 1 dbref 'login_interface
var 1 child_index 0
var 1 fertile 0
var 1 manager #37
var 1 owned []
var 1 owners [#37]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 16 commands [["@quit|QUIT", 'quit_cmd], ["h?elp", 'quit_cmd], ["@who|WHO", 'quit_cmd], ["c?onnect guest *", 'quit_cmd], ["c?onnect *", 'quit_cmd], ["m?otd", 'quit_cmd]]
var 16 shortcuts []
var 1 inited 1

method connect_cmd
    arg com, words;
    var words, u, password, salt, syn, name, passwd, line;
    
    (> .perms(sender(), 'this) <);
    
    //
    syn = "`connect <name> <pass>' (last word is taken as the password)";
    
    // parse name / password
    words = explode(words);
    if (listlen(words) < 2)
        $parse.tell_error(syn);
    passwd = words[listlen(words)];
    name = $list.to_string(sublist(words, 1, listlen(words) - 1));
    
    // find name in the db
    catch ~namenf {
        user = $user_db.find(name);
    } with handler {
        line = "Either that user does not exist or has a different password.";
        $parse.tell_error(line, syn);
    }
    
    // validate password
    if (!(user.check_password(passwd))) {
        line = "Either that user does not exist or has a different password.";
        $parse.tell_error(line, syn);
    }
    
    // change connection objects
    connection.change_interface_object(user);
    user.connection_logged_in(addr, port);
    
    // this is redundant, as .change_interface_object will shut us down
    .close();
.

method create_cmd
    arg com, words;
    var words, syn;
    
    syn = "!  Usage: `create <name> <password> <email@host>'";
    if (sender() != this())
        throw(~perm, "Sender is not this.");
    
    // Get user name, password, and email.
    words = explode(words);
    if (listlen(words) != 3)
        return .tell(syn);
    
    // Create a new user object.
    catch any {
        user = $sys.create_user(words[1], words[2], words[3]);
    } with handler {
        .tell(syn);
        switch (error()) {
            case ~duplicate:
                .tell(("!  The user " + toliteral(words[1])) + " already exists.");
            default:
                .tell("!  There was a problem creating you:");
                .tell("!  => " + ((traceback()[1])[2]));
                .tell("!  If there is a problem contact: " + ($sys.get_system_email('login)));
    
                // $sys.log(traceback());
        }
        if (user) {
            (| user.destroy() |);
            user = 0;
        }
        return;
    }
    
    // Log the user in.
    user.connection_logged_in(addr, port);
.

method quit_cmd
    arg dummy;
    
    if (sender() != this())
        throw(~perm, "Sender is not this.");
    .tell("Goodbye.");
    disconnect();
.

method connect_guest_cmd
    arg com, com2, words;
    var syn, email, name, result;
    
    .perms(sender(), 'this);
    syn = "=> Syntax: 'connect guest <name> <email>' (type 'help' for more help)";
    
    // Get user name and password.
    words = explode(words);
    if (listlen(words) < 2)
        return .tell(syn);
    name = $list.to_string(sublist(words, 1, listlen(words) - 1));
    email = words[listlen(words)];
    result = $code.valid_email(email);
    if ((result[1]) != 'valid) {
        switch (result[1]) {
            case 'invalid:
                .tell("!  The given email address is not a legitimate address.");
                .tell("!  Specify both username and hostname (do not use brackets).");
                return;
            case 'invip, 'invhostname:
                .echo($string.wrap_line(((("The hostname \"" + (result[3])) + "\" is invalid, when in actuality you are connecting from \"") + ((addr == "-1") ? ip | addr)) + "\".  The server is not currently locking out invalid email addresses, although your connection has been noted (We do realize that some hosts may not function normally).", 79, "!  ", 1));
                $channels.announce('System, ((((((("Invalid Connection Email: " + email) + " <") + addr) + ":") + ip) + "> (") + name) + ")");
        }
    }
    catch any {
        user = $sys.create_user(name, 0, email, 'anonymous_class);
    } with handler {
        .tell(syn);
        switch (error()) {
            case ~duplicate:
                .tell(("!  The name " + toliteral(words[1])) + " is already in use.");
            default:
                .tell("!  There was a problem creating you:");
                .tell("!  => " + ((traceback()[1])[2]));
                .tell("!  If there is a problem contact: " + ($sys.get_system_email('login)));
        }
        $brandon.tell_traceback(traceback());
    
        // $sys.log(traceback());
        return;
    }
    
    // Log the user in.
    $sys.log((("GUEST: " + (words[1])) + " ") + (words[2]));
    user.connection_logged_in(addr, port);
.

method who_cmd
    arg com;
    var l;
    
    for l in ($code.generate_listing($user_db.connected()))
        .tell(l);
.

method help_cmd
    arg com;
    var l;
    
    .perms(sender(), 'this);
    for l in ($login_interface.connect_help())
        .tell(l);
.

parent #7248
object #185

var 1 child_index 5
var 1 owners [#936]
var 1 fertile 1
var 15 verbs #[]
var 23 location #21
var 1 inited 1
var 185 disk_text ""
var 184 seperator 0
var 1 owned []
var 1179 gender #1182
var 23 obvious 1
var 17 prose #[]
var 1 manager #185
var 1 writable [#185]
var 1 readable ['methods, 'code]
var 1 dbref 'disk_readable
var 2787 name ['uniq, "Generic Disk Readable Object"]
var 2787 name_aliases []
var 1032 text []
var 7261 public ['readable]

method read_cmd
    arg [args];
    var actor;
    
    actor = sender();
    actor.tell(.description(actor, 'namef));
    actor.tell(.seperator());
    actor.echo_file(disk_text);
.

method init_disk_readable
    if (caller() != $root)
        throw(~perm, "Caller is not $root");
    disk_text = "";
.

method set_disk_text
    arg filename;
    
    if (!(.is_writable_by(sender())))
        throw(~perm, "Sender not an owner");
    disk_text = filename;
.

parent #7248
object #592

var 1 child_index 0
var 1 owners [#936]
var 1 fertile 0
var 15 verbs #[]
var 23 location #140
var 184 seperator 0
var 1 inited 1
var 1 owned []
var 592 last_write_time 771406285
var 592 readers #[[#37, 784587776], [#9197, 784220792], [#7275, 784587686], [#9499, 784435106], [#9507, 784436408], [#9555, 784477535], [#2277, 784529497], [#9039, 784536040], [#9663, 784597987]]
var 1179 gender #1182
var 23 obvious 1
var 17 prose #[['short, ["The latest comments from your local admins (woo, are we devoted or what).  Last written on at: %time."]]]
var 1 manager #592
var 1 writable [#592]
var 1 readable ['methods, 'code]
var 1 dbref 'news
var 2787 name ['uniq, "News"]
var 2787 name_aliases ["news"]
var 1032 text ["There is a Cold Dark mailing list.  Subscribe/Unsubscribe to it by sending a message to 'tcd-request@tiny.mcs.usu.edu' with a mail body of 'subscribe' or 'unsubscribe'.  Send to the list via 'tcd@tiny.mcs.usu.edu'."]
var 7261 public ['readable]

method read_vrb
    arg [args];
    
    pass(@args);
    readers = dict_add(readers, sender(), time());
.

method write_cmd
    arg [args];
    
    pass(@args);
    last_write_time = time();
.

method new
    // returns true if the sender has not read recent news
    // first see if they have even read the news
    if (!(sender() in dict_keys(readers)))
        return 1;
    if ((readers[sender()]) < last_write_time)
        return 1;
    return 0;
.

method short_description
    arg [args];
    var text, x;
    
    text = pass(@args);
    for x in [1 .. listlen(text)]
        text = replace(text, x, strsub(text[x], "%time", $time.ldate(last_write_time)));
    return text;
.

method validate_readers
    var x, new;
    
    .perms(sender(), 'system);
    new = #[];
    for x in (readers) {
        if (valid(x[1]))
            new = dict_add(new, x[1], x[2]);
    }
    readers = new;
.

method prose
    arg [args];
    var prose, x, lines;
    
    prose = (> pass(@args) <);
    if (type(prose) == 'dictionary)
        lines = (| prose['short] |);
    else
        lines = prose;
    if (lines) {
        for x in [1 .. listlen(lines)]
            lines = replace(lines, x, strsub(lines[x], "%time", $time.date(last_write_time)));
    }
    if (type(prose) == 'dictionary)
        return dict_add(prose, 'short, lines);
    else
        return lines;
.

method last_updated_on
    arg type;
    
    switch (type) {
        case 'string:
            return $time.date(last_write_time);
        case 'integer:
            return last_write_time;
    }
.

parent #24
parent #15
object #9552

var 1 dbref 'slate
var 1 child_index 0
var 1 fertile 0
var 1 manager #37
var 1 owned []
var 1 owners [#37]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 1 inited 1
var 9552 connection 0
var 9552 remote_host ""
var 9552 remote_port 0
var 9552 request_method ""
var 9552 received_text []
var 15 verbs #[]
var 23 location #21
var 23 obvious 1
var 1178 messages #[]
var 17 prose #[]
var 1179 gender #1182
var 2787 name ['uniq, "Generic Slate"]
var 2787 name_aliases []

method init_slate
    (> .perms(caller(), $root) <);
    connection = 0;
    remote_host = "";
    remote_port = 0;
    request_method = "";
    received_text = [];
.

method uninit_slate
    (> .perms(caller(), $root) <);
    connection = 0;
    remote_host = "";
    remote_port = 0;
    request_method = "";
    received_text = [];
.

method received_text
    (> .perms(sender(), 'this) <);
    return received_text;
.

method connection
    (> .perms(sender(), 'this) <);
    return connection;
.

method remote_host
    (> .perms(sender(), 'this) <);
    return remote_host;
.

method remote_port
    (> .perms(sender(), 'this) <);
    return remote_port;
.

method "request_method;"
    (> .perms(sender(), 'this) <);
    return request_method;
.

method send
    arg line;
    
    (> .perms(sender(), 'this) <);
    connection.send(line);
.

method connection_ending
.

parent #1162
object #747

var 1 child_index 0
var 1 owners [#936]
var 1 owned []
var 1 fertile 0
var 16 commands [["save", 'save_cmd]]
var 16 shortcuts []
var 1 inited 1
var 922 command_aliases []
var 1 manager #747
var 1 writable [#747]
var 1 readable ['parameters, 'methods, 'code]
var 1 dbref 'note_editor

method start_editing
    arg what;
    var obj, text;
    
    // called by $user_input.edit_cmd
    obj = (| sender().match_environment(what) |);
    if ((!obj) || (!(| obj.writeable_by(sender()) |))) {
        sender().tell(("I don't see a note around here called " + what) + " that you can edit.");
        return 0;
    }
    catch any {
        text = sender().run_with_users_perms(obj, 'text);
    } with handler {
        sender().tell(("You cannot edit " + what) + ".");
        sender().tell("Error: " + ((traceback()[1])[2]));
        return 0;
    }
    sender().tell(("Now editing " + what) + ".");
    
    // user doing editing, obj edited, text, current line number, changes made
    return #[['user, sender()], ['obj, obj], ['text, text], ['cur_line, 1], ['changed, 0]];
.

method help_msg
    var msg;
    
    msg = [];
    msg = msg + ["The note editor allows you to write on notes interactively."];
    msg = msg + ["It includes these commands it inherits from the generic editor:"];
    msg = msg + pass();
    msg = msg + [""];
    msg = msg + ["And adds the following:"];
    msg = msg + ["  save         store text to note"];
    msg = msg + [""];
    return msg;
.

method save_cmd
    arg editing, cmd;
    var error;
    
    .perms(sender(), 'parser);
    catch any {
        (editing['user]).run_with_users_perms(editing['obj], 'erase_cmd, "", "all", "", "");
        (editing['user]).run_with_users_perms(editing['obj], 'add_text, editing['text], $user);
        (editing['user]).tell("Done.");
    
        // clear modified flag
        editing = $dict.replace(editing, 'changed, 0);
    } with handler {
        (editing['user]).tell("An error occurred attempting to save.");
        (editing['user]).tell("The error was " + ((traceback()[1])[2]));
    }
    return editing;
.

parent #2485
object #2491

var 1 child_index 0
var 1 fertile 0
var 1 manager #2491
var 1 owners [#936]
var 1 writable [#2491]
var 1 readable ['parameters, 'methods, 'code]
var 1 trusted []
var 1 owned []
var 1 inited 1
var 1 dbref 'not

method unparse
    arg notlist;
    
    catch any {
        catch ~type, ~methodnf {
            return "!" + ((notlist[1]).unparse());
        } with handler {
            return "!" + tostr(notlist[1]);
        }
    } with handler {
        return "!()";
    }
.

method test
    arg notlist, [args];
    var val;
    
    catch ~range {
        catch ~type, ~methodnf {
            return !((notlist[1]).test(@args));
        } with handler {
            return !(notlist[1]);
        }
    } with handler {
        return 1;
    }
.

parent #7801
object #7811

var 1 dbref 'finger_interface
var 1 child_index 98
var 1 fertile 1
var 1 manager #37
var 1 owned []
var 1 owners [#37]
var 1 writable []
var 1 readable ['parameters, 'methods, 'code]
var 16 commands [["help", 'help_cmd], ["uptime", 'uptime_cmd], ["all", 'all_cmd], ["who", 'who_cmd], ["*", 'unknown_cmd]]
var 16 shortcuts []
var 1 inited 1
var 7801 connection #7856

method parse_line
    arg line;
    var cmd;
    
    while (line && ((line[1]) == " "))
        line = substr(line, 2);
    if (!line) {
        .motd();
    } else if ((line[1]) == ".") {
        line = substr(line, 2);
    
        //    if (!line) {
        //        .send("Unknown option, try \".help\".");
        //    } else {
        cmd = .match_command(line);
        if (cmd)
            .(cmd[1])(@cmd[2]);
    
        //    }
    } else {
        .send(.finger_user(line));
    }
    return 'disconnect;
.

method motd
    .perms(sender(), 'this);
    .send($login.build('default));
    .send($string.center("Email: " + ($sys.get_system_email('finger)), 79));
    .send($string.center("For more information, finger .help", 79));
.

method finger_user
    arg str;
    var user, line, lines, idle, desc;
    
    .perms(sender(), 'this);
    user = (| $user_db.find(str) |);
    if (!user)
        return [("Sorry, no user found by the name of \"" + str) + "\", try \".help\"."];
    line = pad(" Name:        " + (user.namef()), 37);
    line = (line + " In real life: ") + (user.data_on('real_name));
    lines = [line];
    line = " Last Login: ";
    if (user.connected()) {
        if ((user.idle_seconds()) > 10) {
            idle = ", " + ($time.dhms(user.idle_seconds(), 'long));
            idle = idle + " idle.";
        } else {
            idle = "";
        }
        line = " On since:    " + ($time.ltime(user.connected_at()));
        line = (line + " (Mountain)") + idle;
    } else {
        line = " Last Login:  " + ctime(user.last_command_at());
    }
    lines = [@lines, line];
    line = user.display_data('real_name, 'affiliation, 'position, 'location);
    lines = [@lines, @line];
    desc = $list.to_string(user.prose('short));
    if (strlen(desc) < 60) {
        lines = [@lines, " Description: " + desc];
    } else {
        lines = [@lines, " Description:"];
        desc = $string.wrap_line(desc, 79, "    ");
        desc = replace(desc, 1, "    " + (desc[1]));
        lines = [@lines, @desc];
    }
    return lines;
.

method help_cmd
    arg cmd;
    
    .send("If you are trying to find a user, do not prepend \".\".");
    .send(["", "Options available:", ""]);
    .send("     .all      Show all users connected.");
    .send("     .uptime   Uptime other server information");
    .send(["", "If there are any problems, please email " + ($sys.email('fingerd)), ""]);
.

method uptime_cmd
    arg cmd;
    var line;
    
    line = $time.elapsed($sys.uptime(), 'long);
    .send("Server has been up for: " + line);
    .send("Currently Connected users: " + tostr(listlen($user_db.connected())));
    .send("ColdMUD Version " + ($list.to_string(version(), ".")));
.

method all_cmd
    arg cmd;
    var x, line;
    
    (> .perms(sender(), 'this) <);
    
    // .send($code.generate_listing($user_db.connected()));
    .send(pad("USER", 40) + "TIME  (IDLE)     LOCATION");
    for x in ($user_db.connected()) {
        line = pad(x.namef('titled), 40);
        line = line + pad(x.time_poll(), 17);
        line = line + (x.realm_name());
        .send(line);
    }
.

method unknown_cmd
    arg cmd;
    
    .send(("Unknown command \"" + cmd) + "\", try \".help\".");
.

method who_cmd
    arg cmd;
    
    (> .perms(sender(), 'this) <);
    .send($code.generate_listing($user_db.connected()));
.