You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
454 lines
22 KiB
454 lines
22 KiB
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<% include ../partials/head %>
|
|
</head>
|
|
<body class="container">
|
|
|
|
<header>
|
|
<% include ../partials/header %>
|
|
</header>
|
|
|
|
<main>
|
|
<div class="row">
|
|
<div class="col-sm-8">
|
|
<div class="jumbotron">
|
|
<h1>EnlivenMinetest</h1>
|
|
<p>Modding.</p>
|
|
<h2> <!--result--></h2>
|
|
<p><%= msg %></p>
|
|
</div>
|
|
<div>
|
|
<h2>Resources</h2>
|
|
<ul>
|
|
<li><a href="https://git.minetest.org/minetest/minetest/src/branch/master/doc/lua_api.txt">doc/lua_api.txt</a> on minetest.org (drastically improved over the original github version)</li>
|
|
</ul>
|
|
|
|
<h2>Tips</h2>
|
|
* In singleplayer, you have the `privs` privilege. You can give yourself
|
|
all privileges by typing: "/grant singleplayer all" (The same can be
|
|
done with your own username if you are hosting a world). You can use
|
|
"/giveme itemname quantity" where quantity is optional and itemname
|
|
can be found by pushing question mark at the bottom of inventory (i)
|
|
then clicking the item on the crafting guide on the right (see also
|
|
"Common Items for Moderators to Spawn" further down.
|
|
* You can test small pieces of code using the "Run Lua" and "Formspec
|
|
Tester" features of the CoderEdit or WorldEdit GUI if you have the
|
|
privilege.
|
|
|
|
<h2>Introduction</h2>
|
|
<p>There are other modding books out there, but they often just rehash
|
|
the documentation of Minetest without explaining much. The Modding
|
|
section of the ENLIVEN Getting Started guide is here to help explain
|
|
some of the assumptions and jargon.
|
|
</p>
|
|
<p>Modding is easy in Minetest, because it is designed to be modded.
|
|
The Minetest client downloads the "game" (collection of mods and
|
|
modpacks) each time you connect to a server, so you don't have to
|
|
install anything yourself. Automatic "game" downloading also means that
|
|
each server can be very different, but load quickly, offering you many
|
|
experiences to try easily.</p>
|
|
<p>Anyone can make a "game" using Minetest by
|
|
writing mods or combining existing mods. Most "games" are based on
|
|
games that are included in the Minetest/games directory--however, some
|
|
games that differ drastically in gameplay can be made if one heavily
|
|
edits or replaces mods that provide core functionality. Must of
|
|
Minetest's core functionality is written in Lua.
|
|
</p>
|
|
<p>Examples are a good way to get started. Since mods are scripted in
|
|
Lua, every mod is open source. Almost every one is released under
|
|
some sort of public license as well, which usually allows you to modify,
|
|
reuse, and redistribute the code (usually under the condition that you
|
|
credit the original author). <i>Some joke licenses exist but DO NOT
|
|
protect your work in cases where they explicitly allow others to copy
|
|
your work and claim it as their own especially if modified it in any
|
|
way--they would just be doing what you said they could do.</i></p>
|
|
<p>The license file sometimes has no file
|
|
extension, so you may have to pick a program to open it in Windows.
|
|
You can open it (or any other text file) in Notepad. However, Geany
|
|
is recommended since there is more than one undo step. For Lua
|
|
programming, you can install ZeroBrane Studio (which is free) then
|
|
install
|
|
"<a href="https://github.com/poikilos/MinetestIDE">MinetestIDE</a>"
|
|
which patches ZeroBrane Studio to provide code completion
|
|
(a form of autocomplete with API usage tips for coding).
|
|
</p>
|
|
<p>Every mod, at minimum, must have a file called init.lua. You
|
|
should also add a description.txt describing it, a README.md or other
|
|
readme file explaining more, and a LICENSE.md or other license file.
|
|
The MIT License is used for Minetest itself, so that is recommended.
|
|
Some people determine that using GPL v3 can prevent the program from
|
|
being used on popular mobile devices, since the GPL v3 specifies that a
|
|
user must be able to not only reprogram but also replace the program
|
|
with their recompiled version--this may not be possible if your version
|
|
shares a namespace and key with the application you are changing, and
|
|
you may not have the same connectivity or functionality without using
|
|
the same key. Therefore, components or mods using GPL v3 may prevent
|
|
their inclusion into future version of Minetest "games", as several
|
|
versions of Minetest (often by other names) are on Google Play and the
|
|
iOS App Store.
|
|
You can find the MIT License online and paste it into Notepad or Geany.
|
|
Be sure to fill
|
|
in your name and the year you created the mod. Having a license will
|
|
make sure others know they are legally safe using, changing, and
|
|
redistributing your mod if that's what you tell them in the license.
|
|
Having others change and improve your mod will help you too, because
|
|
all Lua is open source (is distributed in plain text form not compiled
|
|
form normally) and you can normally utilize others' improvements if you
|
|
pick a good license as suggested.
|
|
</p>
|
|
<h2>Debugging Errors</h2>
|
|
<p>If you have an error or Minetest crashes when your mod is enabled,
|
|
try looking at minetest/bin/debug.txt (in $HOME/minetest/bin/debug.txt
|
|
if installed using EnlivenMinetest installer for GNU+Linux systems,
|
|
but usually in C:\games\minetest\bin\debug.txt if using Windows)</p>
|
|
<p>Using the Minetest API and other mods with APIs. Try reading the
|
|
last few lines of the file. Use Geany or ZeroBrane (above)
|
|
instead of Notepad, as Notepad may crash or mangle text when using
|
|
large files. You can also use <a href="https://notepad-plus-plus.org/">
|
|
Notepad++</a>.
|
|
</p>
|
|
<p><i>Delete or rename the debug.txt file by the current date (with
|
|
Minetest closed) every so often so it doesn't get too long.</i></p>
|
|
<p>
|
|
API stands for application programming interface. It is just the set of
|
|
classes and/or functions you use to change the behavior of an existing
|
|
program such as Minetest. Mods that add significant features, such as
|
|
Mobs Redo or codermobs, usually have their own API. You can see all of
|
|
the functions in the api.lua file if the author has followed naming
|
|
conventions and placed public features there. In addition, many mods
|
|
have a api.txt or similarly named files. You can start by opening up
|
|
your minetest directory on your computer (after installing or otherwise
|
|
installing Minetest) and doing a search for api, or just open the
|
|
following files depending on what you want to do:
|
|
</p>
|
|
<ul>
|
|
<li>minetest/doc/menu_lua_api.txt</li>
|
|
<li>minetest/doc/fst_api.txt</li>
|
|
<li>minetest/doc/lua_api.txt</li>
|
|
<li>minetest/doc/client_lua_api.txt</li>
|
|
<li>minetest/games/Bucket_Game/mods/codercore/areas/api.md</li>
|
|
<li>minetest/games/Bucket_Game/mods/codercore/craft_guide/api_craft_guide.lua</li>
|
|
<li>minetest/games/Bucket_Game/mods/codermobs/mobs/api_new.txt</li>
|
|
<li>minetest/games/Bucket_Game/mods/codermobs/mobs/api.txt</li>
|
|
<li>minetest/games/Bucket_Game/mods/coderbuild/hopper/api.txt</li>
|
|
<li>minetest/games/Bucket_Game/mods/coderbuild/magmatools/textures/magmatools_tool_magmapick.png</li>
|
|
<li>minetest/games/Bucket_Game/mods/coderbuild/castle/castle_gates/api.txt</li>
|
|
<li>minetest/games/Bucket_Game/mods/coderbuild/ambience/api.txt</li>
|
|
<li>minetest/games/Bucket_Game/mods/coderbuild/bonemeal/api.txt</li>
|
|
<li>minetest/games/Bucket_Game/mods/coderbuild/flowerpot/api.md</li>
|
|
<li>minetest/games/Bucket_Game/mods/coderfood/farming/api.txt</li>
|
|
</ul>
|
|
<p>
|
|
Remember, you can always look at examples as well. You can find a mod
|
|
that does something similar to what you want, looking at all of the .lua
|
|
files in a mod like that may help.
|
|
</p>
|
|
<p>Knowing the Lua language well means you can make more advanced mods.
|
|
Even if you know the API perfectly, you still need to understand both
|
|
programming concepts and the Lua language to do well. If you don't yet
|
|
know any languages, a software development concepts course on YouTube or
|
|
in book or formal education will help you greatly, Lua or not. If you
|
|
already know programming concepts, here are some Lua caveats that can
|
|
help you get started:
|
|
<ul>
|
|
<li>Everything other than primitive value types are tables. Tables
|
|
are what all other languages call associative arrays or dictionaries.</li>
|
|
<li>The concatenation operator (for adding strings together) is <code>..</code></li>
|
|
<li>You can send self as the first param for function automatically
|
|
using <code>obj:do_something</code> instead of
|
|
<code>obj.do_something</code>. This is helpful for functions used as
|
|
object methods, which make use of the <code>self</code>
|
|
variable.</li>
|
|
<li>Arrays start at 1 (unless you forcefully set a 0 or negative index). You must start the array at one for array functions to work. Prefilled arrays start at 1, and use curly braces: <code>things = {"something", "something else"}</code>.</li>
|
|
<li><code>#</code> is the length operator.
|
|
<code>if #minetest.find_nodes_in_area(pos0, pos1, "group:flora") > 3 then</code>
|
|
is legitimate code: it will cause the case to happen if the count of
|
|
flora nodes in the 3D box is greater than 3.</li>
|
|
<li>Though Lua guides will tell you there is no ternary operator,
|
|
and that is technically true, you can do a ternary operation as
|
|
follows:
|
|
<code>local gender = texture_name:find("_female") and "female" or "male"</code>
|
|
The code sets gender to either "female" or "male".</li>
|
|
<li>0 is true in Lua, but nil is false. This behavior is helpful when checking whether a setting is present:
|
|
<code>local radius = (tonumber(minetest.setting_get("protector_radius")) or 5)</code>
|
|
The code allows a zero value.</li>
|
|
<li>Lua's tostring method does not have an underscore, and is a global function</li>
|
|
<li>Lua can represent an object as a unique hash using tostring (for
|
|
an example, see owner of arrow projectile object in mobs redo), but
|
|
trying to append an object to a string will result in a fatal "not
|
|
serializeable" error</li>
|
|
<li>For-loops use a "do" keyword: <code>for i=-5, 5 do</code></li>
|
|
<li>Clauses (such as if, else and for) end with <code>end</code></li>
|
|
</ul>
|
|
Minetest Lua functions unrelated to the engine's functionality:
|
|
<ul>
|
|
<li><code>dump</code> can convert a table to a string (a list of methods of an object, usually)</li>
|
|
</ul>
|
|
</p>
|
|
<h2>Changing Existing Mods</h2>
|
|
<p>A public license allows you to change and rerelease the mod,
|
|
in addition to just being "open source." Many
|
|
mods are on GitHub, GitLab, or notabug.org to allow easy
|
|
forking. Forking is when someone other than the project owner
|
|
makes improvements or fixes (often forking implies keeping it separate
|
|
and not having your changes pulled in to the project owner's version).
|
|
If the changes
|
|
are applicable to everyone, you would usually fork it by clicking "fork"
|
|
which allows you to download your own copy of the mod with "GitHub
|
|
Desktop" for GitHub on Windows or a public licensed program like "Git
|
|
Cola." Then you would make or paste in your changes, go back to the
|
|
program and stage all tracked and untracked changes (not required on
|
|
GitHub Desktop), name the commit, click commit, then click push. Then
|
|
you can go back to the repository online where you got the mod and click
|
|
"pull request" comparing across forks to the "head" from your
|
|
repository, allowing the owner to "accept" the request or comment on
|
|
changes you need to make or regretfully decline. Usually pull requests
|
|
are preceeded by discussion, often at an issue on the issue tracker.
|
|
Unless you are fixing something, you likely will have to present
|
|
something the project owner already wants or is trivial but helpful.
|
|
If the owner declines,
|
|
you can always keep your repository and use and distribute your version
|
|
of the mod if the license allows that. In some cases, you can instead
|
|
just make a mod that overrides an existing mod--that would require
|
|
putting the mod in depends.txt, clearing crafting recipes, and other
|
|
similar steps--see <a href="https://github.com/poikilos/homedecor_ua">
|
|
github.com/poikilos/homedecor_ua</a> for an example.
|
|
</p>
|
|
<h2>Craftitems and Nodes</h2>
|
|
A node is drawn as a block, 3d mesh, or other drawtype and
|
|
is placeable. A craftitem can't be placed, so the only way to get rid
|
|
of it is to drop it, and like other things dropped it will become a
|
|
floating sprite waiting to be picked up by clicking. There are also
|
|
other types of entities in Minetest such as mobs and particles.
|
|
All items that aren't nodes are called craftitems even if they aren't
|
|
used in recipes. You can use the name of a node or craftitem when
|
|
defining a crafting recipe. However, you must depend on the mod being
|
|
used to ensure that it is loaded before your mod, if the item comes
|
|
from a different mod. You can depend on another mod by adding its name
|
|
to the depends.txt file in your mod.
|
|
<h2>Mobs</h2>
|
|
Creating passive or hostile Non-Player Characters or Enemy Characters
|
|
requires a mob api such as Simple Mobs, Mobs Redo, or codermobs
|
|
which share anestry in that order. Codermobs is included in Bucket_Game
|
|
and hence new versions of ENLIVEN. Some other mob frameworks include:
|
|
mobf, Jordan4Ibanez' OpenAI, and others.
|
|
<h3>Codermobs</h3>
|
|
Bucket_Game (the basis for ENLIVEN) has codermobs as the modding
|
|
framework. It is a general purpose API based on Mobs Redo but with
|
|
additional features and fixes. If you want to test your mob or do
|
|
performance testing, you can spawn one or more mobs with one command:
|
|
<pre>
|
|
"/se" (or "/spawnentity") now supports all of the following modes.
|
|
This feature will show up in the next snapshot. For now, you can see
|
|
it working in the online copy of Wonder World.
|
|
|
|
/se Ent
|
|
/se Ent Num
|
|
/se Ent Pos
|
|
/se Ent Pos Num
|
|
/se Ent Num Pos
|
|
|
|
For example: /se codermobs:badger 5
|
|
|
|
The Num parameter is presently limited to 10. The limit may be increased
|
|
or decreased at a later date.
|
|
|
|
Note: Spaces are permitted, though optional, before or after commas in
|
|
positions.
|
|
|
|
</pre>
|
|
<p style="text-align:right; width=100%">-OldCoder</p>
|
|
<h4>Making Mob Models</h4>
|
|
<h6>How to Use Blender</h6>
|
|
<p>Many Blender tutorials exist on YouTube. However, they usually go
|
|
into painful detail about consfusing options that do not help beginners,
|
|
which are the audience of tutorials in the first place. To offset this
|
|
lack of Blender information, I created a course for when I was teaching
|
|
Blender. These free and public-licensed
|
|
<a href="http://expertmultimedia.com/usingblender/resources/?dir=Blender%202.5-2.7">
|
|
Tutorials are here</a> (that is the Blender 2.5-2.7 directory--for 2.8,
|
|
click "Index" at the top). To install Blender and the B3D exporter for
|
|
Minetest, see "<a href="one-time-setup-3d-modeling">One-time Setup for 3D Modeling</a>" below.</p>
|
|
<h5>Scale</h5>
|
|
<p>10 Blender units is 1 Minetest unit, so if your creature should be
|
|
1.6 meters tall (5 ft 3 in), then the model should be 16 Blender units
|
|
tall.
|
|
<ul>
|
|
<li>The <code>visual_size</code> specifies size for 2D sprites such as wielditem, in
|
|
Minetest units (default 1 x 1 is 1 meter square).</li>
|
|
<li>The <code>visual_size</code> specifies scale for meshes. For
|
|
example: The mummy from tsm_pyramids is about 2 Blender units (also same
|
|
for b3view), the
|
|
<code>visual_size</code> in Lua is 8, result is looks like it is the
|
|
expected 1.6 Minetest units high. 1.6 is the expected result since the 2
|
|
Blender units are divided by 10 resulting in .2--multiplied by
|
|
<code>visual_size</code> 8 results in 1.6 Minetest units.</li>
|
|
</ul>
|
|
</p>
|
|
<h5><a name="one-time-setup-3d-modeling"></a>One-time Setup for 3D Modeling</h5>
|
|
<ol>
|
|
<li>Install Blender 2.79 from <a href=https://blender.org">
|
|
blender.org</a> (or 2.8 if you don't need to export b3d).</li>
|
|
<li>If using Blender 2.79, set it to left click select (like most
|
|
programs, and Blender 2.8):
|
|
<ol>
|
|
<li>Open Blender</li>
|
|
<li>Click "File," "User Preferences."</li>
|
|
<li>Click the "Input" tab.</li>
|
|
<li>Change "Select With" to "Left."</li>
|
|
<li>Click "Save User Settings," then press x on the "Blender
|
|
User Preferences" window.</li>
|
|
</ol>
|
|
</li>
|
|
<li>If using Blender 2.79, install the B3D plugin. You can get a
|
|
version for minetest that does not export the texture path with the
|
|
model, reducing useless missing texture warnings in the debug log in
|
|
some versions of minetest (click Save not open, so you can find it
|
|
in Downloads later):<br/>
|
|
<a href="https://github.com/minetest/B3DExport/archive/master.zip">
|
|
Download</a>
|
|
<ol>
|
|
<li>Open Blender</li>
|
|
<li>Click "File," "User Preferences."</li>
|
|
<li>Click the "Add-ons" tab.</li>
|
|
<li>Click "Install Add-on from File..."</li>
|
|
<li>Choose the "B3DExport-master.zip" (or other B3D export
|
|
plugin if not the one above) that you downloaded.</li>
|
|
<li>Search for "B3D"</li>
|
|
<li>If the "Import-Export: B3D (BLITZ3D) Model Exporter" box
|
|
is not checked, click it and wait for it to become checked
|
|
(clicking again will just cancel the enable add-on
|
|
operation).</li>
|
|
<li>Click "Save User Settings," then press x on the "Blender
|
|
User Preferences" window.</li>
|
|
</ol>
|
|
</li>
|
|
<li>OPTIONAL: If you need to import x files into Blender, repeat the
|
|
steps above for github.com/limemidolin/directX_blender (2.79 fork of
|
|
littleneo's DirectX Exporter):<br/>
|
|
<a href="https://github.com/limemidolin/directX_blender/archive/master.zip">Download</a></li>
|
|
</ol>
|
|
<h5>Export</h5>
|
|
Minetest modding because 2.8 does not yet have a good b3d exporter, and
|
|
b3d format is the preferred (most efficient) format for animated
|
|
models. If you are creating static (<b>non</b>-animated) models, you can
|
|
use Blender 2.8 then export to any model format supported by Irrlicht
|
|
(Usually 3ds, obj, are good static formats--Irrlicht also supports other
|
|
common formats such as ms3d and md3; uncommon formats; and x for
|
|
animated 3D models but x is not as efficient in size as b3d).</p>
|
|
<h2>Sounds</h2>
|
|
<p>Sounds must be mono if you want 3D positional audio, such as for
|
|
mob sounds (see
|
|
"<a href="http://irrlicht.sourceforge.net/forum/viewtopic.php?f=1&t=30371">irrKlang
|
|
3d Sound Position</a>" on the Irrlicht forum, and "The Modding Book").
|
|
</p>
|
|
<h2>Creating New Ores</h2>
|
|
Creating new ores or other blocks may be confusing after you learn the
|
|
API. If you want about 48 blocks before you find another cluster of
|
|
your ore, then the clust_scarcity should be 48*48*48 since the game is
|
|
3D. The chance of finding a cluster is 1 out of the clust_scarcity
|
|
number. The cluster size (clust_size) only affects the size of the
|
|
"vein" (though technically there are multiple shapes of clusters allowed
|
|
and vein is not recommended since it is hundreds of times slower).
|
|
Minetest uses the generic term cluster to refer to all patterns of ore
|
|
deposits. The number of ores in the cluster is determined by
|
|
clust_num_ores. If your clust_size is 3, then that would be a 3*3*3
|
|
cube (but you just specify 3, not 27 there) and the maximum number of
|
|
ores you could set for clust_num_ores is 27, though that is not
|
|
recommended because then the person would find a 3*3*3 area that is
|
|
completely ore (that would give the person 27 ore each time they found
|
|
a cluster). Generally, the ore is a node (drawn as a block) and the gem
|
|
or metal is a craftitem (drawn as a sprite). You normally should set the
|
|
drop of the ore to a separate craftitem (however, if it is something
|
|
you have to smelt such as a metal, you could drop the ore node, then
|
|
provide a "cooking" crafting recipe to get the metal).</p>
|
|
<p>the absheight option should only be used for ores that should appear
|
|
in mountains. It forces an ore that occurs in a negative range to also
|
|
appear in the corresponding positive range. Another confusing parameter
|
|
of the register_ore function is y_min.
|
|
Most programmers are more concerned with y_max, which is how deep a
|
|
player must dig to have a chance of mining the ore.
|
|
y_min is the value below which the
|
|
ore stops. Sometimes people set this to a very low number that normally
|
|
won't be reached, such as -31000. This number may be useful for certain
|
|
cases where an ore shouldn't occur below a certain point, such as amber
|
|
(all nodes generated in this way are called ores in Minetest even if
|
|
they are not technically a metal or mineral ore and even if they
|
|
cannot be smelted nor drop a mineral--they still use the
|
|
minetest.register_ore function).</p>
|
|
|
|
<h2>Appendices</h2>
|
|
<h3>Common Errors</h3>
|
|
<p class="lead"><samp color="darkred">ERROR[Server]: LuaEntity name
|
|
"creatures:chicken" not defined</samp></p>
|
|
<p>If you have the error above, you have removed a mod or customized a
|
|
creature so it has a different name.</p>
|
|
<p>To convert the mob to some other mob, try something like:<br/>
|
|
<code>mobs:alias_mob("creatures:chicken", "codermobs:chicken")</code><br/>
|
|
If you have an unknown node (you see blocks in the game that say
|
|
"unknown node" on them), you may need an additional mod to support
|
|
your world. If you removed a mod on purpose or a node was renamed in a
|
|
later version (see nftools example below), you can use Minetest's
|
|
builtin alias function to make a mod to convert the nodes:<br/>
|
|
<code>minetest.register_alias("name", "convert_to")</code><br/>
|
|
Example content for init.lua:<br/>
|
|
<code>minetest.register_alias("nftools:aquamarine_ore", "nftools:stone_with_turquoise")</code><br/>
|
|
In that case, your depends.txt must contain one line:<br/>
|
|
<code>nftools</code><br/>
|
|
</p>
|
|
<p>The alias function may be confusing: You are registering the alias
|
|
parameter 1 for parameter 2, which means that you are defining parameter
|
|
1 as an alias--not a real item--but another name for convert_to. When
|
|
the world is saved, only convert_to will be saved. If you are sure that
|
|
all of the world was loaded that contained the problematic nodes
|
|
(players visited all of those areas) then you can remove your
|
|
transitional mod.</p>
|
|
<h3>Common Items for Moderators to Spawn</h3>
|
|
(list of item names for /giveme itemname)
|
|
<pre>
|
|
glass
|
|
default:obsidian_glass
|
|
moreblocks:wood_tile
|
|
technic:concrete
|
|
stairs:stair_desert_stonebrick
|
|
stairs:stair_wood
|
|
stairs:stair_goldblock
|
|
stairs:stair_lapis_brick
|
|
|
|
mossycobble lapis:lapis_brick
|
|
|
|
mesecons_lightstone:lightstone_red_off
|
|
mesecons_torch:mesecon_torch_on
|
|
wool:white
|
|
technic:stainless_steel_block
|
|
|
|
lapis:base_lazurite_block
|
|
|
|
#white seams:
|
|
lapis:column_lazurite_brick
|
|
lapis:base_lazurite_brick
|
|
|
|
#subtle seams:
|
|
lapis:column_lapis_brick
|
|
lapis:base_lapis_brick
|
|
|
|
lapis:base_lapis_block
|
|
lapis:column_lapis_block
|
|
default:fence_aspen_wood
|
|
</pre><h3>Historical Resources</h3>
|
|
(may only apply to minetest.net (same as GitHub.com/minetest) releases which have a heavily changed API without backward compatibility)
|
|
<ul>
|
|
<li><a href="https://rubenwardy.com/minetest_modding_book/en/index.html">The Minetest Modding Book</a> on rubenwardy.com</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<footer>
|
|
<% include ../partials/footer %>
|
|
</footer>
|
|
|
|
</body>
|
|
</html>
|
|
|