1998Q4/
<!-- MHonArc v2.4.4 -->
<!--X-Subject: [MUD&#45;Dev] MUD Design doc (long) -->
<!--X-From-R13: Fuvahf Pneaneq <guvahf_oneaneqNovtsbbg.pbz> -->
<!--X-Date: Fri, 11 Dec 1998 01:29:08 &#45;0800 -->
<!--X-Message-Id: 3670E890.5465DAA#bigfoot,com -->
<!--X-Content-Type: text/plain -->
<!--X-Head-End-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<html>
<head>
<title>MUD-Dev message, [MUD-Dev] MUD Design doc (long)</title>
<!-- meta name="robots" content="noindex,nofollow" -->
<link rev="made" href="mailto:thinus_barnard#bigfoot,com">
</head>
<body background="/backgrounds/paperback.gif" bgcolor="#ffffff"
      text="#000000" link="#0000FF" alink="#FF0000" vlink="#006000">

  <font size="+4" color="#804040">
    <strong><em>MUD-Dev<br>mailing list archive</em></strong>
  </font>
      
<br>
[&nbsp;<a href="../">Other Periods</a>
&nbsp;|&nbsp;<a href="../../">Other mailing lists</a>
&nbsp;|&nbsp;<a href="/search.php3">Search</a>
&nbsp;]
<br clear=all><hr>
<!--X-Body-Begin-->
<!--X-User-Header-->
<!--X-User-Header-End-->
<!--X-TopPNI-->

Date:&nbsp;
[&nbsp;<a href="msg00948.html">Previous</a>
&nbsp;|&nbsp;<a href="msg00950.html">Next</a>
&nbsp;]
&nbsp;&nbsp;&nbsp;&nbsp;
Thread:&nbsp;
[&nbsp;<a href="msg00951.html">Previous</a>
&nbsp;|&nbsp;<a href="msg00936.html">Next</a>
&nbsp;]
&nbsp;&nbsp;&nbsp;&nbsp;
Index:&nbsp;
[&nbsp;<A HREF="author.html#00949">Author</A>
&nbsp;|&nbsp;<A HREF="#00949">Date</A>
&nbsp;|&nbsp;<A HREF="thread.html#00949">Thread</A>
&nbsp;]

<!--X-TopPNI-End-->
<!--X-MsgBody-->
<!--X-Subject-Header-Begin-->
<H1>[MUD-Dev] MUD Design doc (long)</H1>
<HR>
<!--X-Subject-Header-End-->
<!--X-Head-of-Message-->
<UL>
<LI><em>To</em>: MUD-Dev &lt;<A HREF="mailto:mud-dev#kanga,nu">mud-dev#kanga,nu</A>&gt;</LI>
<LI><em>Subject</em>: [MUD-Dev] MUD Design doc (long)</LI>
<LI><em>From</em>: Thinus Barnard &lt;<A HREF="mailto:thinus_barnard#bigfoot,com">thinus_barnard#bigfoot,com</A>&gt;</LI>
<LI><em>Date</em>: Fri, 11 Dec 1998 11:40:32 +0200</LI>
<LI><em>Reply-To</em>: <A HREF="mailto:mud-dev#kanga,nu">mud-dev#kanga,nu</A></LI>
</UL>
<!--X-Head-of-Message-End-->
<!--X-Head-Body-Sep-Begin-->
<HR>
<!--X-Head-Body-Sep-End-->
<!--X-Body-of-Message-->
<PRE>
Hi,

Here is a design doc I am writing for my MUD. If anyone has such
documents I would love to see it. Maybe some of these docs can be
published on the MUD-Dev web site..? I find design documents very
instructive and much more understandable than source code. I hope this
doc helps someone.

Cheers
Thinus

-----------------------------------------

GATES OF MYTH AND MYSTERY - Design details

1. GENERAL OBJECTIVES - What I want to do.

1.1 FOREWORD - Meaningless chatter.
I am writing this document mainly for myself but hope that it might
prove useful and give some insight into the design and logic of MUDs in
general. I will try to explain all the issues I had to deal with in a
clear and easy to understand way. This document will probably never be
finished as improvements and new features will be added all the time.


1.2 OVERVIEW - Whatever.
I have never liked the idea of coders and builders and administrators
that cannot play in a mud so I set out to create a world that would be
fun to play, create and maintain. I also dislike level/experience based
systems. This will be an attempt to create a pure skill based system.


1.3 ADMINISTRATORS - Targets of hatred and groveling.
The administrators will be presented as gods. Gods will have a certain
amount of religion points. They can use these points to affect the world

in several ways. The only way a god can regain religion points is when
characters sacrifice objects to the god or from donations from other
gods. If a god spends points to help a character who encountered a bug
the god can demand sacrifices from the coders/builders responsible for
the bug. Players will be able to use a pray command to pray to a
specific god or to all gods. Gods have no physical presence, if a god
wants to have a physical presence he will have to possess a creature.
There will be several types of possession to represent the amount of
freedom the possessed creature still has. Possession will not be limited

to gods. There will probably be a NPC god too. This god will have
certain rules for answering prayers. It will be very expensive to get a
prayer answered from this god. This god is needed for when no other gods

are connected.


1.4 CODERS - The people that do all the cool stuff.
All players in the world can be coders. Coding can only be done in a
dream chamber. Every god will have at least one dream chamber. A player
can then write the code and create the object to test it. When the
player is satisfied with the object he can pray to have his dream come
true. The god can then demand a suitable sacrifice before creating the
object (creation will cost religion points). All objects will be
measured in terms of religion points. If a player has a piece of nifty
code or a cool idea to expand the game the player could be rewarded with

any objects the god finds fitting.


1.5 BUILDING - I want to create a vorpal banana of god slaying.
Building can also be done in a dream chamber. If a player has enough
money to sacrifice he can create a whole area with NPCs and other
objects.


1.6 CHARACTERS - The living.
All players and NPCs are characters. All commands available to players
will also be available to NPCs except for OOC commands like "who",
"quit", etc.


1.7 NPCs - The living dead.
NPCs will be controlled by an AI system. Each NPC will have a loyalty
character and a loyalty rating. If offered enough money and if its
loyalty rating is low enough the NPC might change loyalties. NPCs can be

loyal to themselves. NPCs can be hired to perform simple tasks like
guarding, attacking, training, following, etc. If the loyalty rating is
high enough the NPC will perform the task for free.


1.8 PLAYERS - The living living.
Players are free to do what they choose. The main objectives will
probably be to build your own domain, to become a specialist in certain
skills or to become a god (there will be ways).


1.9 THE LINK-DEAD PLAYER - The living living dead.
All characters in the mud are going to exist all the time. If you log
off or go link dead your character will be moved to the half-life
vaults. These vaults will be well hidden. When the character re-connects

the character will be moved to the last location. There will be ways to
enter the vault. When a character is in the half-life state the
character can not be killed. Some magic spells might still have an
effect. The character can be searched for items though. So if someone
finds the entrance to the vault he can rob the half-life bodies. A
player will be able to change his half-life location. If a player has
enough money and some good guards and locks they can create their own
half-life vault.

1.10 DEATH - Oops, did I just step on your village?
When a character dies the character will automatically drop all items
carried. The character will be moved to the halls of the dead. A prayer
will bring the character back to life and move it to a temple. The god
will demand sacrifices though. The gods will keep tabs on sacrifices
owed and when a character is deep in debt the gods can ask the character

to perform certain tasks, like newbie duty. If a newbie keeps dying the
gods can be merciful and give the newbie some instructions and
assistance.


1.11 SHOPS - Adventurer heads for sale at dragon keep.
A shop will only have limited supplies. The shopkeepers should encourage

characters to sell their items to them so that they will have a running
supply of stock. If you kill the shopkeeper you can take all the items
being sold in the shop. A shop will usually have a trader with good
trading skills and a guard or two with good fighting skills. Remember
that the guards can be bribed.

1.12 CLOSING - Blah, blah.
I would like to keep the mud as open as possible, give the players as
much freedom as possible (and the NPCs too). Most muds are controlled by

impossibilities, things like unkillable NPCs, unbreakable doors,
unusable items or skills/spells, unpickable locks, etc. In this world no

one and nothing is safe. Even the gods are vulnerable (yes, the gods can

be slain, there will be ways, oh yes, there will be ways). The mud will
strive not to introduce any impossibilities into the game. Some people
will argue that limiting the player to a fixed set of commands is
already introducing impossibilities. This has some merit as a player
wont be able to break branches off a tree and make his own bow, etc. So
what exactly is my objective? As I see it the game defines certain
rules. These rules are implemented by a command set. The commands in the

command set should be as flexible as possible. If I type in 'kill table'

the reply should not be 'You cannot kill table'. An acceptable reply is
'Table is not alive and cannot be killed' or 'You whack the table a few
times and are pretty sure the table has moved on to greener pastures'. I

think where the problems originate is that coders just look at a
player's stats and then prevents the player from doing certain things.
To me this is a big no-no. If you want to prevent a player from doing
something you will have to place a guard or a decent lock, and a lock
can be picked and a guard can be killed. So the code will never include
a statement where certain players are allowed to do something and other
players are prevented from doing it. What this means is that all player
affecting must be done through existing game mechanics. If you want to
prevent someone going through a door get a high level mage to embed a
few powerful lightning spells on the door and to supply you with a way
to bypass the spell.
Ok, that's the idea. Let's design.




2. DESIGN - Groovy baby.


2.1 INTRODUCTION - Hi, I'm your mugger, my name is Rob U. Blind.
I will handle the design by first describing a few systems. These
systems will handle all aspects of the game.


2.2 THE WORLD SYSTEM - I'm a systematic girl in a systematic world.
I hesitate to use the word 'world' because it immediately brings up a
picture of a rotating earth in my mind. I should rather call it universe

but for ease of use I will keep it world. The world contains everything
in the MUD. Let us look at how we can represent earth in a mud. First we

have earth (assume that the mud is limited to earth, no space travel).
Earth contains everything. We can sub divide earth into continents and
oceans. For all intents and purposes they are the same things except
that one has land and the other water. We can sub divide the continents
again into lands. The lands into several locations. Each of these
locations will be a room in normal mud terms. In these locations we will

find certain objects (humans, animals, trees, houses, tables, etc.) Some

of these objects, a bag for instance, can contain even more objects.
This forms a nice tree structure with earth the root and at the top. It
is even possible to plug space traveling into this. We just make earth
not the root anymore but a node in the universe tree. My world structure

will work like this. All objects will have 3 pointers. One pointer will
point to the parent, one to the next sibling and one to the first child.

The root object will have null pointers for the parent and for the next
sibling. If you want more information see any text on tree structures.

2.2.1 POINTERS VS INDEX - Does the index disappoint?
The problem with pointers are that they change if you shutdown the mud
and run it again. If you save the 3 pointers with the objects they will
not be valid when you load the library after a shutdown. To bypass this
we give each object a number instead. The tree will be linked by
numbers. The number the object is given will always stay the same. When
an object is completely removed from the game we have to make the number

available for use again. It would be a pity if the mud ran for a few
years and suddenly crashed when we create object number 4,294,967,296.
If you have this many objects in the mud then you will have to change
the numbers to 64 bit and run a little conversion thingy on all the
objects.

2.2.2 CONTAINERS - Stuff it.
Everything in the world is contained within something else. Can we use
this for moving stuff around? Partially. If we have a bag and we have a
cat inside it, the cat will have the bag as a parent. If we want to let
the cat out of the bag we simply add the cat as a child of the bag's
parent. Does that sentence make any sense? Let me clear it up a little.
We have object A - a room, B - a bag, C - a cat. B has A as a parent and

C has B as a parent. To move C out of B we add C as a child of A. Now C
and B will be siblings and they are both children of A, and the cat is
out of the bag. This seems to work quite cool. We have to do some
bookkeeping on the tree to indicate the change but other than that the
procedure is easy.
The problem is room exits. Rooms hardly ever has an exit that leads to
its parent. First step in solving this is to implement a default
movement method. Here is how it works:
In every object we have a get_move method that takes the direction as a
parameter and returns the number of the new parent.
The default get_move method will return the number of the parent.
For rooms we override the get_move method. The new get_move method will
compare the direction parameter with the directions known to it and
return the number if it finds a match otherwise it will return its own
number. To add an exit to a room we will have another method that takes
the direction and destination room number as parameters and adds the
exit to the room object's exit list.
This just might work. The only problem is to identify objects in such a
way that the coders don't have to use numbers to link rooms together. We

also have to take the dream chamber concept into consideration. An
identifier field should do the trick, we just have to check for
uniqueness of the field and then the builder can give his room a unique
name to access it by.


2.3 THE SKILL SYSTEM - Strangle dragon failed? Why?
The mud will not implement levels, exp, stats like strength and
dexterity or classes. There can be only skills. Skills will also be a
tree. An overall skill rating will be the root of the tree. On the first

level of the tree will be the normal stats we are used to like strength,

agility, constitution, mental ability (for spells), etc. Underneath for
instance strength we will have a skill combat. Underneath combat we can
have unarmed, swords, axes, etc. Underneath unarmed we can have
punching, kicking and wrestling. Every character will have a skill tree
of his own to keep track of the different values obtained in the
different skills. Note that the character does not need a complete skill

tree. The character just needs the branches in which the character has a

skill value. If you use a skill the value of the parent should have an
influence. Yes, yes, but what about shooting a bow, doesn't it use
strength and agility? Ok, put a link in the bow shooting skill to
strength. Compare the structure I described here with the structure of
the world system. Well slap me silly, it seems to be exactly the same
type of structure. A normal tree except that some nodes must be linked
to completely different parts of the tree. Hmmmmmm. Maybe we should make

a nice generic structure and fit all the other systems into it too.


2.4 THE COMMAND HANDLER - Command 'klli draghn' not recognized.
If we look at the way commands are handled we have to start at the
keyboard. The player types a command and the command is received by the
networking module of the mud. The networking module now passes the
command together with the player that issued the command to the command
handler. The command handler now has to try and find the command
somewhere. Where to start? First the command handler has to check if the

player has that command defined on the player object. Then the command
handler has to check if the command is defined on any object the player
is carrying. Then the command handler has to check if the location the
player is in defines the command and then finally the command handler
has to check the standard command set for the command. If no such
command is found the command handler informs the player, otherwise the
method associated with the command is called to perform the required
action. It is very important to decide on the scope allowed to commands.

All commands in the standard command set can be executed anytime,
anywhere. This has to be taken into consideration when designing the
command set. Custom commands embedded in objects presents a few
problems. Here are a few examples of the route of a command illustrating

the problem areas:

P1  - player 1
P2  - player 2
O1  - object 1
O2  - object 2
O11 - object 11
O22 - object 22
L1  - location 1
L2  - location 2

P1 is carrying O1 and P2 is carrying O2. P1 and P2 are in L1. L1 is in
L2 (just say L1 is a cage and L2 a normal room). O1 contains O11 and O2
contains O22. L2 is contained in the world object.

Ex 1
P1 issues a command that is only defined in the default command set.
P1 tries to handle the command and fails
P1 calls O1 to handle the command (in the inventory of P1)
  O1 fails to handle the command (O1 should NOT call O11)
P1 calls L1 to handle the command
  L1 fails to handle the command and calls P2 to handle it (P2 is also
inside L1)
    P2 fails to handle the command (P2 should NOT call O2)
P1 calls the default command handler

Example 1 does not make provision for 1 feature I would like to add to
my world. Consider my world tree, let's say that on the first level of
the tree we have several continents. I assign builders to each of these
continents. One of the continents develops a command they want to
implement but this command is only relevant in their continent. To
implement it using the command handling illustrated in ex 1 will be
messy. If I could change the command handling so that the command is
passed to every parent until the command is handled or the root object
is reached it should be easy to implement area specific commands.
Another example:

Ex 2
P1 issues a command that is defined in L2
P1 tries to handle the command and fails
P1 calls O1 to handle the command (in the inventory of P1)
  O1 fails to handle the command (O1 should NOT call O11)
P1 now PASSES the command to L1

L1 tries to handle the command and fails
L1 calls P2 to handle the command (P2 in L1)
  P2 fails to handle the command (P2 should NOT call O2)
L1 PASSES the command to L2
L2 handles the command and returns success.

If L2 failed to handle the command it would have been passed to the
parent of L2 which is the world object. The default command set will be
defined in the world object. Note how easy it will be to put another
node between L2 and the world object. The command will be passed from L2

to the new node and then on to the root. Also note that if we join the
world with a space traveling world the command handling will not stop at

the root, it will be passed on to the universe root. The more I think
about the possibilities the more I drool. But first we have another
wrinkle that needs to be ironed out. Imagine L2 has a bell. If we are in

L2 and we type 'ring bell' then the bell rings (and you have to buy a
round for everyone). If we are in L1 and we type 'ring bell' the command

will eventually be passed to L2 and the bell will ring. Oops. I'm locked

inside a cage but I can still ring the bell on the table. We just have
to add a flag that indicates if it is a global or a local command.
Global commands are available to the sub-tree of which the object
containing the command is the root.

To see the commands in action here are methods required:
handle_command(command, command_src) no return value
handle_global(command, command_src) return true or false
handle_local(command, command_src) return true or false
handle_static(command, command_src) return true or false

handle_command
This is the default command handler. Whenever a command is generated
this method will be called in the object that generated the command.
When an object fails to handle a command it will call the handle_command

method of its parent.
The first thing handle_command does is call handle_global. If
handle_global fails then handle_command checks if this object is the
same one as command_src. If it is then it will call the handle_static of

its first child. If it is not it will check if command_src is one of its

children. If it is it will call handle_static of its first child.
If the command has not been handled call the handle_command of the
parent.

handle_global
Will just check the commands with a global flag defined on this object,
call the method associated with the command if found and return true,
otherwise return false.

handle_local
Same as handle_global but checks commands with local flag.

handle_static
This will call the handle_global, if it fails it will call handle_local.

If handle_local fails it will check if it has a sibling. If it has a
sibling it will call handle_static of the sibling.
If the command has not been handled return false otherwise true.


2.5 TIMING - I want it all! I want it all! And I want it now!
We need a queue to store all the commands the system has to process
together with a time of when to process it. We need this so that 3 pages

of combat doesn't scroll past at blinding speed with the last line
reading 'Welcome to Green Pasture. Home for the livingly challenged.'
Whenever a command is generated that must happen at a certain time a
timer object should be created. The timer object must have a trigger
function, a requested time and maybe a parameter or two for the trigger
function. The timer object is then added to the queue. The queue will
not really be a standard queue but a queue sorted on requested time. The

world will keep comparing the current time with the requested time of
the first object in the queue. If the current time is equal to or later
than the requested time the timer object is triggered and removed from
the queue. Simple, isn't it? Will probably hit the snags come
implementation.





TO DO - Lazy slob.
World specific details. Stuff like day/night, weather, visibility, etc.
PK, RP and PG (as if enough hasn't been said already). Specific design
details about structures, classes and some OOP stuff. The THEME!!! I
have a theme in progress, some basic ideas but no real mind crunching
done on the subject. Basically a theme to give IC explanations for OOC
commands. In other words rational explanations for commands like who,
finger, etc. Rational in a fantasy sense.


ACRONYMICALLY CHALLENGED LIST - Why is abbreviation such a long word?
IC - In character
OOC - Out of character
PK - Player killer/killing
PG - Power gamer/gaming
RP - Role playing
NPC - Non-player character



FINALLY - This is the end, my only friend the end - The Doors
If there is anything you don't agree with or want more info about, mail
me (email address at end of doc). If you want to chat about your ideas
and designs, mail me. If you want to criticize or totally rip this
document apart and expose the gruesome flaws and pathetic reasoning,
mail me. If a butterfly flapped its wings and caused a ripple in the
pond of reality that slightly altered the direction a mouse was running
and forced your cat to jump at it which resulted in your cat landing in
the mud and now you have to bath it and you contemplate suicide as an
alternative, mail me (not recommended after criticizing me).




Thinus Barnard
<A  HREF="mailto:thinus_barnard#bigfoot,com">mailto:thinus_barnard#bigfoot,com</A>


</PRE>

<!--X-Body-of-Message-End-->
<!--X-MsgBody-End-->
<!--X-Follow-Ups-->
<HR>
<!--X-Follow-Ups-End-->
<!--X-References-->
<!--X-References-End-->
<!--X-BotPNI-->
<UL>
<LI>Prev by Date:
<STRONG><A HREF="msg00948.html">[MUD-Dev] Re: DIS: Client-Server vs Peer-to-Peer</A></STRONG>
</LI>
<LI>Next by Date:
<STRONG><A HREF="msg00950.html">[MUD-Dev] Re: DIS: Client-Server vs Peer-to-Peer</A></STRONG>
</LI>
<LI>Prev by thread:
<STRONG><A HREF="msg00951.html">[MUD-Dev] A short introduction of a (quite) long-time lurker</A></STRONG>
</LI>
<LI>Next by thread:
<STRONG><A HREF="msg00936.html">[MUD-Dev] ADMIN: (IMPORTNANT) Server down time and possible service interruption</A></STRONG>
</LI>
<LI>Index(es):
<UL>
<LI><A HREF="index.html#00949"><STRONG>Date</STRONG></A></LI>
<LI><A HREF="thread.html#00949"><STRONG>Thread</STRONG></A></LI>
</UL>
</LI>
</UL>

<!--X-BotPNI-End-->
<!--X-User-Footer-->
<!--X-User-Footer-End-->
<ul><li>Thread context:
<BLOCKQUOTE><UL>
<LI><STRONG>[MUD-Dev] Re: MUD Design doc (long)</STRONG>, <EM>(continued)</EM>
<ul compact>
<LI><strong><A NAME="01007" HREF="msg01007.html">[MUD-Dev] Re: MUD Design doc (long)</A></strong>, 
Benjamin D. Wiechel <a href="mailto:strycher#toast,net">strycher#toast,net</a>, Fri 18 Dec 1998, 23:38 GMT
<UL>
<LI><strong><A NAME="01031" HREF="msg01031.html">[MUD-Dev] Re: MUD Design doc (long)</A></strong>, 
J C Lawrence <a href="mailto:claw#under,engr.sgi.com">claw#under,engr.sgi.com</a>, Mon 21 Dec 1998, 23:34 GMT
</LI>
</UL>
</LI>
<LI><strong><A NAME="01048" HREF="msg01048.html">[MUD-Dev] Re: MUD Design doc (long)</A></strong>, 
Nathan F Yospe <a href="mailto:yospe#hawaii,edu">yospe#hawaii,edu</a>, Wed 23 Dec 1998, 20:11 GMT
</LI>
</ul>
</LI>
<LI><strong><A NAME="00951" HREF="msg00951.html">[MUD-Dev] A short introduction of a (quite) long-time lurker</A></strong>, 
Per Vognsen <a href="mailto:vognsen#post10,tele.dk">vognsen#post10,tele.dk</a>, Fri 11 Dec 1998, 16:39 GMT
<LI><strong><A NAME="00949" HREF="msg00949.html">[MUD-Dev] MUD Design doc (long)</A></strong>, 
Thinus Barnard <a href="mailto:thinus_barnard#bigfoot,com">thinus_barnard#bigfoot,com</a>, Fri 11 Dec 1998, 09:29 GMT
<LI><strong><A NAME="00936" HREF="msg00936.html">[MUD-Dev] ADMIN: (IMPORTNANT) Server down time and possible service interruption</A></strong>, 
J C Lawrence <a href="mailto:claw#under,engr.sgi.com">claw#under,engr.sgi.com</a>, Tue 08 Dec 1998, 01:56 GMT
<LI><strong><A NAME="00935" HREF="msg00935.html">[MUD-Dev] Error tolerant UDP data streams</A></strong>, 
J C Lawrence <a href="mailto:claw#under,engr.sgi.com">claw#under,engr.sgi.com</a>, Tue 08 Dec 1998, 01:40 GMT
<UL>
<LI><strong><A NAME="00938" HREF="msg00938.html">[MUD-Dev] Re: [DevMUD] Error tolerant UDP data streams</A></strong>, 
Darren Henderson <a href="mailto:darren#jasper,somtel.com">darren#jasper,somtel.com</a>, Tue 08 Dec 1998, 02:37 GMT
</LI>
<LI><strong><A NAME="00941" HREF="msg00941.html">[MUD-Dev] Re: Error tolerant UDP data streams</A></strong>, 
James Wilson <a href="mailto:jwilson#rochester,rr.com">jwilson#rochester,rr.com</a>, Tue 08 Dec 1998, 12:31 GMT
</LI>
</UL>
</LI>
</UL></BLOCKQUOTE>

</ul>
<hr>
<center>
[&nbsp;<a href="../">Other Periods</a>
&nbsp;|&nbsp;<a href="../../">Other mailing lists</a>
&nbsp;|&nbsp;<a href="/search.php3">Search</a>
&nbsp;]
</center>
<hr>
</body>
</html>