+Log in as ``admin`` creating an account and then an avatar and
+awaken it. Try out the :command:`help` command and make sure you see
+some command words in red (you're using a color terminal, right?)
+since those are admin-only commands and being able to see them
+confirms you're an administrator. When you're ready to terminate the
+service you can either give the :command:`halt` command in your MUD
+client terminal or press the ``control`` and ``c`` keys together in
+the terminal where you ran tox. To exit the tf5 MUD client, give it
+the :command:`/quit` command.
+
+miscellanea
+-----------
+
+This section is a collection of various coding-related discussions
+and treatises, mostly here because there's not a better place, and
+so they don't get lost in random E-mail threads.
+
+avatar names
+~~~~~~~~~~~~
+
+It comes up fairly often, so bears mentioning, **there is no
+assumption avatar names will be globally unique**. This is part of
+the reason the default :code:`choose_name` menu just runs
+:func:`mudpy.misc.random_name`, to make impersonation a bit harder.
+The idea is to make sure to be able to support realistic settings
+where multiple people are often given the same names and don't
+really have much choice as to what their parents decided to name
+them at birth, but can still choose a name they like later (perhaps
+through some cultural rite of passage quest, attaining a particular
+guild rank, or just through a command they're allowed to run as soon
+as they awaken that avatar for the first time).
+
+It may be possible to force globally-unique avatar names, but the
+need to treat avatars similarly to non-player characters (actors
+which aren't associated with an account and may be driven by
+scripted routines instead) means it may also be desirable to prevent
+a user from choosing an avatar name which duplicates the name of any
+existing actor (whether or not that actor is a user's avatar). This
+would entail scanning the full dataset to identify actors with
+similar names so they could be rejected or excluded for a new
+avatar, but then raises the question as to what to do when some new
+content adds NPCs with a name which is already in use.
+
+The best way to side-step this challenge is to not rely on avatar
+names for programmatic interaction and instead reference the
+corresponding ID for an avatar's element in the universe contents.
+IDs **are** already guaranteed to be globally unique, so there is no
+ambiguity when using them (an avatar's element ID is constructed
+from the owning account name plus an index integer). Exactly what
+variables you have to work from will depend on the context where
+your hypothetical routine is called.
+
+Taking as an example, let's say what you want is to be able to have
+an area's owner permit a specific avatar to pass through the portals
+(doorways, gates, whatever) which connect it to other areas. This is
+similar to how *guild houses* work in some classical MUDs. Here's
+how I'd go about implementing it:
+
+1. Extend the area element to have two new facets: *owners* (type
+ list) and *visitors* (type list). The first will contain
+ references to the element IDs for the avatars who are allowed to
+ alter the entries of both lists, while the second will be the
+ element IDs for avatars who are allowed to enter the area (maybe
+ also allow owners to enter an area so they don't need to be
+ duplicated in both lists).
+
+2. Implement a command which allows someone to see the corresponding
+ ID for an element (alternatively make it an acquirable ability,
+ skill, spell, item, or however finding that information would
+ best fit into your setting). This is stored in the element's
+ :code:`.key` attribute, and you can play around with it on the
+ command line with :command:`show result` like this::
+
+ > look
+ Center Sample Location
+ This is the Center Sample Location. It is merely provided as an
+ example of what an area might look like.
+ [ Exits: down, east, north, south, up, west ]
+ A sample prop sits here.
+ Utso is here.
+
+ > show result [
+ a.key.split('_', 1)[1]
+ for a in actor.universe.contents[
+ actor.get('location')
+ ].contents.values()
+ if a.key.startswith('actor.avatar_')
+ and a.get('name') == 'Utso'
+ ][0]
+
+ 'luser0_0'
+
+ [Put the command on one line, It's merely wrapped here for
+ readability.] In short, this list comprehension takes the
+ internal IDs for elements present in the calling actor's current
+ location, filtered by whether they're avatars and a specific
+ actor name, then splits the group and prefix off (relying on the
+ fact that it uses ``_`` as a prefix separator) and returns the
+ first result. In a non-prototype implementation, the command
+ would probably include a routine which looked something like:
+
+ .. code-block:: python
+
+ location_id = actor.get("location")
+ also_here = actor.universe.contents[location_id].contents
+ for who in also_here.values():
+ if (who.key.startswith("actor.avatar_")
+ and who.get("name") == parameters[0]:
+ message += "Avatar ID: %s" % .key.split("_", 1)[1]
+ break
+
+ That's a rough approximation, and not terribly immersive, but
+ hopefully you get the idea. We could also improve the element
+ attributes with pre-populated backlink references for some of
+ these relationships to reduce code complexity.
+
+3. Implement a command which allows a user to add and remove entries
+ in the owners and visitors lists for their current location,
+ which takes this avatar ID as a parameter.
+
+4. Hook in the :meth:`mudpy.misc.Element.go_to` method to test the
+ owners and visitors lists for the area parameter to make sure
+ self is in one of those lists. Probably also stick in an override
+ to make sure that if the actor's owner account is flagged as
+ administrative then they're also allowed even if they're not on
+ the allowed list.
+
+The resulting workflow this would enable is that after an avatar *A*
+has been set as an owner for area *X* (perhaps by an admin or a
+world builder), *A* when in another area *Y* at the same time as
+some avatar *B* whom they would like to be allowed to visit *X*
+could run the identification command from part #2 above, then they
+would later travel to *X* and run the safe passage command from part
+#3 adding *B* to the visitors list for *X*. After that, *B* is able
+freely enter *X* until *A* runs a similar command to remove them
+from the visitors list for *X* again.
+
+To tackle the immersion problem, an optional substitution cipher
+could be implemented to (reversibly) turn those IDs into something
+more mystical-looking. Also the identification command (or ability,
+skill, spell, tool, whatever) could be limited to only work when the
+area you're running it in is flagged a certain way. Taking this
+concept further, all sorts of elements could have access lists for
+which avatars own them and which avatars are allowed to interact
+with them (in which case maybe the term *visitor* for the latter is
+too area-specific and it needs a slightly more general term?).
+
+However, a far more immersive solution would be to get closable and
+lockable elements (and inventory management) implemented, have a
+means of crafting keys which unlock specific elements, and then when
+creating an area you want to restrict to specific avatars, put
+locked doors for all its portals and give keys for them to anyone
+you want to be able to visit. Or implement non-avatar actors, then
+create guards you can hire or summon or construct to police your
+doorways and check whether visitors are on a list. That list itself
+could even be a piece of paper or a book (a prop), created with
+appropriate materials and some skill which allows the actor to write
+and edit paper notes, given to the guard and held by it as an
+inventory item.
+
+custom commands
+~~~~~~~~~~~~~~~
+
+Command definitions are split into metadata and procedure. The
+metadata needs to be in an element like the basic ones shipped in
+the :file:`share/command.yaml` file, and then a handler function
+added to the :mod:`mudpy.command` module. There's not yet a plugin
+layer to allow those to be added to a separate module. The function
+name needs to match the element base name, or you have to add an
+action facet to the element indicating the name of the function you
+want it to call; the ``command.set`` element has an example of this,
+so that we avoid shadowing Python's built-in :func:`set` function
+and call :func:`mudpy.command.c_set` instead.
+
+The :meth:`mudpy.misc.Element.set` method takes two parameters, the
+name of the facet and the value to pass into it. An example of it in
+action is :meth:`mudpy.misc.User.authenticate` where the user's
+*administrator* facet is set to the value *True* if their username
+is in the ``.mudpy.limit.admins`` list used to bootstrap
+administrators:
+
+.. code-block:: python
+ :emphasize-lines: 9
+
+ def authenticate(self):
+ """Flag the user as authenticated and disconnect duplicates."""
+ if self.state != "authenticated":
+ self.authenticated = True
+ log("User %s authenticated for account %s." % (
+ self, self.account.subkey), 2)
+ if ("mudpy.limit" in universe.contents and self.account.subkey in
+ universe.contents["mudpy.limit"].get("admins")):
+ self.account.set("administrator", True)
+ log("Account %s is an administrator." % (
+ self.account.subkey), 2)