<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.secondlife.com/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Tano+Toll</id>
	<title>Second Life Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.secondlife.com/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Tano+Toll"/>
	<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/wiki/Special:Contributions/Tano_Toll"/>
	<updated>2026-07-27T01:34:53Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.42.1</generator>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:Tano_Toll&amp;diff=1199053</id>
		<title>User:Tano Toll</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:Tano_Toll&amp;diff=1199053"/>
		<updated>2016-02-05T13:11:01Z</updated>

		<summary type="html">&lt;p&gt;Tano Toll: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some of my work for the public domain:&lt;br /&gt;
&lt;br /&gt;
* [[TMCP]] - Tano&#039;s MLP Compatible Pose Scripts - poseball free drop-in replacement for MLPv2&lt;br /&gt;
&lt;br /&gt;
* [[ParcelChatRelay]] - Parcel Chat Relay efficiently allows parcel-wide channel0 talk&lt;br /&gt;
&lt;br /&gt;
* [[Stream_Music_In_PHP]] - Stream a static mp3 stream, synchronized for all listeners, using php&lt;br /&gt;
&lt;br /&gt;
* [[SimpleMLPStylingScript]] - Simple MLP/TMCP compatible styling script example.&lt;br /&gt;
&lt;br /&gt;
* [[User:Tano_Toll/LSL_Tips_and_tricks]] - Some tips and tricks&lt;/div&gt;</summary>
		<author><name>Tano Toll</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:Tano_Toll/LSL_Tips_and_tricks&amp;diff=1199052</id>
		<title>User:Tano Toll/LSL Tips and tricks</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:Tano_Toll/LSL_Tips_and_tricks&amp;diff=1199052"/>
		<updated>2016-02-05T12:47:17Z</updated>

		<summary type="html">&lt;p&gt;Tano Toll: some tips&amp;#039;n&amp;#039;tricks&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some common, or less common, LSL tips, tricks and `hacks` i&#039;d like to share.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Hack 1 : Use lists for typecasting to save bytes ==&lt;br /&gt;
&lt;br /&gt;
Problem example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lsl2&amp;quot;&amp;gt;&lt;br /&gt;
string s = &amp;quot;Amount: &amp;quot;+(string)amount+&amp;quot;L$ by avatar &amp;quot;+name+&amp;quot; with key &amp;quot;+(string)id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hacked solution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lsl2&amp;quot;&amp;gt;&lt;br /&gt;
string s = (string)[&amp;quot;Amount: &amp;quot;, amount, &amp;quot;L$ by avatar &amp;quot;,name,&amp;quot; with key &amp;quot;, id];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Explanation:&lt;br /&gt;
Typecasting a list to string will auto-typecast all elements in the list (without spacers). If you need spacers, you could use llDumpList2String(list, seperator)&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lsl2&amp;quot;&amp;gt;&lt;br /&gt;
llOwnerSay ((string)[&amp;quot;Free memory: &amp;quot;,llGetFreeMemory()]);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Justification: Only 1 typecast and a list declaration is needed, which saves bytes when you&#039;d have to do many typecasts. Also, it makes your code more readable.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Hack 2: Abuse sensor event to emulate a 2nd timer. ==&lt;br /&gt;
In need of a second and independant timer? Of course you can just multiplex your timer. But, if your script not uses llSensor() or llSensorRepeat() for anything else, you can abuse this as a second timer. Preferably do not use this for timers with a low interval as there is some overhead.&lt;br /&gt;
&lt;br /&gt;
How:&lt;br /&gt;
1. Set up an llSensorEvent() with an impossible combination&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lsl2&amp;quot;&amp;gt;&lt;br /&gt;
    llSensorRepeat (&amp;quot;noname&amp;quot;, &amp;quot;invalidkey&amp;quot;, AGENT|ACTIVE, 0.0, 0.0, 30.0);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
2. Use the no_sensor() event as alternate timer&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lsl2&amp;quot;&amp;gt;&lt;br /&gt;
    no_sensor() {&lt;br /&gt;
        llOwnerSay (&amp;quot;Timer 2&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
== Hack 3: Create a better PRNG ==&lt;br /&gt;
The pseudo random number generator available to LSL scripts is far from perfect.&lt;br /&gt;
A better -albeit slower- way of generating pseudo random numbers is to use llMD5String().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lsl2&amp;quot;&amp;gt;&lt;br /&gt;
string seed=&amp;quot;initvalue&amp;quot;;&lt;br /&gt;
integer rnd() {    &lt;br /&gt;
    seed = llMD5String (&amp;quot;Some constant&amp;quot; + seed, 0); //feed seed to itself. You can add more entropy if you like&lt;br /&gt;
    return (integer)(&amp;quot;0x&amp;quot;+llGetSubString(seed, 0, 6); //will return a positive integer 28-bits wide&lt;br /&gt;
    //or:&lt;br /&gt;
    //return (integer)(&amp;quot;0x&amp;quot;+llGetSubString(seed, 0, 7); //will return a signed integer 32-bits wide&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
imperfect usage example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lsl2&amp;quot;&amp;gt;&lt;br /&gt;
seed=&amp;quot;example&amp;quot;;&lt;br /&gt;
integer A = rnd() % 100; //A = 0..99&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hack 4: Use notecards without notecards ==&lt;br /&gt;
Not as much a hack, yet an unknown feature by many.&lt;br /&gt;
You want to use a configuration or data notecard, but not include a notecard in your product? Totally possible:&lt;br /&gt;
&lt;br /&gt;
  1. Create a notecard in your inventory and fill in the data&lt;br /&gt;
  2. Copy the UUID key of this notecard and paste it in your script as notecard name&lt;br /&gt;
  3. Your script can read the notecard as normal (as if it was a notecard in the object).&lt;br /&gt;
&lt;br /&gt;
Catch: If you change the contents of the notecard, the key will change!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Hack 5: Variable parameters ==&lt;br /&gt;
Yet again, just an overlooked feature.&lt;br /&gt;
Suppose you have a function, and you want it to accept various types as parameter. Much like &#039;overloaded&#039; functions in typed languages, or typeless functions.&lt;br /&gt;
&lt;br /&gt;
Answer: just use a list!&lt;br /&gt;
Example&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lsl2&amp;quot;&amp;gt;&lt;br /&gt;
print (list data) {&lt;br /&gt;
    llSay (0, llList2String(data,0));&lt;br /&gt;
}&lt;br /&gt;
print ([0]); //prints &#039;0&#039;&lt;br /&gt;
print ([1.0]); //prints &#039;1.00000000&#039;&lt;br /&gt;
print ([&amp;quot;I have a cow&amp;quot;]); //prints &#039;I have a cow&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Of course your function has to be type aware (or type-ignorant).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Hack 6: Formatting floats ==&lt;br /&gt;
a short way to imperfectly print floats. May be adequate for many cases.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lsl2&amp;quot;&amp;gt;&lt;br /&gt;
//format float to string&lt;br /&gt;
//by Tano Toll 2015 - public domain&lt;br /&gt;
&lt;br /&gt;
//note that this will work for most but not any values. still it serves my needs.&lt;br /&gt;
//fails very large numbers (&amp;gt; +- maxint) and for very small negative values of zero.&lt;br /&gt;
//so -0.9 will be mistranslated. so will 1e20&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//fixed precision (1 decimal after seperator):&lt;br /&gt;
string formatFloat (float value) {&lt;br /&gt;
    return llGetSubString((string) value, 0, llStringLength((string) ((integer) value))+1); //1 bit precision&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//arbitrary precision (N decimals after decimal seperator)&lt;br /&gt;
string formatFloat2 (float value, integer precision) {    &lt;br /&gt;
    return llGetSubString((string) value, 0, llStringLength((string) ((integer) value))+precision); //1 bit precision&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//example:&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llSay(0, (string) [formatFloat(PI),&amp;quot; &amp;quot;, formatFloat(-PI), &amp;quot; &amp;quot;, formatFloat2(-PI, 6), &amp;quot; &amp;quot;, formatFloat (-0.01), &amp;quot; &amp;quot;, &lt;br /&gt;
            formatFloat (-0.999999999999), &amp;quot; &amp;quot;, formatFloat (1e8), &amp;quot; &amp;quot;,formatFloat (1e9), &amp;quot; &amp;quot;,formatFloat (1e10), &amp;quot; &amp;quot;, &lt;br /&gt;
            formatFloat (-2e8), &amp;quot; &amp;quot;, formatFloat (-2e9), &amp;quot; &amp;quot;, formatFloat (-2e10), &amp;quot; &amp;quot;, formatFloat (-2e30), &amp;quot; &amp;quot;, formatFloat (1e-30)] );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--[[User:Tano Toll|Tano Toll]] ([[User talk:Tano Toll|talk]]) 04:47, 5 February 2016 (PST)&lt;/div&gt;</summary>
		<author><name>Tano Toll</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Pseudo-random_Number_Generator&amp;diff=1176857</id>
		<title>Pseudo-random Number Generator</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Pseudo-random_Number_Generator&amp;diff=1176857"/>
		<updated>2013-02-19T22:45:08Z</updated>

		<summary type="html">&lt;p&gt;Tano Toll: /* Seedable PRNG Based On MD5 Hashing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{LSL Header}}&lt;br /&gt;
&lt;br /&gt;
See also: [[llFrand]], [[llListRandomize]], [[Seedable_PRNG]]&lt;br /&gt;
&lt;br /&gt;
== Seedable PRNG Based On Multiply/ Add/ Overflow ==&lt;br /&gt;
&lt;br /&gt;
Here&#039;s a Pseudo-random Number Generator - I ([[User:Xaviar Czervik|Xaviar Czervik]]) just made it up off the top of my head - so it has no mathematical research behind it to prove it&#039;s random... I&#039;ve tested it for a while and it looks random to me, about the same as llFrand(). But what ever. Sue me. The main reason that I use it so that I can test scripts, and then when it blows up because of a math error, I can just run the script again an it will use the same numbers, in the same order. &lt;br /&gt;
&lt;br /&gt;
I use this for determining a random channel for two (or more) objects to talk on. This allows the scripts to talk without users being able to intercept the messages - and even if they do - then the channel will change in a minute or two - so no harm done.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// IMPORTANT: Change the following numbers before using!&lt;br /&gt;
integer seed1 = 0x053FA20C;&lt;br /&gt;
integer seed2 = 0x3B1264D5;&lt;br /&gt;
integer seed1Mod = 0x71B5F252;&lt;br /&gt;
integer seed2Mod = 0x56A0E61D;&lt;br /&gt;
&lt;br /&gt;
integer rand(integer spread) {&lt;br /&gt;
    	seed1 = (seed1 * seed1Mod + 0xB);&lt;br /&gt;
    	seed2 = (seed2 * seed2Mod + 0xB);&lt;br /&gt;
        seed2Mod = seed1Mod;&lt;br /&gt;
        seed1Mod = seed1 * seed2;&lt;br /&gt;
	return seed1Mod % spread;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
The below code is exactly the same as the above, only it is much faster. Thanks to Strife Onizuka.&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
integer rand(integer spread) {&lt;br /&gt;
    	seed2 = (seed2 * seed2Mod + 0xB);&lt;br /&gt;
	return (seed1Mod = ((seed1 = (seed1 * (seed2Mod = seed1Mod) + 0xB)) * seed2)) % spread;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
Example code to test the randomness (Is that a word?) of the generator.&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
default {&lt;br /&gt;
	state_entry() {&lt;br /&gt;
		integer i = 0;&lt;br /&gt;
		integer min = 0x7FFFFFFF;&lt;br /&gt;
		integer max = -0x7FFFFFFF;&lt;br /&gt;
		integer total = 0;&lt;br /&gt;
		while (i &amp;lt; 100000000) {&lt;br /&gt;
			integer r = rand(0x7FFFFFFF);&lt;br /&gt;
			if (r &amp;lt; min) {&lt;br /&gt;
				min = r;&lt;br /&gt;
			}&lt;br /&gt;
			if (r &amp;gt; max) {&lt;br /&gt;
				max = r;&lt;br /&gt;
			}&lt;br /&gt;
			total += r;&lt;br /&gt;
			i++;&lt;br /&gt;
		}&lt;br /&gt;
		llOwnerSay(&amp;quot;Min: &amp;quot; + (string)min);&lt;br /&gt;
		llOwnerSay(&amp;quot;Max: &amp;quot; + (string)max);&lt;br /&gt;
		llOwnerSay(&amp;quot;Average: &amp;quot; + (string)(total/100000000));&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: A pattern of digits like yyyymmddnn often works as a seed that changes often enough, &#039;&#039;e.g.&#039;&#039;, test with 2007090103 == 2,007,090,103 as the 3rd try of the 1st day of the 9th month of the 2007th year, except you must take care to avoid confusing yourself with integers larger than the 2,147,483,647 limit of 32-bit signed arithmetic.&lt;br /&gt;
&lt;br /&gt;
== Conventional Linear Congruential Seedable PRNG Based On Multiply/ Add/ Overflow ==&lt;br /&gt;
&lt;br /&gt;
Note: Google Groups sci.math cites Knuth &amp;amp; Lewis suggesting the following linear congruential generator for 32-bit arithmetic processors. Someone skilled in the relevant mathematics should be able to prove that these choices of multiplier and addend provides results that feel more random. Someone skilled in Google might find yet more popular choices than these. People say the choose function returning the quotient rather than the remainder matters: try counting odd results and even results from the pseudorandom() routine to see why.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
integer seed = 2007090103;&lt;br /&gt;
&lt;br /&gt;
integer pseudorandom()&lt;br /&gt;
{&lt;br /&gt;
    seed = 1664525 * seed + 1013904223;&lt;br /&gt;
    return seed;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer choose(integer count)&lt;br /&gt;
{&lt;br /&gt;
    integer nonnegative = 0x7fffFFFF;&lt;br /&gt;
    integer choice = pseudorandom() &amp;amp; nonnegative;&lt;br /&gt;
    return ((choice / (nonnegative / count)) % count);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        string line;&lt;br /&gt;
        integer index;&lt;br /&gt;
&lt;br /&gt;
        line = &amp;quot;&amp;quot;;&lt;br /&gt;
        for (index = 0; index &amp;lt; 9; ++index)&lt;br /&gt;
        {&lt;br /&gt;
           line += &amp;quot; &amp;quot; + (string) pseudorandom();&lt;br /&gt;
        }&lt;br /&gt;
        llOwnerSay(line);&lt;br /&gt;
&lt;br /&gt;
        line = &amp;quot;&amp;quot;;&lt;br /&gt;
        for (index = 0; index &amp;lt; 30; ++index)&lt;br /&gt;
        {&lt;br /&gt;
           line += &amp;quot; &amp;quot; + (string) (1 + choose(6));&lt;br /&gt;
        }&lt;br /&gt;
        llOwnerSay(line);&lt;br /&gt;
&lt;br /&gt;
        llOwnerSay(&amp;quot;OK&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Seedable PRNG Based On MD5 Hashing ==&lt;br /&gt;
I haven&#039;t noticed any irregular behavior in this one, i would love to know what you guys think - Kyrah Abattoir&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
string seed = &amp;quot;&amp;quot;;//Any String you want as your initial seed.&lt;br /&gt;
&lt;br /&gt;
//this version will pull a random int from 0 to max int&lt;br /&gt;
integer NextInt()&lt;br /&gt;
{&lt;br /&gt;
	seed = llMD5String(seed,0);&lt;br /&gt;
	integer value = (integer)(&amp;quot;0x&amp;quot;+llGetSubString(seed,0,6));&lt;br /&gt;
	return value;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//This one will limit the result from 0 to the range indicated&lt;br /&gt;
integer NextIntClamped(integer max)&lt;br /&gt;
{&lt;br /&gt;
	max++;&lt;br /&gt;
	seed = llMD5String(seed,0);&lt;br /&gt;
	integer value = (integer)(&amp;quot;0x&amp;quot;+llGetSubString(seed,0,6))%max;&lt;br /&gt;
	return value;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//0 to 1 duh.&lt;br /&gt;
integer NextBool()&lt;br /&gt;
{&lt;br /&gt;
	return NextIntClamped(1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I think MD5 random is just fine. I did some testing with ent and dieharder (random number test suites) based on recursed md5 &#039;random&#039; and it seems to have superior pseudo-random-number charactaristics. The only drawback is the decreased performance, which is usually (for games etc) not an issue at all.&lt;br /&gt;
My version (below) added a little extra entropy using timestamps. You could inject other sources of entropy as well. [[User:Tano Toll|Tano Toll]] Tano Toll&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
string md5=&amp;quot;seed&amp;quot;;&lt;br /&gt;
integer rnd() {&lt;br /&gt;
    //add in more entropy if you like, like touch position (detectedtouchST etc).&lt;br /&gt;
    //however, seeding the md5 with itself is already quite sufficient&lt;br /&gt;
    md5=llMD5String(md5+(string)llGetUnixTime()+(string)llGetTime(), 0x5EED);        &lt;br /&gt;
    return (integer)(&amp;quot;0x&amp;quot;+llGetSubString(md5,0,7));    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
float frnd (float max) {&lt;br /&gt;
    //this suffers a few bit rounding errors&lt;br /&gt;
    return llFabs(max * rnd()/0x80000000);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ ent random.outmd5 &lt;br /&gt;
Entropy = 7.999961 bits per byte.&lt;br /&gt;
&lt;br /&gt;
Optimum compression would reduce the size&lt;br /&gt;
of this 4222048 byte file by 0 percent.&lt;br /&gt;
&lt;br /&gt;
Chi square distribution for 4222048 samples is 231.03, and randomly&lt;br /&gt;
would exceed this value 75.00 percent of the times.&lt;br /&gt;
&lt;br /&gt;
Arithmetic mean value of data bytes is 127.4654 (127.5 = random).&lt;br /&gt;
Monte Carlo value for Pi is 3.140641831 (error 0.03 percent).&lt;br /&gt;
Serial correlation coefficient is 0.000047 (totally uncorrelated = 0.0).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{LSLC|Library}}&lt;/div&gt;</summary>
		<author><name>Tano Toll</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Pseudo-random_Number_Generator&amp;diff=1176856</id>
		<title>Pseudo-random Number Generator</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Pseudo-random_Number_Generator&amp;diff=1176856"/>
		<updated>2013-02-19T22:43:32Z</updated>

		<summary type="html">&lt;p&gt;Tano Toll: /* Seedable PRNG Based On MD5 Hashing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{LSL Header}}&lt;br /&gt;
&lt;br /&gt;
See also: [[llFrand]], [[llListRandomize]], [[Seedable_PRNG]]&lt;br /&gt;
&lt;br /&gt;
== Seedable PRNG Based On Multiply/ Add/ Overflow ==&lt;br /&gt;
&lt;br /&gt;
Here&#039;s a Pseudo-random Number Generator - I ([[User:Xaviar Czervik|Xaviar Czervik]]) just made it up off the top of my head - so it has no mathematical research behind it to prove it&#039;s random... I&#039;ve tested it for a while and it looks random to me, about the same as llFrand(). But what ever. Sue me. The main reason that I use it so that I can test scripts, and then when it blows up because of a math error, I can just run the script again an it will use the same numbers, in the same order. &lt;br /&gt;
&lt;br /&gt;
I use this for determining a random channel for two (or more) objects to talk on. This allows the scripts to talk without users being able to intercept the messages - and even if they do - then the channel will change in a minute or two - so no harm done.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// IMPORTANT: Change the following numbers before using!&lt;br /&gt;
integer seed1 = 0x053FA20C;&lt;br /&gt;
integer seed2 = 0x3B1264D5;&lt;br /&gt;
integer seed1Mod = 0x71B5F252;&lt;br /&gt;
integer seed2Mod = 0x56A0E61D;&lt;br /&gt;
&lt;br /&gt;
integer rand(integer spread) {&lt;br /&gt;
    	seed1 = (seed1 * seed1Mod + 0xB);&lt;br /&gt;
    	seed2 = (seed2 * seed2Mod + 0xB);&lt;br /&gt;
        seed2Mod = seed1Mod;&lt;br /&gt;
        seed1Mod = seed1 * seed2;&lt;br /&gt;
	return seed1Mod % spread;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
The below code is exactly the same as the above, only it is much faster. Thanks to Strife Onizuka.&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
integer rand(integer spread) {&lt;br /&gt;
    	seed2 = (seed2 * seed2Mod + 0xB);&lt;br /&gt;
	return (seed1Mod = ((seed1 = (seed1 * (seed2Mod = seed1Mod) + 0xB)) * seed2)) % spread;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
Example code to test the randomness (Is that a word?) of the generator.&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
default {&lt;br /&gt;
	state_entry() {&lt;br /&gt;
		integer i = 0;&lt;br /&gt;
		integer min = 0x7FFFFFFF;&lt;br /&gt;
		integer max = -0x7FFFFFFF;&lt;br /&gt;
		integer total = 0;&lt;br /&gt;
		while (i &amp;lt; 100000000) {&lt;br /&gt;
			integer r = rand(0x7FFFFFFF);&lt;br /&gt;
			if (r &amp;lt; min) {&lt;br /&gt;
				min = r;&lt;br /&gt;
			}&lt;br /&gt;
			if (r &amp;gt; max) {&lt;br /&gt;
				max = r;&lt;br /&gt;
			}&lt;br /&gt;
			total += r;&lt;br /&gt;
			i++;&lt;br /&gt;
		}&lt;br /&gt;
		llOwnerSay(&amp;quot;Min: &amp;quot; + (string)min);&lt;br /&gt;
		llOwnerSay(&amp;quot;Max: &amp;quot; + (string)max);&lt;br /&gt;
		llOwnerSay(&amp;quot;Average: &amp;quot; + (string)(total/100000000));&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: A pattern of digits like yyyymmddnn often works as a seed that changes often enough, &#039;&#039;e.g.&#039;&#039;, test with 2007090103 == 2,007,090,103 as the 3rd try of the 1st day of the 9th month of the 2007th year, except you must take care to avoid confusing yourself with integers larger than the 2,147,483,647 limit of 32-bit signed arithmetic.&lt;br /&gt;
&lt;br /&gt;
== Conventional Linear Congruential Seedable PRNG Based On Multiply/ Add/ Overflow ==&lt;br /&gt;
&lt;br /&gt;
Note: Google Groups sci.math cites Knuth &amp;amp; Lewis suggesting the following linear congruential generator for 32-bit arithmetic processors. Someone skilled in the relevant mathematics should be able to prove that these choices of multiplier and addend provides results that feel more random. Someone skilled in Google might find yet more popular choices than these. People say the choose function returning the quotient rather than the remainder matters: try counting odd results and even results from the pseudorandom() routine to see why.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
integer seed = 2007090103;&lt;br /&gt;
&lt;br /&gt;
integer pseudorandom()&lt;br /&gt;
{&lt;br /&gt;
    seed = 1664525 * seed + 1013904223;&lt;br /&gt;
    return seed;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer choose(integer count)&lt;br /&gt;
{&lt;br /&gt;
    integer nonnegative = 0x7fffFFFF;&lt;br /&gt;
    integer choice = pseudorandom() &amp;amp; nonnegative;&lt;br /&gt;
    return ((choice / (nonnegative / count)) % count);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        string line;&lt;br /&gt;
        integer index;&lt;br /&gt;
&lt;br /&gt;
        line = &amp;quot;&amp;quot;;&lt;br /&gt;
        for (index = 0; index &amp;lt; 9; ++index)&lt;br /&gt;
        {&lt;br /&gt;
           line += &amp;quot; &amp;quot; + (string) pseudorandom();&lt;br /&gt;
        }&lt;br /&gt;
        llOwnerSay(line);&lt;br /&gt;
&lt;br /&gt;
        line = &amp;quot;&amp;quot;;&lt;br /&gt;
        for (index = 0; index &amp;lt; 30; ++index)&lt;br /&gt;
        {&lt;br /&gt;
           line += &amp;quot; &amp;quot; + (string) (1 + choose(6));&lt;br /&gt;
        }&lt;br /&gt;
        llOwnerSay(line);&lt;br /&gt;
&lt;br /&gt;
        llOwnerSay(&amp;quot;OK&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Seedable PRNG Based On MD5 Hashing ==&lt;br /&gt;
I haven&#039;t noticed any irregular behavior in this one, i would love to know what you guys think - Kyrah Abattoir&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
string seed = &amp;quot;&amp;quot;;//Any String you want as your initial seed.&lt;br /&gt;
&lt;br /&gt;
//this version will pull a random int from 0 to max int&lt;br /&gt;
integer NextInt()&lt;br /&gt;
{&lt;br /&gt;
	seed = llMD5String(seed,0);&lt;br /&gt;
	integer value = (integer)(&amp;quot;0x&amp;quot;+llGetSubString(seed,0,6));&lt;br /&gt;
	return value;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//This one will limit the result from 0 to the range indicated&lt;br /&gt;
integer NextIntClamped(integer max)&lt;br /&gt;
{&lt;br /&gt;
	max++;&lt;br /&gt;
	seed = llMD5String(seed,0);&lt;br /&gt;
	integer value = (integer)(&amp;quot;0x&amp;quot;+llGetSubString(seed,0,6))%max;&lt;br /&gt;
	return value;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//0 to 1 duh.&lt;br /&gt;
integer NextBool()&lt;br /&gt;
{&lt;br /&gt;
	return NextIntClamped(1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I think MD5 random is just fine. I did some testing with ent and dieharder (random number test suites) based on recursed md5 &#039;random&#039; and it seems to have superior pseudo-random-number charactaristics. The only drawback is the decreased performance, which is usually (for games etc) not an issue at all.&lt;br /&gt;
My version (below) added a little extra entropy using timestamps. You could inject other sources of entropy as well. [[User:Tano Toll|Tano Toll]] Tano Toll&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
string md5=&amp;quot;seed&amp;quot;;&lt;br /&gt;
integer rnd() {&lt;br /&gt;
    //add in more entropy if you like, like touch position (detectedtouchST etc).&lt;br /&gt;
    //however, seeding the md5 with itself is already quite sufficient&lt;br /&gt;
    string md5=llMD5String(md5+(string)llGetUnixTime()+(string)llGetTime(), 0x5EED);        &lt;br /&gt;
    return (integer)(&amp;quot;0x&amp;quot;+llGetSubString(md5,0,7));    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
float frnd (float max) {&lt;br /&gt;
    //this suffers a few bit rounding errors&lt;br /&gt;
    return llFabs(max * rnd()/0x80000000);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ ent random.outmd5 &lt;br /&gt;
Entropy = 7.999961 bits per byte.&lt;br /&gt;
&lt;br /&gt;
Optimum compression would reduce the size&lt;br /&gt;
of this 4222048 byte file by 0 percent.&lt;br /&gt;
&lt;br /&gt;
Chi square distribution for 4222048 samples is 231.03, and randomly&lt;br /&gt;
would exceed this value 75.00 percent of the times.&lt;br /&gt;
&lt;br /&gt;
Arithmetic mean value of data bytes is 127.4654 (127.5 = random).&lt;br /&gt;
Monte Carlo value for Pi is 3.140641831 (error 0.03 percent).&lt;br /&gt;
Serial correlation coefficient is 0.000047 (totally uncorrelated = 0.0).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{LSLC|Library}}&lt;/div&gt;</summary>
		<author><name>Tano Toll</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Pseudo-random_Number_Generator&amp;diff=1176855</id>
		<title>Pseudo-random Number Generator</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Pseudo-random_Number_Generator&amp;diff=1176855"/>
		<updated>2013-02-19T22:39:51Z</updated>

		<summary type="html">&lt;p&gt;Tano Toll: /* Seedable PRNG Based On MD5 Hashing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{LSL Header}}&lt;br /&gt;
&lt;br /&gt;
See also: [[llFrand]], [[llListRandomize]], [[Seedable_PRNG]]&lt;br /&gt;
&lt;br /&gt;
== Seedable PRNG Based On Multiply/ Add/ Overflow ==&lt;br /&gt;
&lt;br /&gt;
Here&#039;s a Pseudo-random Number Generator - I ([[User:Xaviar Czervik|Xaviar Czervik]]) just made it up off the top of my head - so it has no mathematical research behind it to prove it&#039;s random... I&#039;ve tested it for a while and it looks random to me, about the same as llFrand(). But what ever. Sue me. The main reason that I use it so that I can test scripts, and then when it blows up because of a math error, I can just run the script again an it will use the same numbers, in the same order. &lt;br /&gt;
&lt;br /&gt;
I use this for determining a random channel for two (or more) objects to talk on. This allows the scripts to talk without users being able to intercept the messages - and even if they do - then the channel will change in a minute or two - so no harm done.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// IMPORTANT: Change the following numbers before using!&lt;br /&gt;
integer seed1 = 0x053FA20C;&lt;br /&gt;
integer seed2 = 0x3B1264D5;&lt;br /&gt;
integer seed1Mod = 0x71B5F252;&lt;br /&gt;
integer seed2Mod = 0x56A0E61D;&lt;br /&gt;
&lt;br /&gt;
integer rand(integer spread) {&lt;br /&gt;
    	seed1 = (seed1 * seed1Mod + 0xB);&lt;br /&gt;
    	seed2 = (seed2 * seed2Mod + 0xB);&lt;br /&gt;
        seed2Mod = seed1Mod;&lt;br /&gt;
        seed1Mod = seed1 * seed2;&lt;br /&gt;
	return seed1Mod % spread;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
The below code is exactly the same as the above, only it is much faster. Thanks to Strife Onizuka.&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
integer rand(integer spread) {&lt;br /&gt;
    	seed2 = (seed2 * seed2Mod + 0xB);&lt;br /&gt;
	return (seed1Mod = ((seed1 = (seed1 * (seed2Mod = seed1Mod) + 0xB)) * seed2)) % spread;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
Example code to test the randomness (Is that a word?) of the generator.&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
default {&lt;br /&gt;
	state_entry() {&lt;br /&gt;
		integer i = 0;&lt;br /&gt;
		integer min = 0x7FFFFFFF;&lt;br /&gt;
		integer max = -0x7FFFFFFF;&lt;br /&gt;
		integer total = 0;&lt;br /&gt;
		while (i &amp;lt; 100000000) {&lt;br /&gt;
			integer r = rand(0x7FFFFFFF);&lt;br /&gt;
			if (r &amp;lt; min) {&lt;br /&gt;
				min = r;&lt;br /&gt;
			}&lt;br /&gt;
			if (r &amp;gt; max) {&lt;br /&gt;
				max = r;&lt;br /&gt;
			}&lt;br /&gt;
			total += r;&lt;br /&gt;
			i++;&lt;br /&gt;
		}&lt;br /&gt;
		llOwnerSay(&amp;quot;Min: &amp;quot; + (string)min);&lt;br /&gt;
		llOwnerSay(&amp;quot;Max: &amp;quot; + (string)max);&lt;br /&gt;
		llOwnerSay(&amp;quot;Average: &amp;quot; + (string)(total/100000000));&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: A pattern of digits like yyyymmddnn often works as a seed that changes often enough, &#039;&#039;e.g.&#039;&#039;, test with 2007090103 == 2,007,090,103 as the 3rd try of the 1st day of the 9th month of the 2007th year, except you must take care to avoid confusing yourself with integers larger than the 2,147,483,647 limit of 32-bit signed arithmetic.&lt;br /&gt;
&lt;br /&gt;
== Conventional Linear Congruential Seedable PRNG Based On Multiply/ Add/ Overflow ==&lt;br /&gt;
&lt;br /&gt;
Note: Google Groups sci.math cites Knuth &amp;amp; Lewis suggesting the following linear congruential generator for 32-bit arithmetic processors. Someone skilled in the relevant mathematics should be able to prove that these choices of multiplier and addend provides results that feel more random. Someone skilled in Google might find yet more popular choices than these. People say the choose function returning the quotient rather than the remainder matters: try counting odd results and even results from the pseudorandom() routine to see why.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
integer seed = 2007090103;&lt;br /&gt;
&lt;br /&gt;
integer pseudorandom()&lt;br /&gt;
{&lt;br /&gt;
    seed = 1664525 * seed + 1013904223;&lt;br /&gt;
    return seed;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer choose(integer count)&lt;br /&gt;
{&lt;br /&gt;
    integer nonnegative = 0x7fffFFFF;&lt;br /&gt;
    integer choice = pseudorandom() &amp;amp; nonnegative;&lt;br /&gt;
    return ((choice / (nonnegative / count)) % count);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        string line;&lt;br /&gt;
        integer index;&lt;br /&gt;
&lt;br /&gt;
        line = &amp;quot;&amp;quot;;&lt;br /&gt;
        for (index = 0; index &amp;lt; 9; ++index)&lt;br /&gt;
        {&lt;br /&gt;
           line += &amp;quot; &amp;quot; + (string) pseudorandom();&lt;br /&gt;
        }&lt;br /&gt;
        llOwnerSay(line);&lt;br /&gt;
&lt;br /&gt;
        line = &amp;quot;&amp;quot;;&lt;br /&gt;
        for (index = 0; index &amp;lt; 30; ++index)&lt;br /&gt;
        {&lt;br /&gt;
           line += &amp;quot; &amp;quot; + (string) (1 + choose(6));&lt;br /&gt;
        }&lt;br /&gt;
        llOwnerSay(line);&lt;br /&gt;
&lt;br /&gt;
        llOwnerSay(&amp;quot;OK&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Seedable PRNG Based On MD5 Hashing ==&lt;br /&gt;
I haven&#039;t noticed any irregular behavior in this one, i would love to know what you guys think - Kyrah Abattoir&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
string seed = &amp;quot;&amp;quot;;//Any String you want as your initial seed.&lt;br /&gt;
&lt;br /&gt;
//this version will pull a random int from 0 to max int&lt;br /&gt;
integer NextInt()&lt;br /&gt;
{&lt;br /&gt;
	seed = llMD5String(seed,0);&lt;br /&gt;
	integer value = (integer)(&amp;quot;0x&amp;quot;+llGetSubString(seed,0,6));&lt;br /&gt;
	return value;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//This one will limit the result from 0 to the range indicated&lt;br /&gt;
integer NextIntClamped(integer max)&lt;br /&gt;
{&lt;br /&gt;
	max++;&lt;br /&gt;
	seed = llMD5String(seed,0);&lt;br /&gt;
	integer value = (integer)(&amp;quot;0x&amp;quot;+llGetSubString(seed,0,6))%max;&lt;br /&gt;
	return value;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//0 to 1 duh.&lt;br /&gt;
integer NextBool()&lt;br /&gt;
{&lt;br /&gt;
	return NextIntClamped(1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I think MD5 random is just fine. I did some testing with ent and dieharder (random number test suites) based on recursed md5 &#039;random&#039; and it seems to have superior pseudo-random-number charactaristics. The only drawback is the decreased performance, which is usually (for games etc) not an issue at all.&lt;br /&gt;
My version (below) added a little extra entropy using timestamps. You could inject other sources of entropy as well. [[User:Tano Toll|Tano Toll]] Tano Toll&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
string md5=&amp;quot;seed&amp;quot;;&lt;br /&gt;
integer rnd() {&lt;br /&gt;
    //add in more entropy if you like, like touch position (detectedtouchST etc).&lt;br /&gt;
    //however, seeding the md5 with itself is already quite sufficient&lt;br /&gt;
    string md5=llMD5String(md5+(string)llGetUnixTime()+(string)llGetTime(), 0x5EED);        &lt;br /&gt;
    return (integer)(&amp;quot;0x&amp;quot;+llGetSubString(md5,0,7));    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
float frnd (float max) {&lt;br /&gt;
    //this suffers a few bit rounding errors&lt;br /&gt;
    return llFabs(max * rnd()/0x80000000);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{LSLC|Library}}&lt;/div&gt;</summary>
		<author><name>Tano Toll</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=ParcelChatRelay&amp;diff=1175797</id>
		<title>ParcelChatRelay</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=ParcelChatRelay&amp;diff=1175797"/>
		<updated>2013-01-03T12:06:21Z</updated>

		<summary type="html">&lt;p&gt;Tano Toll: /* Notes: */ Added code for version 2&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Parcel Chat Relay==&lt;br /&gt;
&lt;br /&gt;
===Description:===&lt;br /&gt;
Communicate on your land in general chat regardless of distance between avatars. Useful when building, in clubs, for roleplay, etc.&lt;br /&gt;
&lt;br /&gt;
Messages will be intelligently relayed - a listener will never hear a message twice! It will either be heard normally, or relayed. Using the new llRegionSayTo() api, chat messages are only relayed to avatars that are out of range.&lt;br /&gt;
&lt;br /&gt;
===How to use:===&lt;br /&gt;
* Rez 1 or more relays on your parcel, in a way that you could hear each avatar (&amp;lt;20m). Do not worry overlapping, but don&#039;t overdo it either - less relays will still be less lag.&lt;br /&gt;
* If you rez a relay on its&#039; final position, it will immediately be &#039;tuned&#039; and part of the network.&lt;br /&gt;
* If you move or remove a relay, it might take up to 10 minutes for the network to catch up.&lt;br /&gt;
&lt;br /&gt;
===Features:===&lt;br /&gt;
* Muliple relays can be rezzed to cover each part of your parcel.&lt;br /&gt;
* Dedoubling without any overhead&lt;br /&gt;
* Low lag - relays do not have to communicate to dedouble messages&lt;br /&gt;
&lt;br /&gt;
===Limitations:===&lt;br /&gt;
* Works only per parcel (by design). Agents on neighboring land will not receive relayed messages.&lt;br /&gt;
* Receivers have to be within radar range (96m) of the receiving relay&lt;br /&gt;
* Scripts cannot distinguish normal say, whispering and shouting. Normal say is assumed. Shouts may be heard double by the receiver&lt;br /&gt;
* Moving avatars might experience &#039;border&#039; cases - where a message sometimes accidentally is not relayed or double relayed. Due to the fast response time unlikely&lt;br /&gt;
* The displayed (&#039;faked&#039;) name is the official linden name, and chat is colored like objects, not avatars. Also depends on viewer settings.&lt;br /&gt;
Remarks on the parcel limitation.. Other options (sim wide, range based) would be easily possible, but i like the item to be zero-config (&#039;just works&#039;). Feel free to mod the script at your demands.&lt;br /&gt;
&lt;br /&gt;
===License:===&lt;br /&gt;
Modified BSD / public domain&lt;br /&gt;
&lt;br /&gt;
This script is also available at marketplace for your convenience: https://marketplace.secondlife.com/p/Parcel-Chat-Relay/3157725&lt;br /&gt;
&lt;br /&gt;
===Notes:===&lt;br /&gt;
Possible easy-to-adjust modifications: do not use parcel key but owner key as handle, allowing cross parcel-but-same-owner chat, or specifying a fixed key for region-wide that.&lt;br /&gt;
&lt;br /&gt;
===VERSION 2.0===&lt;br /&gt;
Recommended and most efficient version&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
//PCR Version 2//&lt;br /&gt;
//changes:&lt;br /&gt;
//* No longer uses radar but llGetAgentList to detect agents&lt;br /&gt;
//* Removed hover text and replaced by ownersay spam on updates&lt;br /&gt;
//* Added configurable option for coverage (parcel, parcels by same owner, entire region)&lt;br /&gt;
//* Made timer faster running in first 10 minutes after rez, to update faster on repositions&lt;br /&gt;
//* Some adjustments to allow cross-parcel and region-wide chat; replaced parcel key by owner key in those situations.&lt;br /&gt;
//* Overall, this version is more efficient and causes less lag, especially when idling, since agent list is not unneccesary updated by sensor events. It also provides better coverage and automatic support for skyboxes.&lt;br /&gt;
&lt;br /&gt;
//2011-2012 Tano Toll - TSL License//&lt;br /&gt;
&lt;br /&gt;
//Short summorization:&lt;br /&gt;
//Relays will know of eachothers existance&lt;br /&gt;
//Relays listen to public chat&lt;br /&gt;
//The relay _closest_ to sending agent is responsible for relaying the message&lt;br /&gt;
//Messages will only be relayed to agents further than 20 meter away from the speaker&lt;br /&gt;
//Messages will only be relayed to agents on the same parcel&lt;br /&gt;
&lt;br /&gt;
//USAGE:&lt;br /&gt;
//* Edit coverage parameter below to suit your needs&lt;br /&gt;
//* place this script in a objects, placed in hearing range of avatars&lt;br /&gt;
//* If you do NOT want to relay a certain place, like a skybox, simply place no relay object. However, agents in the skybox will still hear what is said near other relays. If you do not want that, please use version 1 of this script that uses radar to detect agents.&lt;br /&gt;
&lt;br /&gt;
// CONFIGURATION&lt;br /&gt;
&lt;br /&gt;
//choose coverage:&lt;br /&gt;
//integer coverage=AGENT_LIST_PARCEL;&lt;br /&gt;
integer coverage=AGENT_LIST_PARCEL_OWNER;&lt;br /&gt;
//integer coverage=AGENT_LIST_REGION;&lt;br /&gt;
&lt;br /&gt;
//Maximum range from listener object to avatar&lt;br /&gt;
integer maxRange=6000; //sim wide, reaches all skyboxes&lt;br /&gt;
//integer maxRange=290; //sim wide, ground level&lt;br /&gt;
//integer maxRange=100; //radar range, like version 1&lt;br /&gt;
&lt;br /&gt;
//just a hash. change to use several systems on a single parcel.&lt;br /&gt;
string tag=&amp;quot;+-/&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// NO NEED TO EDIT BELOW THIS LINE. CHANGES AT OWN RISK //&lt;br /&gt;
&lt;br /&gt;
//list of detected nearby agents:&lt;br /&gt;
list insim;&lt;br /&gt;
&lt;br /&gt;
//timestamp of last check - to reduce sim load&lt;br /&gt;
integer stamp;&lt;br /&gt;
&lt;br /&gt;
//key of the parcel where we are rezzed&lt;br /&gt;
key parcelkey;&lt;br /&gt;
&lt;br /&gt;
//key based for handle, depending on setting parcel or owner&lt;br /&gt;
key handlebase; &lt;br /&gt;
&lt;br /&gt;
//chat channel handle made with key as base&lt;br /&gt;
integer handle;&lt;br /&gt;
&lt;br /&gt;
//list of detected nearby relays&lt;br /&gt;
list repeaters;&lt;br /&gt;
&lt;br /&gt;
//for less confusing setup, fast timer first minutes after rez, then slow down to appropiate interval&lt;br /&gt;
integer timercount;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
announce() {&lt;br /&gt;
    llRegionSay (handle, tag+(string)handlebase);   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        //llSetText(&amp;quot;Chat Relay started...&amp;quot;,ZERO_VECTOR,1);&lt;br /&gt;
        llOwnerSay(&amp;quot;Chat Relay started...&amp;quot;);&lt;br /&gt;
        if (llGetAttached()) {&lt;br /&gt;
            //owner relay only mode&lt;br /&gt;
            //redundant in this script.&lt;br /&gt;
            //llListen (0, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
        } else {&lt;br /&gt;
            //relay all agents&lt;br /&gt;
            llListen (0, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);   &lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        //scan for nearby agents&lt;br /&gt;
        //llSensorRepeat (&amp;quot;&amp;quot;, &amp;quot;&amp;quot;, AGENT, 65, TWO_PI, 20);&lt;br /&gt;
        &lt;br /&gt;
        //make up a inter-relay channel, so they can find eachother&lt;br /&gt;
        parcelkey=llList2Key(llGetParcelDetails(llGetPos(), [PARCEL_DETAILS_ID]),0);        &lt;br /&gt;
        &lt;br /&gt;
        //adjust key based on coverage. for single parcel, use parcel key. else use owner key.&lt;br /&gt;
        //notice that on region-wide coverage, all relays must be rezzed by same owner.&lt;br /&gt;
                      &lt;br /&gt;
        if (coverage==AGENT_LIST_PARCEL)&lt;br /&gt;
            handlebase=parcelkey;&lt;br /&gt;
        else&lt;br /&gt;
            handlebase=llGetOwner();&lt;br /&gt;
            &lt;br /&gt;
        handle=-10909-(integer)(&amp;quot;0x&amp;quot;+llGetSubString(handlebase,1,5));&lt;br /&gt;
        llListen(handle, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, tag+(string)handlebase);&lt;br /&gt;
        &lt;br /&gt;
        //broadcast our existance about every 5 minutes, but starting with 10 second interval to avoid setup confusion&lt;br /&gt;
        //llSetTimerEvent(290.0+llFrand (20.0)); //about each 300 seconds, not all at once&lt;br /&gt;
        llSetTimerEvent (10.0);&lt;br /&gt;
        announce();&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    on_rez(integer n) {&lt;br /&gt;
        //simply reset&lt;br /&gt;
        llResetScript();   &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    timer() {        &lt;br /&gt;
        //announce self&lt;br /&gt;
        announce();&lt;br /&gt;
        &lt;br /&gt;
        //check interval&lt;br /&gt;
        timercount++;&lt;br /&gt;
        if (timercount==60) //after about 10 minutes&lt;br /&gt;
            llSetTimerEvent(290.0+llFrand (20.0)); //change to 5 minute interval       &lt;br /&gt;
        &lt;br /&gt;
        //and clear list. repeaters with an too old timestamp will be removed.&lt;br /&gt;
        integer n=llGetListLength(repeaters)-1;&lt;br /&gt;
        integer t=llGetUnixTime();&lt;br /&gt;
        while (n&amp;gt;0) {&lt;br /&gt;
            if ((t-llList2Integer(repeaters, n))&amp;gt;390) { //time out&lt;br /&gt;
                llOwnerSay (&amp;quot;Lost connection to node at &amp;quot;+(string)llList2Vector(repeaters, n-1));&lt;br /&gt;
                repeaters=llDeleteSubList(repeaters, n-2, n);&lt;br /&gt;
            }&lt;br /&gt;
            n-=3;&lt;br /&gt;
        }   &lt;br /&gt;
        //llSetText (&amp;quot;Node(s): &amp;quot;+(string)(1+llGetListLength(repeaters)/3), &amp;lt;1,1,1&amp;gt;, 1);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    listen (integer channel, string name, key id, string m) {        &lt;br /&gt;
        &lt;br /&gt;
        if (!channel) { //channel 0&lt;br /&gt;
            //only relay agents, not objects&lt;br /&gt;
            if (llGetAgentSize(id));else&lt;br /&gt;
                return;&lt;br /&gt;
                &lt;br /&gt;
            //see if another relay is more nearby&lt;br /&gt;
            integer n=0;&lt;br /&gt;
            vector senderpos=llList2Vector(llGetObjectDetails(id, [OBJECT_POS]), 0);&lt;br /&gt;
            float d=llVecDist(senderpos, llGetPos());            &lt;br /&gt;
            while (n&amp;lt;llGetListLength(repeaters)) {&lt;br /&gt;
                if (d&amp;gt;llVecDist(senderpos, llList2Vector(repeaters, n+1)))&lt;br /&gt;
                    return;&lt;br /&gt;
                n+=3;&lt;br /&gt;
            }&lt;br /&gt;
            //We are nearest repeater. Our job to relay.&lt;br /&gt;
            &lt;br /&gt;
            //see if we need to refresh our list - cache it for 15 seconds&lt;br /&gt;
            if ((llGetUnixTime()-stamp) &amp;gt; 15.0) {&lt;br /&gt;
                stamp=llGetUnixTime();&lt;br /&gt;
                insim=llGetAgentList (coverage, []);&lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
            //relay to everyone in range. that&#039;s fixed to minimum 20 mins maximum 60.&lt;br /&gt;
            //get position of chatter&lt;br /&gt;
            vector o=llList2Vector(llGetObjectDetails(id, [OBJECT_POS]), 0);&lt;br /&gt;
        &lt;br /&gt;
            n=llGetListLength(insim);&lt;br /&gt;
            string oname=llGetObjectName();&lt;br /&gt;
            llSetObjectName(name);&lt;br /&gt;
            while (~--n) {&lt;br /&gt;
                vector t=llList2Vector(llGetObjectDetails(llList2Key(insim, n), [OBJECT_POS]), 0);        &lt;br /&gt;
                float d=llVecDist (o,t);&lt;br /&gt;
                if (d&amp;gt;=20 &amp;amp;&amp;amp; d&amp;lt;=maxRange) {&lt;br /&gt;
                    //same parcel? - edit - check skipped.&lt;br /&gt;
                    //if (parcelkey==llList2Key(llGetParcelDetails(llList2Vector(llGetObjectDetails(llList2Key(insim,n), [OBJECT_POS]),0), [PARCEL_DETAILS_ID]),0))&lt;br /&gt;
                        llRegionSayTo (llList2Key(insim,n), 0, m);   &lt;br /&gt;
                }&lt;br /&gt;
            }       &lt;br /&gt;
            llSetObjectName(oname);&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (channel==handle) {&lt;br /&gt;
            //there&#039;s another repeater..&lt;br /&gt;
            vector pos=llList2Vector(llGetObjectDetails(id, [OBJECT_POS]),0);&lt;br /&gt;
            &lt;br /&gt;
            integer p=llListFindList(repeaters, [id, pos]);&lt;br /&gt;
            if (~p)&lt;br /&gt;
                repeaters=llDeleteSubList(repeaters, p, p+2);&lt;br /&gt;
            else&lt;br /&gt;
                llOwnerSay (&amp;quot;New node found at &amp;quot;+(string)pos);&lt;br /&gt;
            repeaters += [id, pos, llGetUnixTime()];&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===VERSION 1.0===&lt;br /&gt;
In some cases, you might want to use the original radar-based version. Usually not recommended, listed for completeness.&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
//2011-2012 Tano Toll - TSL License//&lt;br /&gt;
&lt;br /&gt;
//Short summorization:&lt;br /&gt;
//Relays will know of eachothers existance&lt;br /&gt;
//Relays listen to public chat&lt;br /&gt;
//The relay _closest_ to sending agent is responsible for relaying the message&lt;br /&gt;
//Messages will only be relayed to agents further than 20 meter away from the speaker&lt;br /&gt;
//Messages will only be relayed to agents on the same parcel&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//list of detected nearby agents:&lt;br /&gt;
list insim;&lt;br /&gt;
&lt;br /&gt;
//just a hash. change to use several systems on a single parcel.&lt;br /&gt;
string tag=&amp;quot;+-/&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//key of the parcel where we are rezzed&lt;br /&gt;
key parcelkey;&lt;br /&gt;
&lt;br /&gt;
//chat channel handle made with key as base&lt;br /&gt;
integer parcelhandle;&lt;br /&gt;
&lt;br /&gt;
//list of detected nearby relays&lt;br /&gt;
list repeaters;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
announce() {&lt;br /&gt;
    llRegionSay (parcelhandle, tag+(string)parcelkey);   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llSetText(&amp;quot;Chat Relay started...&amp;quot;,ZERO_VECTOR,1);&lt;br /&gt;
        if (llGetAttached()) {&lt;br /&gt;
            //owner relay only mode&lt;br /&gt;
            //redundant in this script.&lt;br /&gt;
            //llListen (0, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
        } else {&lt;br /&gt;
            //relay all agents&lt;br /&gt;
            llListen (0, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);   &lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        //scan for nearby agents&lt;br /&gt;
        llSensorRepeat (&amp;quot;&amp;quot;, &amp;quot;&amp;quot;, AGENT, 65, TWO_PI, 20);&lt;br /&gt;
        &lt;br /&gt;
        //make up a inter-relay channel, so they can find eachother&lt;br /&gt;
        parcelkey=llList2Key(llGetParcelDetails(llGetPos(), [PARCEL_DETAILS_ID]),0);&lt;br /&gt;
        parcelhandle=-10909-(integer)(&amp;quot;0x&amp;quot;+llGetSubString(parcelkey,1,5));&lt;br /&gt;
        llListen(parcelhandle, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, tag+(string)parcelkey);&lt;br /&gt;
        &lt;br /&gt;
        //broadcast our existance about every 5 minutes&lt;br /&gt;
        llSetTimerEvent(290.0+llFrand (20.0)); //about each 300 seconds, not all at once&lt;br /&gt;
        announce();&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    on_rez(integer n) {&lt;br /&gt;
        //simply reset&lt;br /&gt;
        llResetScript();   &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    timer() {        &lt;br /&gt;
        //announce self&lt;br /&gt;
        announce();&lt;br /&gt;
        &lt;br /&gt;
        //and clear list. repeaters with an too old timestamp will be removed.&lt;br /&gt;
        integer n=llGetListLength(repeaters)-1;&lt;br /&gt;
        integer t=llGetUnixTime();&lt;br /&gt;
        while (n&amp;gt;0) {&lt;br /&gt;
            if ((t-llList2Integer(repeaters, n))&amp;gt;390) { //time out&lt;br /&gt;
                repeaters=llDeleteSubList(repeaters, n-2, n);&lt;br /&gt;
            }&lt;br /&gt;
            n-=3;&lt;br /&gt;
        }   &lt;br /&gt;
        llSetText (&amp;quot;Node(s): &amp;quot;+(string)(1+llGetListLength(repeaters)/3), &amp;lt;1,1,1&amp;gt;, 1);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    sensor (integer n) {&lt;br /&gt;
        //add detected agents to our list&lt;br /&gt;
        while (~--n) {&lt;br /&gt;
            key id=llDetectedKey(n);&lt;br /&gt;
            if (!~llListFindList(insim, [id]))&lt;br /&gt;
                insim+=id;    &lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        //clean up agents that are no longer in sim&lt;br /&gt;
        n=llGetListLength(insim);&lt;br /&gt;
        while (~--n)&lt;br /&gt;
            if (llGetAgentSize(llList2Key(insim,n))); else&lt;br /&gt;
                insim=llDeleteSubList(insim,n,n);   &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    no_sensor() {&lt;br /&gt;
        insim=[];&lt;br /&gt;
        /*&lt;br /&gt;
        //clean up agents that are no longer in sim&lt;br /&gt;
        integer n=llGetListLength(insim);&lt;br /&gt;
        while (~--n)&lt;br /&gt;
            if (llGetAgentSize(llList2Key(insim,n))); else&lt;br /&gt;
                insim=llDeleteSubList(insim,n,n);   &lt;br /&gt;
        */&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    listen (integer channel, string name, key id, string m) {&lt;br /&gt;
        &lt;br /&gt;
        &lt;br /&gt;
        if (!channel) { //channel 0&lt;br /&gt;
            //only relay agents, not objects&lt;br /&gt;
            if (llGetAgentSize(id));else&lt;br /&gt;
                return;&lt;br /&gt;
                &lt;br /&gt;
            //see if another relay is more nearby&lt;br /&gt;
            integer n=0;&lt;br /&gt;
            vector senderpos=llList2Vector(llGetObjectDetails(id, [OBJECT_POS]), 0);&lt;br /&gt;
            float d=llVecDist(senderpos, llGetPos());            &lt;br /&gt;
            while (n&amp;lt;llGetListLength(repeaters)) {&lt;br /&gt;
                if (d&amp;gt;llVecDist(senderpos, llList2Vector(repeaters, n+1)))&lt;br /&gt;
                    return;&lt;br /&gt;
                n+=3;&lt;br /&gt;
            }&lt;br /&gt;
            //We are nearest repeater. Our job to relay.&lt;br /&gt;
            &lt;br /&gt;
            //relay to everyone in range. that&#039;s fixed to minimum 20 mins maximum 60.&lt;br /&gt;
            //get position of chatter&lt;br /&gt;
            vector o=llList2Vector(llGetObjectDetails(id, [OBJECT_POS]), 0);&lt;br /&gt;
        &lt;br /&gt;
            n=llGetListLength(insim);&lt;br /&gt;
            string oname=llGetObjectName();&lt;br /&gt;
            llSetObjectName(name);&lt;br /&gt;
            while (~--n) {&lt;br /&gt;
                vector t=llList2Vector(llGetObjectDetails(llList2Key(insim, n), [OBJECT_POS]), 0);        &lt;br /&gt;
                float d=llVecDist (o,t);&lt;br /&gt;
                if (d&amp;gt;=20/* &amp;amp;&amp;amp; d&amp;lt;=60*/) {&lt;br /&gt;
                    //same parcel?&lt;br /&gt;
                    if (parcelkey==llList2Key(llGetParcelDetails(llList2Vector(llGetObjectDetails(llList2Key(insim,n), [OBJECT_POS]),0), [PARCEL_DETAILS_ID]),0))&lt;br /&gt;
                        llRegionSayTo (llList2Key(insim,n), 0, m);   &lt;br /&gt;
                }&lt;br /&gt;
            }       &lt;br /&gt;
            llSetObjectName(oname);&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (channel==parcelhandle) {&lt;br /&gt;
            //there&#039;s another repeater..&lt;br /&gt;
            vector pos=llList2Vector(llGetObjectDetails(id, [OBJECT_POS]),0);&lt;br /&gt;
            &lt;br /&gt;
            integer p=llListFindList(repeaters, [id, pos]);&lt;br /&gt;
            if (~p)&lt;br /&gt;
                repeaters=llDeleteSubList(repeaters, p, p+2);&lt;br /&gt;
            repeaters += [id, pos, llGetUnixTime()];&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
--[[User:Tano Toll|Tano Toll]] 19:54, 11 May 2012 (PDT)&lt;/div&gt;</summary>
		<author><name>Tano Toll</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:Tano_Toll&amp;diff=1174755</id>
		<title>User:Tano Toll</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:Tano_Toll&amp;diff=1174755"/>
		<updated>2012-11-22T21:24:49Z</updated>

		<summary type="html">&lt;p&gt;Tano Toll: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some of my work for the public domain:&lt;br /&gt;
&lt;br /&gt;
* [[TMCP]] - Tano&#039;s MLP Compatible Pose Scripts - poseball free drop-in replacement for MLPv2&lt;br /&gt;
&lt;br /&gt;
* [[ParcelChatRelay]] - Parcel Chat Relay efficiently allows parcel-wide channel0 talk&lt;br /&gt;
&lt;br /&gt;
* [[Stream_Music_In_PHP]] - Stream a static mp3 stream, synchronized for all listeners, using php&lt;br /&gt;
&lt;br /&gt;
* [[SimpleMLPStylingScript]] - Simple MLP/TMCP compatible styling script example.&lt;/div&gt;</summary>
		<author><name>Tano Toll</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=SimpleMLPStylingScript&amp;diff=1174754</id>
		<title>SimpleMLPStylingScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=SimpleMLPStylingScript&amp;diff=1174754"/>
		<updated>2012-11-22T21:22:22Z</updated>

		<summary type="html">&lt;p&gt;Tano Toll: &amp;lt;code&amp;gt; tag omitted from sl mediawiki, cheated with &amp;lt;lsl&amp;gt; tag.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ok, bit of old and ugly code here. Publishing anyways as example.&lt;br /&gt;
&lt;br /&gt;
What it does. This is an MLP plugin that allows styling of objects. Textures, colors, shinyness. Those are usually enough for most furniture.&lt;br /&gt;
&lt;br /&gt;
Per link, you must describe in the link properties if it is subject to a particular styling paramaters. Those are: Color1, Color2, Texture and Shiny. They are represent as :C+: :C2+: :T+: and :S+:&lt;br /&gt;
So, a linked prim, like a cushion, that is subject to color and texture, would read: :C+:T+:&lt;br /&gt;
Another linked prim, like a wooden base, would be subject to color2 (wood shades) and shininess. It&#039;s description would read :C2+:S+:&lt;br /&gt;
&lt;br /&gt;
You can activate the plugin by sending commands via a linked message on channel 13335&lt;br /&gt;
Example entry in MLP or TMCP notecard:&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
MENU Styling | OWNER&lt;br /&gt;
LINKMSG Light Colors |1,-4,-13335,LightPalette&lt;br /&gt;
LINKMSG Dark Colors |1,-4,-13335,Palette&lt;br /&gt;
LINKMSG Adjust Color|1,-4,-13335,AdjustColor&lt;br /&gt;
LINKMSG Fabric|1,-4,-13335,MenuTexture&lt;br /&gt;
LINKMSG Wood Color |1,-4,-13335,WoodPalette&lt;br /&gt;
//LINKMSG SomeTexture|0,-4,-13335,SetTexture:&amp;lt;uuid&amp;gt;&lt;br /&gt;
//LINKMSG Color Menu|1,-4,-13335,MenuColor&lt;br /&gt;
//LINKMSG Gray|0,-4,-13335,SetColor:&amp;lt;0.5,0.5,0.5&amp;gt;&lt;br /&gt;
TOMENU Shadow&lt;br /&gt;
LINKMSG Shiny Wood|0,-4,-13335,SetShiny:3&lt;br /&gt;
LINKMSG Satin Wood|0,-4,-13335,SetShiny:1&lt;br /&gt;
LINKMSG Pale Wood|0,-4,-13335,SetShiny:0&lt;br /&gt;
TOMENU Size&lt;br /&gt;
BACK&lt;br /&gt;
&lt;br /&gt;
MENU Shadow | ALL&lt;br /&gt;
This example sets the root prim&#039;s alpha.. adjust link number to whatever the shadow texture was&lt;br /&gt;
LINKMSG No Shadow|0,-4,-13335,SetAlpha:1:0&lt;br /&gt;
LINKMSG Light Shadow|0,-4,-13335,SetAlpha:1:0.5&lt;br /&gt;
LINKMSG Full Shadow|0,-4,-13335,SetAlpha:1:1.0&lt;br /&gt;
BACK&lt;br /&gt;
&lt;br /&gt;
MENU Size | OWNER&lt;br /&gt;
LINKMSG Grow|0,-4,-13335,ObjectGrow&lt;br /&gt;
LINKMSG Shrink|0,-4,-13335,ObjectShrink&lt;br /&gt;
BACK&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The styling script is as follows, and again, sorry for bit messy code.. Publishing anyways, might post an update.&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
//THIS SCRIPT ASSUMES A FEW THINGS&lt;br /&gt;
//* THAT ITS CALLED / INITIATED BY MLP or something else that invokes a linked message&lt;br /&gt;
//That the root prim is colorable just like all childs&lt;br /&gt;
//That the root prim needs no (re)texturing but all childs do.&lt;br /&gt;
//Must customize this script for color palette, textures, and/or menu stuff you want in or out - no external configuration&lt;br /&gt;
&lt;br /&gt;
//+BRIGHT CONTRAST+ +SATURATION&lt;br /&gt;
//-BRIGHT CONTRAST- -SATURATION&lt;br /&gt;
//+RED //+BLUE //+GREEN&lt;br /&gt;
//-RED //-BLUE //-GREEN&lt;br /&gt;
&lt;br /&gt;
//PALETTE&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
vector myColor; //reads root prim color on startup&lt;br /&gt;
integer channel;&lt;br /&gt;
integer handle;&lt;br /&gt;
&lt;br /&gt;
list Palette=[  &amp;quot;BORDEAUX&amp;quot;, &amp;quot;PINK&amp;quot;, &amp;quot;AQUA&amp;quot;,&lt;br /&gt;
                &amp;quot;TEAL&amp;quot;, &amp;quot;SKY&amp;quot;, &amp;quot;NAVY&amp;quot;, &lt;br /&gt;
                &amp;quot;OKER&amp;quot;, &amp;quot;BROWN&amp;quot;, &amp;quot;CREAM&amp;quot;,&lt;br /&gt;
                &amp;quot;BLACK&amp;quot;, &amp;quot;GREY&amp;quot;, &amp;quot;DARKBROWN&amp;quot;];&lt;br /&gt;
                &lt;br /&gt;
list PaletteC=[ &amp;lt;0.35,0,0&amp;gt;, &amp;lt;1,0.5,0.5&amp;gt;, &amp;lt;0.3,1.0,0.8&amp;gt;,&lt;br /&gt;
                &amp;lt;0,0.35,0.6&amp;gt;, &amp;lt;0.7,0.75,1&amp;gt;, &amp;lt;0,0,0.35&amp;gt;,&lt;br /&gt;
                &amp;lt;0.61,0.6,0.12&amp;gt;, &amp;lt;0.3,0.2,0.05&amp;gt;, &amp;lt;1.0,1.0,0.9&amp;gt;,&lt;br /&gt;
                &amp;lt;0.01,0.01,0.05&amp;gt;, &amp;lt;0.35,0.35,0.35&amp;gt;, &amp;lt;0.12,0.08,0&amp;gt;];&lt;br /&gt;
&lt;br /&gt;
list PaletteLight=[&amp;quot;BLUE1&amp;quot;, &amp;quot;BLUE2&amp;quot;, &amp;quot;BLUE3&amp;quot;,&lt;br /&gt;
                &amp;quot;PINK1&amp;quot;, &amp;quot;PINK2&amp;quot;, &amp;quot;PINK3&amp;quot;, &lt;br /&gt;
                &amp;quot;GREEN1&amp;quot;, &amp;quot;GREEN2&amp;quot;, &amp;quot;CREAM1&amp;quot;,&lt;br /&gt;
                &amp;quot;WHITE&amp;quot;, &amp;quot;GREY2&amp;quot;, &amp;quot;AMBER&amp;quot; ];&lt;br /&gt;
                &lt;br /&gt;
list PaletteL=[ &amp;lt;0.8,0.8,1.0&amp;gt;, &amp;lt;0.9,0.9,1.0&amp;gt;, &amp;lt;0.7,0.8,1.0&amp;gt;,&lt;br /&gt;
                &amp;lt;1.0,0.7,0.7&amp;gt;, &amp;lt;1.0,0.8,0.8&amp;gt;, &amp;lt;1.0,0.9,0.9&amp;gt;,&lt;br /&gt;
                &amp;lt;0.7,1.0,0.7&amp;gt;, &amp;lt;0.82,1.0,0.8&amp;gt;, &amp;lt;1.0,0.960,0.879&amp;gt;,&lt;br /&gt;
                &amp;lt;1.0,1.0,1.0&amp;gt;, &amp;lt;0.75,0.75,0.75&amp;gt;, &amp;lt;1.0, 0.9, 0.6&amp;gt;];&lt;br /&gt;
                &lt;br /&gt;
list PaletteWood =[  &amp;quot;Cherry&amp;quot;, &amp;quot;Oak&amp;quot;, &amp;quot;Mahogany&amp;quot;,&lt;br /&gt;
                    &amp;quot;Pine&amp;quot;, &amp;quot;Ebony&amp;quot;, &amp;quot;Maple&amp;quot;,&lt;br /&gt;
                    &amp;quot;OldOak&amp;quot;, &amp;quot;Rosewood&amp;quot;, &amp;quot;Elm&amp;quot;,&lt;br /&gt;
                    &amp;quot;Walnut&amp;quot;, &amp;quot;DarkWalnut&amp;quot;, &amp;quot;Onyx&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
list PaletteW=[ &amp;lt;0.6,0.28,0.18&amp;gt;, &amp;lt;0.62,0.41,0.21&amp;gt;, &amp;lt;0.26,0.08,0.05&amp;gt;,&lt;br /&gt;
                &amp;lt;0.76,0.53,0.19&amp;gt;, &amp;lt;0.12,0.11,0.11&amp;gt;, &amp;lt;0.77,0.45,0.26&amp;gt;,&lt;br /&gt;
                &amp;lt;0.59,0.4,0.24&amp;gt;, &amp;lt;0.3,0.15,0.15&amp;gt;, &amp;lt;0.4,0.25,0.2&amp;gt;,&lt;br /&gt;
                &amp;lt;0.5,0.40,0.28&amp;gt;, &amp;lt;0.29,0.14,0.05&amp;gt;, &amp;lt;0.22,0.19,0.14&amp;gt;];&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
list Textures = [&lt;br /&gt;
    &amp;quot;d14c73dd-9844-3fec-3405-c2cfa6cfae92&amp;quot;,&lt;br /&gt;
    &amp;quot;29e827fe-6d57-e155-eaed-236a58b71244&amp;quot;,&lt;br /&gt;
    //&amp;quot;1ae6c524-9a2e-b3a5-6349-4b99dfd861a3&amp;quot;,&lt;br /&gt;
    //&amp;quot;06811c28-baae-68f8-18b6-38c7819f977f&amp;quot;,&lt;br /&gt;
    &amp;quot;3486effe-7ab4-d955-6b4f-a85a3325a287&amp;quot;,&lt;br /&gt;
    //&amp;quot;9e14c601-a7b0-e0e3-585d-a494c320fa87&amp;quot;,&lt;br /&gt;
    //&amp;quot;80d859fb-dab4-9446-2d79-2d2a9693759d&amp;quot;&lt;br /&gt;
    &amp;quot;59d84d87-6ff5-a1b7-3f3b-d45c09ac05c1&amp;quot;,&lt;br /&gt;
    &amp;quot;a523d079-6e2e-5832-8ac5-30b8c6092508&amp;quot;,&lt;br /&gt;
    &amp;quot;feddf1ac-8176-11fe-0bc1-696544037253&amp;quot;,&lt;br /&gt;
    &amp;quot;12d82751-1cd1-8f25-166c-5e2bcb2ed2d6&amp;quot;,&lt;br /&gt;
    &amp;quot;24cf6699-b625-c06c-b2cd-984b28eb09e0&amp;quot;,&lt;br /&gt;
    &amp;quot;7b71d0bc-d329-b94e-2fa8-0b584ca0e80c&amp;quot;,&lt;br /&gt;
    &amp;quot;d598017c-0f6a-42ec-52f6-899be6e82878&amp;quot;,&lt;br /&gt;
    &amp;quot;ddd57884-5a7b-f658-c8ab-d34df5d6d38e&amp;quot;,&lt;br /&gt;
    &amp;quot;3fda0baa-d584-7d22-ed54-3943ef26c37f&amp;quot;    &lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
list TextureNames = [&lt;br /&gt;
    &amp;quot;Stripes&amp;quot;,&lt;br /&gt;
    &amp;quot;Ghecko&amp;quot;,&lt;br /&gt;
    //&amp;quot;Bleached&amp;quot;,&lt;br /&gt;
    //&amp;quot;Modern&amp;quot;,&lt;br /&gt;
    &amp;quot;LineArt&amp;quot;,&lt;br /&gt;
    //&amp;quot;Flowers&amp;quot;,&lt;br /&gt;
    //&amp;quot;Victorian&amp;quot;&lt;br /&gt;
    &amp;quot;Leaves&amp;quot;,&lt;br /&gt;
    &amp;quot;Old green&amp;quot;,&lt;br /&gt;
    &amp;quot;Classic Leaves&amp;quot;,&lt;br /&gt;
    &amp;quot;African&amp;quot;,&lt;br /&gt;
    &amp;quot;Worn&amp;quot;,&lt;br /&gt;
    &amp;quot;Abstract&amp;quot;,&lt;br /&gt;
    &amp;quot;Elephant&amp;quot;,&lt;br /&gt;
    &amp;quot;Wave&amp;quot;,&lt;br /&gt;
    &amp;quot;Leather&amp;quot;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
string colorStr() {&lt;br /&gt;
    return &amp;quot;\nCurrent: [ R=&amp;quot;+(string)llRound(100*myColor.x)+&amp;quot;  G=&amp;quot;+(string)llRound(100*myColor.y)+&amp;quot;  B=&amp;quot;+(string)llRound(100*myColor.z)+&amp;quot; ]&amp;quot;;  &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
menuPalette (key id) {    &lt;br /&gt;
    llDialog (id, &amp;quot;Choose a color&amp;quot;+colorStr(), llListSort(Palette,1,TRUE), channel);&lt;br /&gt;
    setListen();&lt;br /&gt;
}&lt;br /&gt;
menuPaletteL (key id) {    &lt;br /&gt;
    llDialog (id, &amp;quot;Choose a color&amp;quot;+colorStr(), llListSort(PaletteLight,1,TRUE), channel);&lt;br /&gt;
}&lt;br /&gt;
menuWoodPalette (key id) {    &lt;br /&gt;
    llDialog (id, &amp;quot;Choose a color&amp;quot;+colorStr(), llListSort(PaletteWood,1,TRUE), channel);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
menuAdjust (key id) {&lt;br /&gt;
    llDialog (id, &amp;quot;Adjust color\nHint: use HUE for small color shifts.&amp;quot;+colorStr(),&lt;br /&gt;
        [&lt;br /&gt;
         &amp;quot;- SATURATION&amp;quot;, &amp;quot;- HUE&amp;quot;, &amp;quot;+ HUE&amp;quot;,&lt;br /&gt;
         &amp;quot;+ SATURATION&amp;quot;, &amp;quot;- BLUE&amp;quot;, &amp;quot;+ BLUE&amp;quot;,&lt;br /&gt;
         &amp;quot;- BRIGHT&amp;quot;, &amp;quot;- GREEN&amp;quot;, &amp;quot;+ GREEN&amp;quot;,&lt;br /&gt;
        &amp;quot;+ BRIGHT&amp;quot;, &amp;quot;- RED&amp;quot;, &amp;quot;+ RED&amp;quot;&lt;br /&gt;
         ],&lt;br /&gt;
         channel);    &lt;br /&gt;
}&lt;br /&gt;
menuColor(key id) {&lt;br /&gt;
    llDialog(id, &amp;quot;Option&amp;quot;, [&amp;quot;Adjust&amp;quot;, &amp;quot;Palette&amp;quot;, &amp;quot;Palette Light&amp;quot;], channel);    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
menuTexture(key id) {&lt;br /&gt;
    /*&lt;br /&gt;
    list l;&lt;br /&gt;
    integer i=llGetListLength(Textures);&lt;br /&gt;
    for (;i;i--) {&lt;br /&gt;
        l+=&amp;quot;Fabric &amp;quot;+(string)i;   &lt;br /&gt;
    }&lt;br /&gt;
    llDialog (id, &amp;quot;Select fabric&amp;quot;, l, channel);&lt;br /&gt;
    */&lt;br /&gt;
    llDialog (id, &amp;quot;Select fabric&amp;quot;, llListSort(TextureNames,1,TRUE), channel);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
scale(float s) {&lt;br /&gt;
    if (s&amp;lt;0.10)&lt;br /&gt;
        return;&lt;br /&gt;
    llSetScale(s*llGetScale());       &lt;br /&gt;
    if (llGetNumberOfPrims()&amp;gt;1) {&lt;br /&gt;
        integer i;&lt;br /&gt;
        for (i=2; i&amp;lt;=llGetNumberOfPrims(); i++) {&lt;br /&gt;
            list l=llGetLinkPrimitiveParams(i, [PRIM_POS_LOCAL, PRIM_SIZE]);&lt;br /&gt;
            //llOwnerSay (&amp;quot;PP:&amp;quot;+(string)l);&lt;br /&gt;
            vector newpos=s*(llList2Vector(l,0));   &lt;br /&gt;
            vector newscale=s*llList2Vector(l,1);   &lt;br /&gt;
            if (newscale==ZERO_VECTOR) //something went wrong&lt;br /&gt;
                return;            &lt;br /&gt;
            llSetLinkPrimitiveParamsFast (i, [PRIM_POS_LOCAL, newpos, PRIM_SIZE, newscale]);            &lt;br /&gt;
        }&lt;br /&gt;
    }    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setColor (vector c) {&lt;br /&gt;
    //check bounds&lt;br /&gt;
    if (c.x &amp;lt; 0) c.x=0;&lt;br /&gt;
    if (c.x &amp;gt; 1) c.x=1;   &lt;br /&gt;
    if (c.y &amp;lt; 0) c.y=0;&lt;br /&gt;
    if (c.y &amp;gt; 1) c.y=1;   &lt;br /&gt;
    if (c.z &amp;lt; 0) c.z=0;&lt;br /&gt;
    if (c.z &amp;gt; 1) c.z=1;   &lt;br /&gt;
    myColor=c;&lt;br /&gt;
    if (llGetNumberOfPrims()==1)&lt;br /&gt;
        llSetColor(myColor, ALL_SIDES);&lt;br /&gt;
    else {&lt;br /&gt;
        integer i;&lt;br /&gt;
        for (i=0; i&amp;lt;=llGetNumberOfPrims(); i++) { //root is 0 or 1, silly SL&lt;br /&gt;
            string d=llList2String(llGetLinkPrimitiveParams(i, [PRIM_DESC]),0);&lt;br /&gt;
            if (-1!=llSubStringIndex(d, &amp;quot;:C+:&amp;quot;))&lt;br /&gt;
                llSetLinkColor(i, myColor, ALL_SIDES);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setColor2 (vector c) {&lt;br /&gt;
    //check bounds&lt;br /&gt;
    if (c.x &amp;lt; 0) c.x=0;&lt;br /&gt;
    if (c.x &amp;gt; 1) c.x=1;   &lt;br /&gt;
    if (c.y &amp;lt; 0) c.y=0;&lt;br /&gt;
    if (c.y &amp;gt; 1) c.y=1;   &lt;br /&gt;
    if (c.z &amp;lt; 0) c.z=0;&lt;br /&gt;
    if (c.z &amp;gt; 1) c.z=1;   &lt;br /&gt;
    myColor=c;&lt;br /&gt;
    if (llGetNumberOfPrims()==1)&lt;br /&gt;
        llSetColor(myColor, ALL_SIDES);&lt;br /&gt;
    else {&lt;br /&gt;
        integer i;&lt;br /&gt;
        for (i=0; i&amp;lt;=llGetNumberOfPrims(); i++) { //root is 0 or 1, silly SL&lt;br /&gt;
            string d=llList2String(llGetLinkPrimitiveParams(i, [PRIM_DESC]),0);&lt;br /&gt;
            if (-1!=llSubStringIndex(d, &amp;quot;:C2+:&amp;quot;))&lt;br /&gt;
                llSetLinkColor(i, myColor, ALL_SIDES);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
setTexture (string texture) {&lt;br /&gt;
    if (llGetNumberOfPrims()==1)&lt;br /&gt;
        llSetTexture(texture, ALL_SIDES);   &lt;br /&gt;
    else {&lt;br /&gt;
        integer i;&lt;br /&gt;
        for (i=0; i&amp;lt;=llGetNumberOfPrims(); i++) { //root is 0 or 1, silly SL&lt;br /&gt;
            string d=llList2String(llGetLinkPrimitiveParams(i, [PRIM_DESC]),0);&lt;br /&gt;
            if (-1!=llSubStringIndex(d, &amp;quot;:T+:&amp;quot;))&lt;br /&gt;
                llSetLinkTexture(i, texture, ALL_SIDES);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setShiny (integer s) {&lt;br /&gt;
        integer i;&lt;br /&gt;
        for (i=0; i&amp;lt;=llGetNumberOfPrims(); i++) { //root is 0 or 1, silly SL&lt;br /&gt;
            string d=llList2String(llGetLinkPrimitiveParams(i, [PRIM_DESC]),0);&lt;br /&gt;
            if (-1!=llSubStringIndex(d, &amp;quot;:S+:&amp;quot;))&lt;br /&gt;
                llSetLinkPrimitiveParams(i, [PRIM_BUMP_SHINY, ALL_SIDES,s, &lt;br /&gt;
                    //existing bumpmap:&lt;br /&gt;
                    llList2Integer(llGetLinkPrimitiveParams(i, [PRIM_BUMP_SHINY, ALL_SIDES]),1)&lt;br /&gt;
                ]);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
setListen() {&lt;br /&gt;
    llListenControl (handle, TRUE);&lt;br /&gt;
    llSetTimerEvent (0.0);&lt;br /&gt;
    llSetTimerEvent (120.0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//funky color conv, tx Sally!&lt;br /&gt;
vector RGB2HSV( vector rgb )&lt;br /&gt;
{&lt;br /&gt;
    float R = rgb.x;&lt;br /&gt;
    if (R&amp;lt;0)        // catch malformed input&lt;br /&gt;
        R=0;&lt;br /&gt;
    else if (R&amp;gt;1)&lt;br /&gt;
        R=1;&lt;br /&gt;
    float G = rgb.y;&lt;br /&gt;
    if (G&amp;lt;0)        // catch malformed input&lt;br /&gt;
        G=0;&lt;br /&gt;
    else if (G&amp;gt;1)&lt;br /&gt;
        G=1;&lt;br /&gt;
    float B = rgb.z;&lt;br /&gt;
    if (B&amp;lt;0)        // catch malformed input&lt;br /&gt;
        B=0;&lt;br /&gt;
    else if (B&amp;gt;1)&lt;br /&gt;
        B=1;&lt;br /&gt;
 &lt;br /&gt;
    float H;&lt;br /&gt;
    float S;&lt;br /&gt;
    float V;&lt;br /&gt;
 &lt;br /&gt;
    list rgbList = [R, G, B]; // list used to get min and max&lt;br /&gt;
 &lt;br /&gt;
    float min;&lt;br /&gt;
    float max;&lt;br /&gt;
    float achromatic;  // =1 if R=G=B&lt;br /&gt;
    float delta;&lt;br /&gt;
 &lt;br /&gt;
    vector hsv;  // the return HSV vector&lt;br /&gt;
 &lt;br /&gt;
    min = llListStatistics(LIST_STAT_MIN, rgbList); //MIN of ( R, G, B );&lt;br /&gt;
    max = llListStatistics(LIST_STAT_MAX, rgbList); //MAX of ( R, G, B );&lt;br /&gt;
    if (R==G &amp;amp;&amp;amp; G==B)&lt;br /&gt;
        achromatic = 1;  // it is a shade of grey, white or black&lt;br /&gt;
    else&lt;br /&gt;
        achromatic = 0;&lt;br /&gt;
 &lt;br /&gt;
    V = max;                    // V = brightness Value form 0 to 1&lt;br /&gt;
    delta = max - min;&lt;br /&gt;
 &lt;br /&gt;
    if( max != 0 )&lt;br /&gt;
        S = delta / max;        // S = saturation from 0 to 1&lt;br /&gt;
    else {&lt;br /&gt;
        // R = G = B = 0        // S = 0, V = 0, H = 0&lt;br /&gt;
        S = 0;                  &lt;br /&gt;
        V = 0;                  &lt;br /&gt;
        H = 0;&lt;br /&gt;
 &lt;br /&gt;
        hsv.x = H;&lt;br /&gt;
        hsv.y = S;&lt;br /&gt;
        hsv.z = V;&lt;br /&gt;
        return hsv;             //H = S = V = 0&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    if (achromatic == 1)&lt;br /&gt;
        H = 0;&lt;br /&gt;
    else if( R == max )&lt;br /&gt;
        H = 0 + ( G - B ) / delta;    // between red &amp;amp; yellow&lt;br /&gt;
    else if( G == max )&lt;br /&gt;
        H = 2 + ( B - R ) / delta;    // between yellow &amp;amp; cyan&lt;br /&gt;
    else&lt;br /&gt;
        H = 4 + ( R - G ) / delta;    // between cyan &amp;amp; red&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
    H *= 60;                          // H is traditionally a figure between 0 and 360 degrees&lt;br /&gt;
    if( H &amp;lt; 0 )&lt;br /&gt;
        H += 360;&lt;br /&gt;
 &lt;br /&gt;
    hsv.x = H;&lt;br /&gt;
    hsv.y = S;&lt;br /&gt;
    hsv.z = V;&lt;br /&gt;
    return hsv;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
vector HSV2RGB( vector hsv )&lt;br /&gt;
{&lt;br /&gt;
    integer i;&lt;br /&gt;
 &lt;br /&gt;
     float H = hsv.x;&lt;br /&gt;
     while (H&amp;lt;0)        // catch malformed H input&lt;br /&gt;
        H+=360;&lt;br /&gt;
     while (H&amp;gt;=360)&lt;br /&gt;
        H-=360;&lt;br /&gt;
     float S = hsv.y;&lt;br /&gt;
     if (S&amp;lt;0)        // catch malformed S input&lt;br /&gt;
    S=0;&lt;br /&gt;
     else if (S&amp;gt;1)&lt;br /&gt;
    S=1;&lt;br /&gt;
     float V = hsv.z;&lt;br /&gt;
     if (V&amp;lt;0)        // catch malformed V input&lt;br /&gt;
    V=0;&lt;br /&gt;
     else if (V&amp;gt;1)&lt;br /&gt;
    V=1;&lt;br /&gt;
 &lt;br /&gt;
    float R;&lt;br /&gt;
    float G;&lt;br /&gt;
    float B;&lt;br /&gt;
 &lt;br /&gt;
    float f;         // variables for calculating base color mixing around the &amp;quot;spectrum circle&amp;quot;&lt;br /&gt;
    float p;&lt;br /&gt;
    float q;&lt;br /&gt;
    float t;&lt;br /&gt;
 &lt;br /&gt;
    vector rgb;&lt;br /&gt;
 &lt;br /&gt;
    if( S == 0 ) {  // achromatic (grey) simply set R,G, &amp;amp; B = Value&lt;br /&gt;
        R = V;&lt;br /&gt;
        G = V;&lt;br /&gt;
        B = V;&lt;br /&gt;
 &lt;br /&gt;
        rgb.x = R;&lt;br /&gt;
        rgb.y = G;&lt;br /&gt;
        rgb.z = B;&lt;br /&gt;
        return rgb;&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    H /= 60;              // Hue factored into range 0 to 5&lt;br /&gt;
    i = llFloor( H );      // integer floor of Hue&lt;br /&gt;
    f = H - i;            // factorial part of H&lt;br /&gt;
 &lt;br /&gt;
    p = V * ( 1 - S );&lt;br /&gt;
    q = V * ( 1 - S * f );&lt;br /&gt;
    t = V * ( 1 - S * ( 1 - f ) );&lt;br /&gt;
 &lt;br /&gt;
    if (i==0){&lt;br /&gt;
        R = V;&lt;br /&gt;
        G = t;&lt;br /&gt;
        B = p;&lt;br /&gt;
    } else if (i==1){&lt;br /&gt;
        R = q;&lt;br /&gt;
        G = V;&lt;br /&gt;
        B = p;&lt;br /&gt;
    } else if (i==2){&lt;br /&gt;
        R = p;&lt;br /&gt;
        G = V;&lt;br /&gt;
        B = t;&lt;br /&gt;
    } else if (i==3){&lt;br /&gt;
        R = p;&lt;br /&gt;
        G = q;&lt;br /&gt;
        B = V;&lt;br /&gt;
    } else if (i==4){&lt;br /&gt;
        R = t;&lt;br /&gt;
        G = p;&lt;br /&gt;
        B = V;&lt;br /&gt;
    } else {       &lt;br /&gt;
        R = V;&lt;br /&gt;
        G = p;&lt;br /&gt;
        B = q;&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    rgb.x = R;&lt;br /&gt;
    rgb.y = G;&lt;br /&gt;
    rgb.z = B;&lt;br /&gt;
 &lt;br /&gt;
    return rgb;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        myColor = llGetColor(ALL_SIDES);&lt;br /&gt;
        integer i;&lt;br /&gt;
        for (i=0; i&amp;lt;=llGetNumberOfPrims(); i++) { //root is 0 or 1, silly SL&lt;br /&gt;
            string d=llList2String(llGetLinkPrimitiveParams(i, [PRIM_DESC]),0);&lt;br /&gt;
            if (-1!=llSubStringIndex(d, &amp;quot;:C+:&amp;quot;)) {&lt;br /&gt;
                myColor=llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_COLOR, ALL_SIDES]),0);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        &lt;br /&gt;
        //llOwnerSay(&amp;quot;Color: &amp;quot;+(string)myColor);&lt;br /&gt;
        channel=10000+llRound(llFrand(320932));&lt;br /&gt;
        handle=llListen(channel, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
        llListenControl(handle, FALSE);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    on_rez(integer n) {&lt;br /&gt;
        llResetScript();   &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    link_message(integer ch, integer n, string data, key id) {&lt;br /&gt;
        if (n==-13335) {&lt;br /&gt;
            //hack.. just don&#039;t flood this please (...)&lt;br /&gt;
            //but we try to get this menu on top of MLP menu&lt;br /&gt;
            //llSleep (1.0);&lt;br /&gt;
            &lt;br /&gt;
            list l=llParseString2List(data, [&amp;quot;:&amp;quot;], []);&lt;br /&gt;
            string d=llList2String(l,0);&lt;br /&gt;
            string p=llList2String(l,1);&lt;br /&gt;
            //interesting, styling command&lt;br /&gt;
            setListen();&lt;br /&gt;
            if (d==&amp;quot;MenuColor&amp;quot;)&lt;br /&gt;
                menuColor(id);&lt;br /&gt;
            else if (d==&amp;quot;MenuTexture&amp;quot;)&lt;br /&gt;
                menuTexture(id);&lt;br /&gt;
            else if (d==&amp;quot;ObjectGrow&amp;quot;)&lt;br /&gt;
                scale(1.05);&lt;br /&gt;
            else if (d==&amp;quot;ObjectShrink&amp;quot;)&lt;br /&gt;
                scale(1.0/1.05);&lt;br /&gt;
            else if (d==&amp;quot;Palette&amp;quot;)&lt;br /&gt;
                menuPalette(id);&lt;br /&gt;
            else if (d==&amp;quot;LightPalette&amp;quot;)&lt;br /&gt;
                menuPaletteL(id);    &lt;br /&gt;
            else if (d==&amp;quot;WoodPalette&amp;quot;)&lt;br /&gt;
                menuWoodPalette(id);    &lt;br /&gt;
            else if (d==&amp;quot;AdjustColor&amp;quot;)&lt;br /&gt;
                menuAdjust(id);&lt;br /&gt;
            else if (d==&amp;quot;SetTexture&amp;quot;) {&lt;br /&gt;
                //we really need a texture handle that&#039;d perfectly fit&lt;br /&gt;
                setTexture(p);   &lt;br /&gt;
            } else if (d==&amp;quot;SetColor&amp;quot;) {&lt;br /&gt;
                setColor ((vector)p);   &lt;br /&gt;
            } else if (d==&amp;quot;SetColor2&amp;quot;) {&lt;br /&gt;
                setColor2 ((vector)p);   &lt;br /&gt;
            } else if (d==&amp;quot;SetAlpha&amp;quot;) {&lt;br /&gt;
                llSetLinkAlpha((integer)p, (float)llList2String(l, 2), ALL_SIDES);   &lt;br /&gt;
            } else if (d==&amp;quot;SetShiny&amp;quot;) {&lt;br /&gt;
                setShiny((integer)p);   &lt;br /&gt;
            } else if (d==&amp;quot;Shiny&amp;quot;) {&lt;br /&gt;
                llSetLinkPrimitiveParams((integer)p, [PRIM_BUMP_SHINY, ALL_SIDES,(integer)llList2String(l,2), &lt;br /&gt;
                    //existing bumpmap:&lt;br /&gt;
                    llList2Integer(llGetLinkPrimitiveParams((integer)p, [PRIM_BUMP_SHINY, ALL_SIDES]),1)&lt;br /&gt;
                ]);&lt;br /&gt;
            } else if (d==&amp;quot;Link___&amp;quot;) {&lt;br /&gt;
                //template for any value on any link..&lt;br /&gt;
                llSetLinkPrimitiveParamsFast((integer)p, [(integer)llList2String(l,2), (float)llList2String(l,3)]);&lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
        }   &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    listen (integer ch, string n, key id, string d) {&lt;br /&gt;
        &lt;br /&gt;
        //only listen to agents&lt;br /&gt;
        if (llGetAgentSize(id)); else return; &lt;br /&gt;
        &lt;br /&gt;
        //user still active; assume no other spam on this channel        &lt;br /&gt;
        setListen();&lt;br /&gt;
        &lt;br /&gt;
        if (d==&amp;quot;&amp;lt;&amp;lt;BACK&amp;quot;)&lt;br /&gt;
            menuColor(id);&lt;br /&gt;
        else if (d==&amp;quot;Adjust&amp;quot;)&lt;br /&gt;
            menuAdjust(id);&lt;br /&gt;
        else if (d==&amp;quot;Palette&amp;quot;)&lt;br /&gt;
            menuPalette(id);&lt;br /&gt;
        else if (d==&amp;quot;Palette Light&amp;quot;)&lt;br /&gt;
            menuPaletteL(id);&lt;br /&gt;
        else {&lt;br /&gt;
            integer i=llListFindList(Palette+PaletteLight, [d]);&lt;br /&gt;
            if (i&amp;gt;=0) {&lt;br /&gt;
                //set color to palette entry&lt;br /&gt;
                setColor(llList2Vector(PaletteC+PaletteL, i));&lt;br /&gt;
                if (-1!=llListFindList(Palette, [d]))&lt;br /&gt;
                    menuPalette(id);&lt;br /&gt;
                else&lt;br /&gt;
                    menuPaletteL(id);&lt;br /&gt;
                return;    &lt;br /&gt;
            }&lt;br /&gt;
            i=llListFindList(PaletteWood, [d]);&lt;br /&gt;
            if (i&amp;gt;=0) {&lt;br /&gt;
                //set color to palette entry&lt;br /&gt;
                setColor2(llList2Vector(PaletteW, i));&lt;br /&gt;
                menuWoodPalette(id);&lt;br /&gt;
                return;    &lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
                  &lt;br /&gt;
            list m=llParseString2List(d, [&amp;quot; &amp;quot;], []);&lt;br /&gt;
            string o=llList2String(m,0);&lt;br /&gt;
            string p=llList2String(m,1);&lt;br /&gt;
            &lt;br /&gt;
            if ((o==&amp;quot;-&amp;quot;) || (o==&amp;quot;+&amp;quot;)) {&lt;br /&gt;
                float f=-1.0;&lt;br /&gt;
                if (o==&amp;quot;+&amp;quot;)&lt;br /&gt;
                    f=1.0;&lt;br /&gt;
                if (p==&amp;quot;BRIGHT&amp;quot;)&lt;br /&gt;
                    setColor(0.05*f*&amp;lt;1,1,1&amp;gt; + myColor);&lt;br /&gt;
                else if (p==&amp;quot;SATURATION&amp;quot;)&lt;br /&gt;
                    //setColor(myColor + 0.05*f*(myColor-&amp;lt;0.55,0.55,0.55&amp;gt;));&lt;br /&gt;
                    setColor (HSV2RGB(&amp;lt;0,0.075*f,0&amp;gt;+RGB2HSV(myColor)));&lt;br /&gt;
                else if (p==&amp;quot;RED&amp;quot;)&lt;br /&gt;
                    setColor(f*&amp;lt;0.05,0,0&amp;gt; + myColor);&lt;br /&gt;
                else if (p==&amp;quot;GREEN&amp;quot;)&lt;br /&gt;
                    setColor(f*&amp;lt;0,0.05,0&amp;gt; + myColor);&lt;br /&gt;
                else if (p==&amp;quot;BLUE&amp;quot;)&lt;br /&gt;
                    setColor(f*&amp;lt;0,0,0.05&amp;gt; + myColor);&lt;br /&gt;
                else if (p==&amp;quot;HUE&amp;quot;)&lt;br /&gt;
                    setColor (HSV2RGB(&amp;lt;15.0*f,0,0&amp;gt;+RGB2HSV(myColor)));&lt;br /&gt;
                menuAdjust(id);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
            /*&lt;br /&gt;
            if (o==&amp;quot;Fabric&amp;quot;) {&lt;br /&gt;
                setTexture(llList2String(Textures, (integer)p-1));&lt;br /&gt;
                menuTexture(id);&lt;br /&gt;
            }&lt;br /&gt;
            */&lt;br /&gt;
            i=llListFindList(TextureNames, [d]);&lt;br /&gt;
            if (i&amp;gt;=0) {&lt;br /&gt;
                setTexture (llList2String(Textures, i));&lt;br /&gt;
                menuTexture(id);   &lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    timer() {&lt;br /&gt;
        llSetTimerEvent(0.0);&lt;br /&gt;
        llListenControl (handle, FALSE);   &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Happy scripting.&lt;/div&gt;</summary>
		<author><name>Tano Toll</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=SimpleMLPStylingScript&amp;diff=1174753</id>
		<title>SimpleMLPStylingScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=SimpleMLPStylingScript&amp;diff=1174753"/>
		<updated>2012-11-22T21:20:29Z</updated>

		<summary type="html">&lt;p&gt;Tano Toll: MLP / TMCP simple styling plugin example&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ok, bit of old and ugly code here. Publishing anyways as example.&lt;br /&gt;
&lt;br /&gt;
What it does. This is an MLP plugin that allows styling of objects. Textures, colors, shinyness. Those are usually enough for most furniture.&lt;br /&gt;
&lt;br /&gt;
Per link, you must describe in the link properties if it is subject to a particular styling paramaters. Those are: Color1, Color2, Texture and Shiny. They are represent as :C+: :C2+: :T+: and :S+:&lt;br /&gt;
So, a linked prim, like a cushion, that is subject to color and texture, would read: :C+:T+:&lt;br /&gt;
Another linked prim, like a wooden base, would be subject to color2 (wood shades) and shininess. It&#039;s description would read :C2+:S+:&lt;br /&gt;
&lt;br /&gt;
You can activate the plugin by sending commands via a linked message on channel 13335&lt;br /&gt;
Example entry in MLP or TMCP notecard:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
MENU Styling | OWNER&lt;br /&gt;
LINKMSG Light Colors |1,-4,-13335,LightPalette&lt;br /&gt;
LINKMSG Dark Colors |1,-4,-13335,Palette&lt;br /&gt;
LINKMSG Adjust Color|1,-4,-13335,AdjustColor&lt;br /&gt;
LINKMSG Fabric|1,-4,-13335,MenuTexture&lt;br /&gt;
LINKMSG Wood Color |1,-4,-13335,WoodPalette&lt;br /&gt;
//LINKMSG SomeTexture|0,-4,-13335,SetTexture:&amp;lt;uuid&amp;gt;&lt;br /&gt;
//LINKMSG Color Menu|1,-4,-13335,MenuColor&lt;br /&gt;
//LINKMSG Gray|0,-4,-13335,SetColor:&amp;lt;0.5,0.5,0.5&amp;gt;&lt;br /&gt;
TOMENU Shadow&lt;br /&gt;
LINKMSG Shiny Wood|0,-4,-13335,SetShiny:3&lt;br /&gt;
LINKMSG Satin Wood|0,-4,-13335,SetShiny:1&lt;br /&gt;
LINKMSG Pale Wood|0,-4,-13335,SetShiny:0&lt;br /&gt;
TOMENU Size&lt;br /&gt;
BACK&lt;br /&gt;
&lt;br /&gt;
MENU Shadow | ALL&lt;br /&gt;
This example sets the root prim&#039;s alpha.. adjust link number to whatever the shadow texture was&lt;br /&gt;
LINKMSG No Shadow|0,-4,-13335,SetAlpha:1:0&lt;br /&gt;
LINKMSG Light Shadow|0,-4,-13335,SetAlpha:1:0.5&lt;br /&gt;
LINKMSG Full Shadow|0,-4,-13335,SetAlpha:1:1.0&lt;br /&gt;
BACK&lt;br /&gt;
&lt;br /&gt;
MENU Size | OWNER&lt;br /&gt;
LINKMSG Grow|0,-4,-13335,ObjectGrow&lt;br /&gt;
LINKMSG Shrink|0,-4,-13335,ObjectShrink&lt;br /&gt;
BACK&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The styling script is as follows, and again, sorry for bit messy code.. Publishing anyways, might post an update.&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
//THIS SCRIPT ASSUMES A FEW THINGS&lt;br /&gt;
//* THAT ITS CALLED / INITIATED BY MLP or something else that invokes a linked message&lt;br /&gt;
//That the root prim is colorable just like all childs&lt;br /&gt;
//That the root prim needs no (re)texturing but all childs do.&lt;br /&gt;
//Must customize this script for color palette, textures, and/or menu stuff you want in or out - no external configuration&lt;br /&gt;
&lt;br /&gt;
//+BRIGHT CONTRAST+ +SATURATION&lt;br /&gt;
//-BRIGHT CONTRAST- -SATURATION&lt;br /&gt;
//+RED //+BLUE //+GREEN&lt;br /&gt;
//-RED //-BLUE //-GREEN&lt;br /&gt;
&lt;br /&gt;
//PALETTE&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
vector myColor; //reads root prim color on startup&lt;br /&gt;
integer channel;&lt;br /&gt;
integer handle;&lt;br /&gt;
&lt;br /&gt;
list Palette=[  &amp;quot;BORDEAUX&amp;quot;, &amp;quot;PINK&amp;quot;, &amp;quot;AQUA&amp;quot;,&lt;br /&gt;
                &amp;quot;TEAL&amp;quot;, &amp;quot;SKY&amp;quot;, &amp;quot;NAVY&amp;quot;, &lt;br /&gt;
                &amp;quot;OKER&amp;quot;, &amp;quot;BROWN&amp;quot;, &amp;quot;CREAM&amp;quot;,&lt;br /&gt;
                &amp;quot;BLACK&amp;quot;, &amp;quot;GREY&amp;quot;, &amp;quot;DARKBROWN&amp;quot;];&lt;br /&gt;
                &lt;br /&gt;
list PaletteC=[ &amp;lt;0.35,0,0&amp;gt;, &amp;lt;1,0.5,0.5&amp;gt;, &amp;lt;0.3,1.0,0.8&amp;gt;,&lt;br /&gt;
                &amp;lt;0,0.35,0.6&amp;gt;, &amp;lt;0.7,0.75,1&amp;gt;, &amp;lt;0,0,0.35&amp;gt;,&lt;br /&gt;
                &amp;lt;0.61,0.6,0.12&amp;gt;, &amp;lt;0.3,0.2,0.05&amp;gt;, &amp;lt;1.0,1.0,0.9&amp;gt;,&lt;br /&gt;
                &amp;lt;0.01,0.01,0.05&amp;gt;, &amp;lt;0.35,0.35,0.35&amp;gt;, &amp;lt;0.12,0.08,0&amp;gt;];&lt;br /&gt;
&lt;br /&gt;
list PaletteLight=[&amp;quot;BLUE1&amp;quot;, &amp;quot;BLUE2&amp;quot;, &amp;quot;BLUE3&amp;quot;,&lt;br /&gt;
                &amp;quot;PINK1&amp;quot;, &amp;quot;PINK2&amp;quot;, &amp;quot;PINK3&amp;quot;, &lt;br /&gt;
                &amp;quot;GREEN1&amp;quot;, &amp;quot;GREEN2&amp;quot;, &amp;quot;CREAM1&amp;quot;,&lt;br /&gt;
                &amp;quot;WHITE&amp;quot;, &amp;quot;GREY2&amp;quot;, &amp;quot;AMBER&amp;quot; ];&lt;br /&gt;
                &lt;br /&gt;
list PaletteL=[ &amp;lt;0.8,0.8,1.0&amp;gt;, &amp;lt;0.9,0.9,1.0&amp;gt;, &amp;lt;0.7,0.8,1.0&amp;gt;,&lt;br /&gt;
                &amp;lt;1.0,0.7,0.7&amp;gt;, &amp;lt;1.0,0.8,0.8&amp;gt;, &amp;lt;1.0,0.9,0.9&amp;gt;,&lt;br /&gt;
                &amp;lt;0.7,1.0,0.7&amp;gt;, &amp;lt;0.82,1.0,0.8&amp;gt;, &amp;lt;1.0,0.960,0.879&amp;gt;,&lt;br /&gt;
                &amp;lt;1.0,1.0,1.0&amp;gt;, &amp;lt;0.75,0.75,0.75&amp;gt;, &amp;lt;1.0, 0.9, 0.6&amp;gt;];&lt;br /&gt;
                &lt;br /&gt;
list PaletteWood =[  &amp;quot;Cherry&amp;quot;, &amp;quot;Oak&amp;quot;, &amp;quot;Mahogany&amp;quot;,&lt;br /&gt;
                    &amp;quot;Pine&amp;quot;, &amp;quot;Ebony&amp;quot;, &amp;quot;Maple&amp;quot;,&lt;br /&gt;
                    &amp;quot;OldOak&amp;quot;, &amp;quot;Rosewood&amp;quot;, &amp;quot;Elm&amp;quot;,&lt;br /&gt;
                    &amp;quot;Walnut&amp;quot;, &amp;quot;DarkWalnut&amp;quot;, &amp;quot;Onyx&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
list PaletteW=[ &amp;lt;0.6,0.28,0.18&amp;gt;, &amp;lt;0.62,0.41,0.21&amp;gt;, &amp;lt;0.26,0.08,0.05&amp;gt;,&lt;br /&gt;
                &amp;lt;0.76,0.53,0.19&amp;gt;, &amp;lt;0.12,0.11,0.11&amp;gt;, &amp;lt;0.77,0.45,0.26&amp;gt;,&lt;br /&gt;
                &amp;lt;0.59,0.4,0.24&amp;gt;, &amp;lt;0.3,0.15,0.15&amp;gt;, &amp;lt;0.4,0.25,0.2&amp;gt;,&lt;br /&gt;
                &amp;lt;0.5,0.40,0.28&amp;gt;, &amp;lt;0.29,0.14,0.05&amp;gt;, &amp;lt;0.22,0.19,0.14&amp;gt;];&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
list Textures = [&lt;br /&gt;
    &amp;quot;d14c73dd-9844-3fec-3405-c2cfa6cfae92&amp;quot;,&lt;br /&gt;
    &amp;quot;29e827fe-6d57-e155-eaed-236a58b71244&amp;quot;,&lt;br /&gt;
    //&amp;quot;1ae6c524-9a2e-b3a5-6349-4b99dfd861a3&amp;quot;,&lt;br /&gt;
    //&amp;quot;06811c28-baae-68f8-18b6-38c7819f977f&amp;quot;,&lt;br /&gt;
    &amp;quot;3486effe-7ab4-d955-6b4f-a85a3325a287&amp;quot;,&lt;br /&gt;
    //&amp;quot;9e14c601-a7b0-e0e3-585d-a494c320fa87&amp;quot;,&lt;br /&gt;
    //&amp;quot;80d859fb-dab4-9446-2d79-2d2a9693759d&amp;quot;&lt;br /&gt;
    &amp;quot;59d84d87-6ff5-a1b7-3f3b-d45c09ac05c1&amp;quot;,&lt;br /&gt;
    &amp;quot;a523d079-6e2e-5832-8ac5-30b8c6092508&amp;quot;,&lt;br /&gt;
    &amp;quot;feddf1ac-8176-11fe-0bc1-696544037253&amp;quot;,&lt;br /&gt;
    &amp;quot;12d82751-1cd1-8f25-166c-5e2bcb2ed2d6&amp;quot;,&lt;br /&gt;
    &amp;quot;24cf6699-b625-c06c-b2cd-984b28eb09e0&amp;quot;,&lt;br /&gt;
    &amp;quot;7b71d0bc-d329-b94e-2fa8-0b584ca0e80c&amp;quot;,&lt;br /&gt;
    &amp;quot;d598017c-0f6a-42ec-52f6-899be6e82878&amp;quot;,&lt;br /&gt;
    &amp;quot;ddd57884-5a7b-f658-c8ab-d34df5d6d38e&amp;quot;,&lt;br /&gt;
    &amp;quot;3fda0baa-d584-7d22-ed54-3943ef26c37f&amp;quot;    &lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
list TextureNames = [&lt;br /&gt;
    &amp;quot;Stripes&amp;quot;,&lt;br /&gt;
    &amp;quot;Ghecko&amp;quot;,&lt;br /&gt;
    //&amp;quot;Bleached&amp;quot;,&lt;br /&gt;
    //&amp;quot;Modern&amp;quot;,&lt;br /&gt;
    &amp;quot;LineArt&amp;quot;,&lt;br /&gt;
    //&amp;quot;Flowers&amp;quot;,&lt;br /&gt;
    //&amp;quot;Victorian&amp;quot;&lt;br /&gt;
    &amp;quot;Leaves&amp;quot;,&lt;br /&gt;
    &amp;quot;Old green&amp;quot;,&lt;br /&gt;
    &amp;quot;Classic Leaves&amp;quot;,&lt;br /&gt;
    &amp;quot;African&amp;quot;,&lt;br /&gt;
    &amp;quot;Worn&amp;quot;,&lt;br /&gt;
    &amp;quot;Abstract&amp;quot;,&lt;br /&gt;
    &amp;quot;Elephant&amp;quot;,&lt;br /&gt;
    &amp;quot;Wave&amp;quot;,&lt;br /&gt;
    &amp;quot;Leather&amp;quot;&lt;br /&gt;
    ];&lt;br /&gt;
&lt;br /&gt;
string colorStr() {&lt;br /&gt;
    return &amp;quot;\nCurrent: [ R=&amp;quot;+(string)llRound(100*myColor.x)+&amp;quot;  G=&amp;quot;+(string)llRound(100*myColor.y)+&amp;quot;  B=&amp;quot;+(string)llRound(100*myColor.z)+&amp;quot; ]&amp;quot;;  &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
menuPalette (key id) {    &lt;br /&gt;
    llDialog (id, &amp;quot;Choose a color&amp;quot;+colorStr(), llListSort(Palette,1,TRUE), channel);&lt;br /&gt;
    setListen();&lt;br /&gt;
}&lt;br /&gt;
menuPaletteL (key id) {    &lt;br /&gt;
    llDialog (id, &amp;quot;Choose a color&amp;quot;+colorStr(), llListSort(PaletteLight,1,TRUE), channel);&lt;br /&gt;
}&lt;br /&gt;
menuWoodPalette (key id) {    &lt;br /&gt;
    llDialog (id, &amp;quot;Choose a color&amp;quot;+colorStr(), llListSort(PaletteWood,1,TRUE), channel);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
menuAdjust (key id) {&lt;br /&gt;
    llDialog (id, &amp;quot;Adjust color\nHint: use HUE for small color shifts.&amp;quot;+colorStr(),&lt;br /&gt;
        [&lt;br /&gt;
         &amp;quot;- SATURATION&amp;quot;, &amp;quot;- HUE&amp;quot;, &amp;quot;+ HUE&amp;quot;,&lt;br /&gt;
         &amp;quot;+ SATURATION&amp;quot;, &amp;quot;- BLUE&amp;quot;, &amp;quot;+ BLUE&amp;quot;,&lt;br /&gt;
         &amp;quot;- BRIGHT&amp;quot;, &amp;quot;- GREEN&amp;quot;, &amp;quot;+ GREEN&amp;quot;,&lt;br /&gt;
        &amp;quot;+ BRIGHT&amp;quot;, &amp;quot;- RED&amp;quot;, &amp;quot;+ RED&amp;quot;&lt;br /&gt;
         ],&lt;br /&gt;
         channel);    &lt;br /&gt;
}&lt;br /&gt;
menuColor(key id) {&lt;br /&gt;
    llDialog(id, &amp;quot;Option&amp;quot;, [&amp;quot;Adjust&amp;quot;, &amp;quot;Palette&amp;quot;, &amp;quot;Palette Light&amp;quot;], channel);    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
menuTexture(key id) {&lt;br /&gt;
    /*&lt;br /&gt;
    list l;&lt;br /&gt;
    integer i=llGetListLength(Textures);&lt;br /&gt;
    for (;i;i--) {&lt;br /&gt;
        l+=&amp;quot;Fabric &amp;quot;+(string)i;   &lt;br /&gt;
    }&lt;br /&gt;
    llDialog (id, &amp;quot;Select fabric&amp;quot;, l, channel);&lt;br /&gt;
    */&lt;br /&gt;
    llDialog (id, &amp;quot;Select fabric&amp;quot;, llListSort(TextureNames,1,TRUE), channel);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
scale(float s) {&lt;br /&gt;
    if (s&amp;lt;0.10)&lt;br /&gt;
        return;&lt;br /&gt;
    llSetScale(s*llGetScale());       &lt;br /&gt;
    if (llGetNumberOfPrims()&amp;gt;1) {&lt;br /&gt;
        integer i;&lt;br /&gt;
        for (i=2; i&amp;lt;=llGetNumberOfPrims(); i++) {&lt;br /&gt;
            list l=llGetLinkPrimitiveParams(i, [PRIM_POS_LOCAL, PRIM_SIZE]);&lt;br /&gt;
            //llOwnerSay (&amp;quot;PP:&amp;quot;+(string)l);&lt;br /&gt;
            vector newpos=s*(llList2Vector(l,0));   &lt;br /&gt;
            vector newscale=s*llList2Vector(l,1);   &lt;br /&gt;
            if (newscale==ZERO_VECTOR) //something went wrong&lt;br /&gt;
                return;            &lt;br /&gt;
            llSetLinkPrimitiveParamsFast (i, [PRIM_POS_LOCAL, newpos, PRIM_SIZE, newscale]);            &lt;br /&gt;
        }&lt;br /&gt;
    }    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setColor (vector c) {&lt;br /&gt;
    //check bounds&lt;br /&gt;
    if (c.x &amp;lt; 0) c.x=0;&lt;br /&gt;
    if (c.x &amp;gt; 1) c.x=1;   &lt;br /&gt;
    if (c.y &amp;lt; 0) c.y=0;&lt;br /&gt;
    if (c.y &amp;gt; 1) c.y=1;   &lt;br /&gt;
    if (c.z &amp;lt; 0) c.z=0;&lt;br /&gt;
    if (c.z &amp;gt; 1) c.z=1;   &lt;br /&gt;
    myColor=c;&lt;br /&gt;
    if (llGetNumberOfPrims()==1)&lt;br /&gt;
        llSetColor(myColor, ALL_SIDES);&lt;br /&gt;
    else {&lt;br /&gt;
        integer i;&lt;br /&gt;
        for (i=0; i&amp;lt;=llGetNumberOfPrims(); i++) { //root is 0 or 1, silly SL&lt;br /&gt;
            string d=llList2String(llGetLinkPrimitiveParams(i, [PRIM_DESC]),0);&lt;br /&gt;
            if (-1!=llSubStringIndex(d, &amp;quot;:C+:&amp;quot;))&lt;br /&gt;
                llSetLinkColor(i, myColor, ALL_SIDES);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setColor2 (vector c) {&lt;br /&gt;
    //check bounds&lt;br /&gt;
    if (c.x &amp;lt; 0) c.x=0;&lt;br /&gt;
    if (c.x &amp;gt; 1) c.x=1;   &lt;br /&gt;
    if (c.y &amp;lt; 0) c.y=0;&lt;br /&gt;
    if (c.y &amp;gt; 1) c.y=1;   &lt;br /&gt;
    if (c.z &amp;lt; 0) c.z=0;&lt;br /&gt;
    if (c.z &amp;gt; 1) c.z=1;   &lt;br /&gt;
    myColor=c;&lt;br /&gt;
    if (llGetNumberOfPrims()==1)&lt;br /&gt;
        llSetColor(myColor, ALL_SIDES);&lt;br /&gt;
    else {&lt;br /&gt;
        integer i;&lt;br /&gt;
        for (i=0; i&amp;lt;=llGetNumberOfPrims(); i++) { //root is 0 or 1, silly SL&lt;br /&gt;
            string d=llList2String(llGetLinkPrimitiveParams(i, [PRIM_DESC]),0);&lt;br /&gt;
            if (-1!=llSubStringIndex(d, &amp;quot;:C2+:&amp;quot;))&lt;br /&gt;
                llSetLinkColor(i, myColor, ALL_SIDES);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
setTexture (string texture) {&lt;br /&gt;
    if (llGetNumberOfPrims()==1)&lt;br /&gt;
        llSetTexture(texture, ALL_SIDES);   &lt;br /&gt;
    else {&lt;br /&gt;
        integer i;&lt;br /&gt;
        for (i=0; i&amp;lt;=llGetNumberOfPrims(); i++) { //root is 0 or 1, silly SL&lt;br /&gt;
            string d=llList2String(llGetLinkPrimitiveParams(i, [PRIM_DESC]),0);&lt;br /&gt;
            if (-1!=llSubStringIndex(d, &amp;quot;:T+:&amp;quot;))&lt;br /&gt;
                llSetLinkTexture(i, texture, ALL_SIDES);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setShiny (integer s) {&lt;br /&gt;
        integer i;&lt;br /&gt;
        for (i=0; i&amp;lt;=llGetNumberOfPrims(); i++) { //root is 0 or 1, silly SL&lt;br /&gt;
            string d=llList2String(llGetLinkPrimitiveParams(i, [PRIM_DESC]),0);&lt;br /&gt;
            if (-1!=llSubStringIndex(d, &amp;quot;:S+:&amp;quot;))&lt;br /&gt;
                llSetLinkPrimitiveParams(i, [PRIM_BUMP_SHINY, ALL_SIDES,s, &lt;br /&gt;
                    //existing bumpmap:&lt;br /&gt;
                    llList2Integer(llGetLinkPrimitiveParams(i, [PRIM_BUMP_SHINY, ALL_SIDES]),1)&lt;br /&gt;
                ]);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
setListen() {&lt;br /&gt;
    llListenControl (handle, TRUE);&lt;br /&gt;
    llSetTimerEvent (0.0);&lt;br /&gt;
    llSetTimerEvent (120.0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//funky color conv, tx Sally!&lt;br /&gt;
vector RGB2HSV( vector rgb )&lt;br /&gt;
{&lt;br /&gt;
    float R = rgb.x;&lt;br /&gt;
    if (R&amp;lt;0)        // catch malformed input&lt;br /&gt;
        R=0;&lt;br /&gt;
    else if (R&amp;gt;1)&lt;br /&gt;
        R=1;&lt;br /&gt;
    float G = rgb.y;&lt;br /&gt;
    if (G&amp;lt;0)        // catch malformed input&lt;br /&gt;
        G=0;&lt;br /&gt;
    else if (G&amp;gt;1)&lt;br /&gt;
        G=1;&lt;br /&gt;
    float B = rgb.z;&lt;br /&gt;
    if (B&amp;lt;0)        // catch malformed input&lt;br /&gt;
        B=0;&lt;br /&gt;
    else if (B&amp;gt;1)&lt;br /&gt;
        B=1;&lt;br /&gt;
 &lt;br /&gt;
    float H;&lt;br /&gt;
    float S;&lt;br /&gt;
    float V;&lt;br /&gt;
 &lt;br /&gt;
    list rgbList = [R, G, B]; // list used to get min and max&lt;br /&gt;
 &lt;br /&gt;
    float min;&lt;br /&gt;
    float max;&lt;br /&gt;
    float achromatic;  // =1 if R=G=B&lt;br /&gt;
    float delta;&lt;br /&gt;
 &lt;br /&gt;
    vector hsv;  // the return HSV vector&lt;br /&gt;
 &lt;br /&gt;
    min = llListStatistics(LIST_STAT_MIN, rgbList); //MIN of ( R, G, B );&lt;br /&gt;
    max = llListStatistics(LIST_STAT_MAX, rgbList); //MAX of ( R, G, B );&lt;br /&gt;
    if (R==G &amp;amp;&amp;amp; G==B)&lt;br /&gt;
        achromatic = 1;  // it is a shade of grey, white or black&lt;br /&gt;
    else&lt;br /&gt;
        achromatic = 0;&lt;br /&gt;
 &lt;br /&gt;
    V = max;                    // V = brightness Value form 0 to 1&lt;br /&gt;
    delta = max - min;&lt;br /&gt;
 &lt;br /&gt;
    if( max != 0 )&lt;br /&gt;
        S = delta / max;        // S = saturation from 0 to 1&lt;br /&gt;
    else {&lt;br /&gt;
        // R = G = B = 0        // S = 0, V = 0, H = 0&lt;br /&gt;
        S = 0;                  &lt;br /&gt;
        V = 0;                  &lt;br /&gt;
        H = 0;&lt;br /&gt;
 &lt;br /&gt;
        hsv.x = H;&lt;br /&gt;
        hsv.y = S;&lt;br /&gt;
        hsv.z = V;&lt;br /&gt;
        return hsv;             //H = S = V = 0&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    if (achromatic == 1)&lt;br /&gt;
        H = 0;&lt;br /&gt;
    else if( R == max )&lt;br /&gt;
        H = 0 + ( G - B ) / delta;    // between red &amp;amp; yellow&lt;br /&gt;
    else if( G == max )&lt;br /&gt;
        H = 2 + ( B - R ) / delta;    // between yellow &amp;amp; cyan&lt;br /&gt;
    else&lt;br /&gt;
        H = 4 + ( R - G ) / delta;    // between cyan &amp;amp; red&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
    H *= 60;                          // H is traditionally a figure between 0 and 360 degrees&lt;br /&gt;
    if( H &amp;lt; 0 )&lt;br /&gt;
        H += 360;&lt;br /&gt;
 &lt;br /&gt;
    hsv.x = H;&lt;br /&gt;
    hsv.y = S;&lt;br /&gt;
    hsv.z = V;&lt;br /&gt;
    return hsv;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
vector HSV2RGB( vector hsv )&lt;br /&gt;
{&lt;br /&gt;
    integer i;&lt;br /&gt;
 &lt;br /&gt;
     float H = hsv.x;&lt;br /&gt;
     while (H&amp;lt;0)        // catch malformed H input&lt;br /&gt;
        H+=360;&lt;br /&gt;
     while (H&amp;gt;=360)&lt;br /&gt;
        H-=360;&lt;br /&gt;
     float S = hsv.y;&lt;br /&gt;
     if (S&amp;lt;0)        // catch malformed S input&lt;br /&gt;
    S=0;&lt;br /&gt;
     else if (S&amp;gt;1)&lt;br /&gt;
    S=1;&lt;br /&gt;
     float V = hsv.z;&lt;br /&gt;
     if (V&amp;lt;0)        // catch malformed V input&lt;br /&gt;
    V=0;&lt;br /&gt;
     else if (V&amp;gt;1)&lt;br /&gt;
    V=1;&lt;br /&gt;
 &lt;br /&gt;
    float R;&lt;br /&gt;
    float G;&lt;br /&gt;
    float B;&lt;br /&gt;
 &lt;br /&gt;
    float f;         // variables for calculating base color mixing around the &amp;quot;spectrum circle&amp;quot;&lt;br /&gt;
    float p;&lt;br /&gt;
    float q;&lt;br /&gt;
    float t;&lt;br /&gt;
 &lt;br /&gt;
    vector rgb;&lt;br /&gt;
 &lt;br /&gt;
    if( S == 0 ) {  // achromatic (grey) simply set R,G, &amp;amp; B = Value&lt;br /&gt;
        R = V;&lt;br /&gt;
        G = V;&lt;br /&gt;
        B = V;&lt;br /&gt;
 &lt;br /&gt;
        rgb.x = R;&lt;br /&gt;
        rgb.y = G;&lt;br /&gt;
        rgb.z = B;&lt;br /&gt;
        return rgb;&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    H /= 60;              // Hue factored into range 0 to 5&lt;br /&gt;
    i = llFloor( H );      // integer floor of Hue&lt;br /&gt;
    f = H - i;            // factorial part of H&lt;br /&gt;
 &lt;br /&gt;
    p = V * ( 1 - S );&lt;br /&gt;
    q = V * ( 1 - S * f );&lt;br /&gt;
    t = V * ( 1 - S * ( 1 - f ) );&lt;br /&gt;
 &lt;br /&gt;
    if (i==0){&lt;br /&gt;
        R = V;&lt;br /&gt;
        G = t;&lt;br /&gt;
        B = p;&lt;br /&gt;
    } else if (i==1){&lt;br /&gt;
        R = q;&lt;br /&gt;
        G = V;&lt;br /&gt;
        B = p;&lt;br /&gt;
    } else if (i==2){&lt;br /&gt;
        R = p;&lt;br /&gt;
        G = V;&lt;br /&gt;
        B = t;&lt;br /&gt;
    } else if (i==3){&lt;br /&gt;
        R = p;&lt;br /&gt;
        G = q;&lt;br /&gt;
        B = V;&lt;br /&gt;
    } else if (i==4){&lt;br /&gt;
        R = t;&lt;br /&gt;
        G = p;&lt;br /&gt;
        B = V;&lt;br /&gt;
    } else {       &lt;br /&gt;
        R = V;&lt;br /&gt;
        G = p;&lt;br /&gt;
        B = q;&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    rgb.x = R;&lt;br /&gt;
    rgb.y = G;&lt;br /&gt;
    rgb.z = B;&lt;br /&gt;
 &lt;br /&gt;
    return rgb;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        myColor = llGetColor(ALL_SIDES);&lt;br /&gt;
        integer i;&lt;br /&gt;
        for (i=0; i&amp;lt;=llGetNumberOfPrims(); i++) { //root is 0 or 1, silly SL&lt;br /&gt;
            string d=llList2String(llGetLinkPrimitiveParams(i, [PRIM_DESC]),0);&lt;br /&gt;
            if (-1!=llSubStringIndex(d, &amp;quot;:C+:&amp;quot;)) {&lt;br /&gt;
                myColor=llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_COLOR, ALL_SIDES]),0);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        &lt;br /&gt;
        //llOwnerSay(&amp;quot;Color: &amp;quot;+(string)myColor);&lt;br /&gt;
        channel=10000+llRound(llFrand(320932));&lt;br /&gt;
        handle=llListen(channel, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
        llListenControl(handle, FALSE);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    on_rez(integer n) {&lt;br /&gt;
        llResetScript();   &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    link_message(integer ch, integer n, string data, key id) {&lt;br /&gt;
        if (n==-13335) {&lt;br /&gt;
            //hack.. just don&#039;t flood this please (...)&lt;br /&gt;
            //but we try to get this menu on top of MLP menu&lt;br /&gt;
            //llSleep (1.0);&lt;br /&gt;
            &lt;br /&gt;
            list l=llParseString2List(data, [&amp;quot;:&amp;quot;], []);&lt;br /&gt;
            string d=llList2String(l,0);&lt;br /&gt;
            string p=llList2String(l,1);&lt;br /&gt;
            //interesting, styling command&lt;br /&gt;
            setListen();&lt;br /&gt;
            if (d==&amp;quot;MenuColor&amp;quot;)&lt;br /&gt;
                menuColor(id);&lt;br /&gt;
            else if (d==&amp;quot;MenuTexture&amp;quot;)&lt;br /&gt;
                menuTexture(id);&lt;br /&gt;
            else if (d==&amp;quot;ObjectGrow&amp;quot;)&lt;br /&gt;
                scale(1.05);&lt;br /&gt;
            else if (d==&amp;quot;ObjectShrink&amp;quot;)&lt;br /&gt;
                scale(1.0/1.05);&lt;br /&gt;
            else if (d==&amp;quot;Palette&amp;quot;)&lt;br /&gt;
                menuPalette(id);&lt;br /&gt;
            else if (d==&amp;quot;LightPalette&amp;quot;)&lt;br /&gt;
                menuPaletteL(id);    &lt;br /&gt;
            else if (d==&amp;quot;WoodPalette&amp;quot;)&lt;br /&gt;
                menuWoodPalette(id);    &lt;br /&gt;
            else if (d==&amp;quot;AdjustColor&amp;quot;)&lt;br /&gt;
                menuAdjust(id);&lt;br /&gt;
            else if (d==&amp;quot;SetTexture&amp;quot;) {&lt;br /&gt;
                //we really need a texture handle that&#039;d perfectly fit&lt;br /&gt;
                setTexture(p);   &lt;br /&gt;
            } else if (d==&amp;quot;SetColor&amp;quot;) {&lt;br /&gt;
                setColor ((vector)p);   &lt;br /&gt;
            } else if (d==&amp;quot;SetColor2&amp;quot;) {&lt;br /&gt;
                setColor2 ((vector)p);   &lt;br /&gt;
            } else if (d==&amp;quot;SetAlpha&amp;quot;) {&lt;br /&gt;
                llSetLinkAlpha((integer)p, (float)llList2String(l, 2), ALL_SIDES);   &lt;br /&gt;
            } else if (d==&amp;quot;SetShiny&amp;quot;) {&lt;br /&gt;
                setShiny((integer)p);   &lt;br /&gt;
            } else if (d==&amp;quot;Shiny&amp;quot;) {&lt;br /&gt;
                llSetLinkPrimitiveParams((integer)p, [PRIM_BUMP_SHINY, ALL_SIDES,(integer)llList2String(l,2), &lt;br /&gt;
                    //existing bumpmap:&lt;br /&gt;
                    llList2Integer(llGetLinkPrimitiveParams((integer)p, [PRIM_BUMP_SHINY, ALL_SIDES]),1)&lt;br /&gt;
                ]);&lt;br /&gt;
            } else if (d==&amp;quot;Link___&amp;quot;) {&lt;br /&gt;
                //template for any value on any link..&lt;br /&gt;
                llSetLinkPrimitiveParamsFast((integer)p, [(integer)llList2String(l,2), (float)llList2String(l,3)]);&lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
        }   &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    listen (integer ch, string n, key id, string d) {&lt;br /&gt;
        &lt;br /&gt;
        //only listen to agents&lt;br /&gt;
        if (llGetAgentSize(id)); else return; &lt;br /&gt;
        &lt;br /&gt;
        //user still active; assume no other spam on this channel        &lt;br /&gt;
        setListen();&lt;br /&gt;
        &lt;br /&gt;
        if (d==&amp;quot;&amp;lt;&amp;lt;BACK&amp;quot;)&lt;br /&gt;
            menuColor(id);&lt;br /&gt;
        else if (d==&amp;quot;Adjust&amp;quot;)&lt;br /&gt;
            menuAdjust(id);&lt;br /&gt;
        else if (d==&amp;quot;Palette&amp;quot;)&lt;br /&gt;
            menuPalette(id);&lt;br /&gt;
        else if (d==&amp;quot;Palette Light&amp;quot;)&lt;br /&gt;
            menuPaletteL(id);&lt;br /&gt;
        else {&lt;br /&gt;
            integer i=llListFindList(Palette+PaletteLight, [d]);&lt;br /&gt;
            if (i&amp;gt;=0) {&lt;br /&gt;
                //set color to palette entry&lt;br /&gt;
                setColor(llList2Vector(PaletteC+PaletteL, i));&lt;br /&gt;
                if (-1!=llListFindList(Palette, [d]))&lt;br /&gt;
                    menuPalette(id);&lt;br /&gt;
                else&lt;br /&gt;
                    menuPaletteL(id);&lt;br /&gt;
                return;    &lt;br /&gt;
            }&lt;br /&gt;
            i=llListFindList(PaletteWood, [d]);&lt;br /&gt;
            if (i&amp;gt;=0) {&lt;br /&gt;
                //set color to palette entry&lt;br /&gt;
                setColor2(llList2Vector(PaletteW, i));&lt;br /&gt;
                menuWoodPalette(id);&lt;br /&gt;
                return;    &lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
                  &lt;br /&gt;
            list m=llParseString2List(d, [&amp;quot; &amp;quot;], []);&lt;br /&gt;
            string o=llList2String(m,0);&lt;br /&gt;
            string p=llList2String(m,1);&lt;br /&gt;
            &lt;br /&gt;
            if ((o==&amp;quot;-&amp;quot;) || (o==&amp;quot;+&amp;quot;)) {&lt;br /&gt;
                float f=-1.0;&lt;br /&gt;
                if (o==&amp;quot;+&amp;quot;)&lt;br /&gt;
                    f=1.0;&lt;br /&gt;
                if (p==&amp;quot;BRIGHT&amp;quot;)&lt;br /&gt;
                    setColor(0.05*f*&amp;lt;1,1,1&amp;gt; + myColor);&lt;br /&gt;
                else if (p==&amp;quot;SATURATION&amp;quot;)&lt;br /&gt;
                    //setColor(myColor + 0.05*f*(myColor-&amp;lt;0.55,0.55,0.55&amp;gt;));&lt;br /&gt;
                    setColor (HSV2RGB(&amp;lt;0,0.075*f,0&amp;gt;+RGB2HSV(myColor)));&lt;br /&gt;
                else if (p==&amp;quot;RED&amp;quot;)&lt;br /&gt;
                    setColor(f*&amp;lt;0.05,0,0&amp;gt; + myColor);&lt;br /&gt;
                else if (p==&amp;quot;GREEN&amp;quot;)&lt;br /&gt;
                    setColor(f*&amp;lt;0,0.05,0&amp;gt; + myColor);&lt;br /&gt;
                else if (p==&amp;quot;BLUE&amp;quot;)&lt;br /&gt;
                    setColor(f*&amp;lt;0,0,0.05&amp;gt; + myColor);&lt;br /&gt;
                else if (p==&amp;quot;HUE&amp;quot;)&lt;br /&gt;
                    setColor (HSV2RGB(&amp;lt;15.0*f,0,0&amp;gt;+RGB2HSV(myColor)));&lt;br /&gt;
                menuAdjust(id);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
            /*&lt;br /&gt;
            if (o==&amp;quot;Fabric&amp;quot;) {&lt;br /&gt;
                setTexture(llList2String(Textures, (integer)p-1));&lt;br /&gt;
                menuTexture(id);&lt;br /&gt;
            }&lt;br /&gt;
            */&lt;br /&gt;
            i=llListFindList(TextureNames, [d]);&lt;br /&gt;
            if (i&amp;gt;=0) {&lt;br /&gt;
                setTexture (llList2String(Textures, i));&lt;br /&gt;
                menuTexture(id);   &lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    timer() {&lt;br /&gt;
        llSetTimerEvent(0.0);&lt;br /&gt;
        llListenControl (handle, FALSE);   &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Happy scripting.&lt;/div&gt;</summary>
		<author><name>Tano Toll</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=TMCP&amp;diff=1171665</id>
		<title>TMCP</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=TMCP&amp;diff=1171665"/>
		<updated>2012-08-15T19:36:17Z</updated>

		<summary type="html">&lt;p&gt;Tano Toll: /* TMCP Sitmanager */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TMCP - Tano&#039;s MLP Compatible Pose scripts&lt;br /&gt;
*a drop in replacement for MLPv2&lt;br /&gt;
*configuration notecard compatible&lt;br /&gt;
*Since august 14. 2012 released under the open source BSD license&lt;br /&gt;
&lt;br /&gt;
Collection of scripts as of version 0.37 below, or available on marketplace for your convenience https://marketplace.secondlife.com/p/TMCP-Tanos-MLP-Compatible-Pose-Scripts-Source-Edition/2964611&lt;br /&gt;
&lt;br /&gt;
Resident &#039;Camden McAndrews&#039; voluntueered as new maintainer. I hope the MLPv2 team will pick it up.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Features==&lt;br /&gt;
* MLPv2 notecard &amp;amp; plugin compatible&lt;br /&gt;
* Fast &amp;amp; Stable operation&lt;br /&gt;
* Intelligent menu&lt;br /&gt;
* No poseballs&lt;br /&gt;
* Plenty memory for larger animation sets&lt;br /&gt;
&lt;br /&gt;
==Limitations==&lt;br /&gt;
* No facial animations (yet)&lt;br /&gt;
* No properties&lt;br /&gt;
(Both limitations are relative easily added, yet not implemented in version 0.37)&lt;br /&gt;
&lt;br /&gt;
==TMCP Sitmanager==&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
//keeps track of sitted target, position them and animate them.&lt;br /&gt;
&lt;br /&gt;
list animPool; //pool of scripts that are able to pose targets&lt;br /&gt;
&lt;br /&gt;
list poolCache; //try re-use same script for same agent, to avoid reasking permissions&lt;br /&gt;
&lt;br /&gt;
list sitted; //strided, holds: AGENT_KEY, logical offset (`ball number`), [animscript?], current animation?, current position?&lt;br /&gt;
integer sittedStride=3;&lt;br /&gt;
&lt;br /&gt;
list sittedAgents;&lt;br /&gt;
list sitScripts;&lt;br /&gt;
&lt;br /&gt;
integer MSG_AGENT_UNSIT = 380;&lt;br /&gt;
integer MSG_ALL_UNSIT =381;&lt;br /&gt;
integer MSG_DISABLE_SITTING =382;&lt;br /&gt;
integer MSG_REGISTER_SITSCRIPT =383;&lt;br /&gt;
integer MSG_QUERY_SITSCRIPT = 385;&lt;br /&gt;
integer MSG_RESET =0;&lt;br /&gt;
integer MSG_ENABLE_SITTING=0;&lt;br /&gt;
integer MSG_SET_SITTARGET=375;&lt;br /&gt;
integer MSG_PLAY_ANIM=390;&lt;br /&gt;
integer MSG_STOP_ANIM=391;&lt;br /&gt;
integer MSG_AGENT_PLAY_ANIM=395; // to notify the slave script&lt;br /&gt;
integer MSG_AGENT_STOP_ANIM=396;&lt;br /&gt;
integer MSG_ATTACH_AGENT = 398;&lt;br /&gt;
integer MSG_DETACH_AGENT = 399;&lt;br /&gt;
integer MSG_RUN_ANIMS=379;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_STOP=353;&lt;br /&gt;
integer MSG_DO_SWAP=354;&lt;br /&gt;
integer MSG_MENU_SWAP=355; &lt;br /&gt;
&lt;br /&gt;
integer MSG_MENU_META=333;&lt;br /&gt;
&lt;br /&gt;
integer MSG_MLP_SITTED=-11000;&lt;br /&gt;
integer MSG_MLP_UNSITTED=-11001;&lt;br /&gt;
&lt;br /&gt;
integer MSG_MODE_BALLUSERS=366;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_DEFAULT_POSE = 358;&lt;br /&gt;
&lt;br /&gt;
integer MSG_RLV_GRAB=308;&lt;br /&gt;
integer MSG_RLV_RELEASE=309;&lt;br /&gt;
integer MSG_RLV_VICTIM_LIST=307;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_MENU_CURRENTMENU = 305;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//keys to controlling:&lt;br /&gt;
//animname+index is key to both real animation name and it&#039;s position.&lt;br /&gt;
&lt;br /&gt;
list agentAnims;&lt;br /&gt;
&lt;br /&gt;
list agentScripts;&lt;br /&gt;
list agentScriptCache;&lt;br /&gt;
&lt;br /&gt;
list agentPoseIdx;&lt;br /&gt;
&lt;br /&gt;
list usedIndexes; //logical pose positions, register in here.&lt;br /&gt;
&lt;br /&gt;
integer MAX_SITTING=1;&lt;br /&gt;
&lt;br /&gt;
string currentAnim;&lt;br /&gt;
integer currentAnimSeats;&lt;br /&gt;
&lt;br /&gt;
list menuMeta;&lt;br /&gt;
&lt;br /&gt;
integer mode_ballusers;&lt;br /&gt;
&lt;br /&gt;
key grabberID;&lt;br /&gt;
&lt;br /&gt;
list potentionalVictims;&lt;br /&gt;
list victimsWithRelay;&lt;br /&gt;
&lt;br /&gt;
list grabbingVictims; //commanded to, but not yet suited&lt;br /&gt;
list grabbedVictims; //victims tagged as victim, sitted&lt;br /&gt;
&lt;br /&gt;
integer CAPTURE_RANGE = 35;&lt;br /&gt;
integer RELAY_CHANNEL = -1812221819;&lt;br /&gt;
integer relay_handle;&lt;br /&gt;
&lt;br /&gt;
integer timer_reason_versioncheck;&lt;br /&gt;
integer rlv_victim_dialog_handle;&lt;br /&gt;
integer rlv_victim_dialog_channel;&lt;br /&gt;
&lt;br /&gt;
integer timer_versioncheck=50;&lt;br /&gt;
integer timer_closechannel=51;&lt;br /&gt;
integer timer_closechannel2=53;&lt;br /&gt;
integer timer_defaultpose=52;&lt;br /&gt;
integer timer_cleargrabbing=55;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
assignScript (key id) {&lt;br /&gt;
    integer i=llListFindList (agentScripts, [id]);&lt;br /&gt;
    if (i&amp;gt;=0) //agent already got assignment&lt;br /&gt;
        return;    &lt;br /&gt;
    i=llListFindList (agentScriptCache, [id]);&lt;br /&gt;
    string candidate;&lt;br /&gt;
    if (i&amp;gt;=0) {&lt;br /&gt;
        candidate=llList2String(agentScriptCache, i+1);&lt;br /&gt;
        if (-1!=llListFindList(agentScripts, [candidate]))&lt;br /&gt;
            candidate=&amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    if (candidate);else {&lt;br /&gt;
        //try to find a new one&lt;br /&gt;
        for (i=0; i&amp;lt;llGetListLength(sitScripts); i++) {&lt;br /&gt;
            string ss=llList2String(sitScripts, i);&lt;br /&gt;
            if (-1==llListFindList(agentScripts, [ss])) {//found free one&lt;br /&gt;
                candidate=ss;   &lt;br /&gt;
                jump break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        @break;        &lt;br /&gt;
    }&lt;br /&gt;
    if (candidate) {&lt;br /&gt;
        agentScripts+=[id, candidate];&lt;br /&gt;
        i=llListFindList (agentScriptCache, [candidate]);&lt;br /&gt;
        if (-1&amp;lt;i) &lt;br /&gt;
            agentScriptCache=llDeleteSubList(agentScriptCache, i-1, i);    &lt;br /&gt;
        agentScriptCache+=[id, candidate];&lt;br /&gt;
        //llOwnerSay ((string)id+&amp;quot; attached to &amp;quot;+candidate);&lt;br /&gt;
        llMessageLinked(LINK_THIS, MSG_ATTACH_AGENT, candidate, id);&lt;br /&gt;
    } else {&lt;br /&gt;
        llRegionSayTo (id, 0, &amp;quot;Sorry, but there is no available script to animate your avatar.&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer assignPoseIdx (key id) {&lt;br /&gt;
    //start counting at 1.. just because we can.&lt;br /&gt;
    integer i=llListFindList (agentPoseIdx, [id]);&lt;br /&gt;
    if (-1&amp;lt;i)&lt;br /&gt;
        return llList2Integer(agentPoseIdx, i+1); //agent already got a pose assigned&lt;br /&gt;
    for (i=1; i&amp;lt;100; i++) {&lt;br /&gt;
        if (-1==llListFindList(agentPoseIdx, [i])) //found empty one&lt;br /&gt;
        {&lt;br /&gt;
            agentPoseIdx+=[id, i];   &lt;br /&gt;
            //llInstantMessage (id, &amp;quot;You are assigned to pose index &amp;quot;+(string)i);&lt;br /&gt;
            return i;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
dropAgent (key id) {&lt;br /&gt;
    //clean up stuff agent had&lt;br /&gt;
       &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
stopAnims(key id) {&lt;br /&gt;
    llMessageLinked (LINK_THIS, MSG_AGENT_STOP_ANIM, &amp;quot;&amp;quot;, id);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
applyAnims() {&lt;br /&gt;
    //apply animation (and position?) for all agents involved&lt;br /&gt;
    &lt;br /&gt;
    //send list of keys with indexes to position. it should know which anim is current.&lt;br /&gt;
    llMessageLinked (LINK_THIS, MSG_RUN_ANIMS, llList2CSV(agentPoseIdx), &amp;quot;&amp;quot;);&lt;br /&gt;
    //llOwnerSay (&amp;quot;anims/poses &amp;quot;+llList2CSV(agentPoseIdx));&lt;br /&gt;
       &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
cleanUp(key id) {&lt;br /&gt;
    stopAnims(id);&lt;br /&gt;
    integer i=llListFindList (agentScripts, [id]);&lt;br /&gt;
    if (-1&amp;lt;i)&lt;br /&gt;
        agentScripts = llDeleteSubList (agentScripts, i, i+1);&lt;br /&gt;
    i=llListFindList (agentPoseIdx, [id]);&lt;br /&gt;
    if (-1&amp;lt;i)&lt;br /&gt;
        agentPoseIdx = llDeleteSubList (agentPoseIdx, i, i+1);&lt;br /&gt;
&lt;br /&gt;
    i=llListFindList (grabbedVictims, [id]);&lt;br /&gt;
    if (-1&amp;lt;i)&lt;br /&gt;
        grabbedVictims = llDeleteSubList (grabbedVictims, i, i);&lt;br /&gt;
           &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setSitTarget() {&lt;br /&gt;
  //needs pose info.. so we calculate the first available index, and match info with current pose.. it&#039;s for position script, i think.&lt;br /&gt;
    //linkedmessage (setsittarget, [posename,] index)..    &lt;br /&gt;
    //posename might be cached by positioner and/or set to defaults.&lt;br /&gt;
    integer idx=1;&lt;br /&gt;
    //find first available&lt;br /&gt;
    while (-1&amp;lt;llListFindList(agentPoseIdx, [idx]))&lt;br /&gt;
        idx++;&lt;br /&gt;
    if (idx&amp;gt;MAX_SITTING) {&lt;br /&gt;
        llSitTarget (ZERO_VECTOR, ZERO_ROTATION/llGetRot());   &lt;br /&gt;
    } else {&lt;br /&gt;
        llSitTarget (&amp;lt;0,0,0.01&amp;gt;, ZERO_ROTATION/llGetRot()); //backup option.&lt;br /&gt;
        llMessageLinked(LINK_THIS, MSG_SET_SITTARGET, (string)idx, &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer maySit(key id) {&lt;br /&gt;
    if (!mode_ballusers) //everyone&lt;br /&gt;
        return TRUE;&lt;br /&gt;
    if (id==llGetOwner()) //always&lt;br /&gt;
        return TRUE;&lt;br /&gt;
    if (mode_ballusers==1) //group&lt;br /&gt;
        return llSameGroup(id);&lt;br /&gt;
    return FALSE; //nope&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
broadcastVictims() {&lt;br /&gt;
    llMessageLinked (LINK_THIS, MSG_RLV_VICTIM_LIST, llList2CSV(grabbedVictims), &amp;quot;&amp;quot;);   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
requestMenu(key id) {&lt;br /&gt;
    llMessageLinked (LINK_THIS, MSG_DO_MENU_CURRENTMENU, &amp;quot;&amp;quot;, id);      &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
inventarise() {&lt;br /&gt;
    //someone sitted or unsitted. do the bookkeeping&lt;br /&gt;
    list agents;&lt;br /&gt;
    integer i;&lt;br /&gt;
    &lt;br /&gt;
    //get sitted avatars&lt;br /&gt;
    for (i=0; i&amp;lt;=llGetNumberOfPrims(); i++) {&lt;br /&gt;
        key id=llGetLinkKey(i);&lt;br /&gt;
        if (llGetAgentSize(id)) {&lt;br /&gt;
            //this is an agent..&lt;br /&gt;
            agents+=id;&lt;br /&gt;
            if (-1!=llListFindList(grabbingVictims, [id])) {&lt;br /&gt;
                //grabbingVictims=[]; //should really do this somewhere else&lt;br /&gt;
                if (-1==llListFindList(grabbedVictims, [id])) {&lt;br /&gt;
                    rlv_lock(id);&lt;br /&gt;
                    grabbedVictims+=id;&lt;br /&gt;
                    broadcastVictims();&lt;br /&gt;
                }&lt;br /&gt;
            }   &lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //now cross reference against existing agents&lt;br /&gt;
    //first see, who&#039;s all gone&lt;br /&gt;
    for (i=0;i&amp;lt;llGetListLength(sittedAgents); i++) {&lt;br /&gt;
        key id=llList2Key(sittedAgents, i);&lt;br /&gt;
        if (-1==llListFindList(agents, [id])) {&lt;br /&gt;
            //agent unsitted, remove him&lt;br /&gt;
            msgUnsit(id, llList2Integer(agentPoseIdx, llListFindList(agentPoseIdx, [id])+1));&lt;br /&gt;
            if (-1!=llListFindList(grabbedVictims, [id])) {&lt;br /&gt;
                //rlv catch, unlock it&lt;br /&gt;
                rlv_release(id);   &lt;br /&gt;
            }&lt;br /&gt;
            cleanUp(id);                           &lt;br /&gt;
            broadcastVictims();            &lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //now, lets see who&#039;s all added&lt;br /&gt;
    for (i=0;i&amp;lt;llGetListLength(agents); i++) {&lt;br /&gt;
        key id=llList2Key(agents, i);&lt;br /&gt;
        if (-1==llListFindList(sittedAgents, [id])) {&lt;br /&gt;
            //freshy added, assign it a script, if possible, and a logical offset&lt;br /&gt;
            if (maySit(id)) {&lt;br /&gt;
                assignScript(id);&lt;br /&gt;
                msgSit(id, assignPoseIdx(id));&lt;br /&gt;
            } else {&lt;br /&gt;
                llUnSit(id);&lt;br /&gt;
                llWhisper (0, &amp;quot;Sorry &amp;quot;+llKey2Name(id)+&amp;quot; but you cannot use this object.&amp;quot;);&lt;br /&gt;
            }&lt;br /&gt;
            //play anim &lt;br /&gt;
            &lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//    if (sittedAgents != agents)&lt;br /&gt;
//        setSitTarget();    &lt;br /&gt;
    sittedAgents = agents;&lt;br /&gt;
    setSitTarget();&lt;br /&gt;
    applyAnims();&lt;br /&gt;
    &lt;br /&gt;
    // default pose switching on idle&lt;br /&gt;
    if (agents==[])&lt;br /&gt;
        scheduleEvent (timer_defaultpose, 120, &amp;quot;&amp;quot;);&lt;br /&gt;
    else&lt;br /&gt;
        cancelEvent (timer_defaultpose);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
makeSwapMenu(key id, integer channel) {&lt;br /&gt;
    //offer nice swap menu&lt;br /&gt;
    //list sitted avatars&lt;br /&gt;
    string text=&amp;quot;&amp;quot;;&lt;br /&gt;
    integer i;&lt;br /&gt;
    integer m=10;&lt;br /&gt;
    list buttons=[&amp;quot;&amp;lt;BACK&amp;quot;];&lt;br /&gt;
    if (MAX_SITTING&amp;lt;m)&lt;br /&gt;
        m=MAX_SITTING;&lt;br /&gt;
    for (i=1; i&amp;lt;=m; i++) {&lt;br /&gt;
        integer j=llListFindList(agentPoseIdx, [i]);&lt;br /&gt;
        string agent = &amp;quot;&amp;lt;Nobody&amp;gt;&amp;quot;;&lt;br /&gt;
        key aid;&lt;br /&gt;
        if (-1&amp;lt;j) {&lt;br /&gt;
            aid=llList2Key(agentPoseIdx, j-1);&lt;br /&gt;
            agent=llKey2Name(aid);&lt;br /&gt;
        }&lt;br /&gt;
        text+=(string)i + &amp;quot;. &amp;quot; + llList2String(menuMeta, i) + &amp;quot; &amp;quot;+agent+&amp;quot;\n&amp;quot;;&lt;br /&gt;
                   &lt;br /&gt;
        if (aid!=id)&lt;br /&gt;
            buttons+=[&amp;quot;SWAP::&amp;quot;+(string)i];&lt;br /&gt;
    }&lt;br /&gt;
    llDialog (id, text, buttons, channel);       &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//consideration: send out sit/unsit events or not.. i think, might as well not. in order not to confuse rlv.&lt;br /&gt;
swapAgent (key id, integer newpos) {&lt;br /&gt;
    //llSay (0, &amp;quot;Swapping &amp;quot;+llKey2Name(id)+&amp;quot; to position #&amp;quot;+(string)newpos);&lt;br /&gt;
    integer o=llListFindList(agentPoseIdx, [id]);&lt;br /&gt;
    if (o&amp;lt;0) {&lt;br /&gt;
        //llOwnerSay (&amp;quot;swap key not found &amp;quot;+(string)id);&lt;br /&gt;
        //agent not found. see if we have a rlv target&lt;br /&gt;
        if (llGetListLength(grabbedVictims)) {&lt;br /&gt;
            //just default to first best sitted. Stuff gets complex with multiple RLV but who cares that.&lt;br /&gt;
            id=llList2Key(grabbedVictims,0);&lt;br /&gt;
            o=llListFindList(agentPoseIdx, [id]);&lt;br /&gt;
            if (o&amp;lt;0) //OUCH, should nevah happen&lt;br /&gt;
                return;            &lt;br /&gt;
        }        &lt;br /&gt;
        else return;&lt;br /&gt;
    }&lt;br /&gt;
    integer oldidx=llList2Integer(agentPoseIdx, o+1);&lt;br /&gt;
    if (oldidx==newpos) {&lt;br /&gt;
        llRegionSayTo (id, 0, &amp;quot;You choosen the same position&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    agentPoseIdx=llDeleteSubList(agentPoseIdx, o, o+1);&lt;br /&gt;
    integer topos=llListFindList(agentPoseIdx, [newpos]);&lt;br /&gt;
    if (-1&amp;lt;topos) {&lt;br /&gt;
        agentPoseIdx=llDeleteSubList(agentPoseIdx, topos-1, topos) + [llList2Key(agentPoseIdx, topos-1),oldidx];        &lt;br /&gt;
    }&lt;br /&gt;
    agentPoseIdx += [id, newpos];&lt;br /&gt;
    applyAnims();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsitAll() {&lt;br /&gt;
    integer i;&lt;br /&gt;
    for (i=0; i&amp;lt;=llGetNumberOfPrims(); i++) {&lt;br /&gt;
        key id=llGetLinkKey(i);&lt;br /&gt;
        if (llGetAgentSize(id))&lt;br /&gt;
            llUnSit(id);    &lt;br /&gt;
    }   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
msgSit(key id, integer poseidx) {&lt;br /&gt;
    //we start count at 1, mlp at zero. fix right here&lt;br /&gt;
    llMessageLinked(LINK_THIS, MSG_MLP_SITTED, (string)(poseidx-1), id);   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
msgUnsit(key id, integer poseidx) {&lt;br /&gt;
    //we start count at 1, mlp at zero. fix right here&lt;br /&gt;
    llMessageLinked(LINK_THIS, MSG_MLP_UNSITTED, (string)(poseidx-1), id);   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
log(string t){&lt;br /&gt;
    //llOwnerSay(t);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
RLVGrabMenu(key id) {&lt;br /&gt;
    grabberID = id;&lt;br /&gt;
    llSensor(&amp;quot;&amp;quot;, NULL_KEY, AGENT, CAPTURE_RANGE, TWO_PI);    &lt;br /&gt;
//    llInstantMessage (id, &amp;quot;Scanning ... menu in 5.. 4.. 3..&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
RLVReleaseAll() {&lt;br /&gt;
    integer i;&lt;br /&gt;
    for (i=0; i&amp;lt;llGetListLength(grabbedVictims); i++) {&lt;br /&gt;
        key id=llList2Key(grabbedVictims,i);&lt;br /&gt;
        rlv_release (id);&lt;br /&gt;
        llWhisper (0,&amp;quot;releasing &amp;quot;+llKey2Name(id));&lt;br /&gt;
        //unsit?&lt;br /&gt;
        llUnSit(id);&lt;br /&gt;
    }&lt;br /&gt;
    grabbedVictims=[];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
rlv_checkversion (key id) {&lt;br /&gt;
    rlv_relay(id, &amp;quot;!version=&amp;quot; + (string)1);    //version_handle&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
rlv_capture(key avatar)&lt;br /&gt;
{&lt;br /&gt;
    rlv_relay(avatar, &amp;quot;@sit:&amp;quot; + (string)llGetKey() + &amp;quot;=force&amp;quot;);&lt;br /&gt;
    //llSay (menu_ban_channel, &amp;quot;- &amp;quot;+(string)avatar);    &lt;br /&gt;
    llWhisper (0, llKey2Name(grabberID)+&amp;quot; captures &amp;quot;+llKey2Name(avatar));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
rlv_lock(key avatar)&lt;br /&gt;
{&lt;br /&gt;
    rlv_relay(avatar, &amp;quot;@unsit=n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
rlv_release(key avatar)&lt;br /&gt;
{&lt;br /&gt;
    rlv_relay(avatar, &amp;quot;@unsit=y&amp;quot;);&lt;br /&gt;
    rlv_relay(avatar, &amp;quot;!release&amp;quot;);&lt;br /&gt;
    //llSay (menu_ban_channel, &amp;quot;- &amp;quot;+(string)avatar);    &lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// write a message to the RLV Relay&lt;br /&gt;
rlv_relay(key avatar, string message)&lt;br /&gt;
{&lt;br /&gt;
    if (avatar != NULL_KEY)&lt;br /&gt;
    {&lt;br /&gt;
        llSay(RELAY_CHANNEL, llEscapeURL(llGetObjectName()) + &amp;quot;,&amp;quot; + (string) avatar + &amp;quot;,&amp;quot; + message);&lt;br /&gt;
        log(&amp;quot;RLV: &amp;quot; + llGetObjectName() + &amp;quot;,&amp;quot; + (string) avatar + &amp;quot;,&amp;quot; + message);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//scheduler&lt;br /&gt;
&lt;br /&gt;
list events = [];&lt;br /&gt;
integer nextEvent = 0;&lt;br /&gt;
&lt;br /&gt;
scheduleEvent(integer id, integer time, string data) {&lt;br /&gt;
    //adjust timestamp&lt;br /&gt;
    time+=llGetUnixTime();&lt;br /&gt;
    &lt;br /&gt;
    //cancel any previous requests, this case we only want one per type, really&lt;br /&gt;
    cancelEvent(id);    &lt;br /&gt;
    &lt;br /&gt;
    events = llListSort(events + [time, id, data], 3, TRUE);&lt;br /&gt;
    setTimer(FALSE);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
cancelEvent(integer id) {&lt;br /&gt;
    //reasonable failsafe as long as you don&#039;t use id&#039;s that could be current timestamp.    &lt;br /&gt;
    integer i=llListFindList(events, [id]);&lt;br /&gt;
    if ((-1&amp;lt;i) &amp;amp;&amp;amp; ((i % 3) == 1)) {&lt;br /&gt;
        //it was an id&lt;br /&gt;
        events=llDeleteSubList(events, i-1, i+1);&lt;br /&gt;
        &lt;br /&gt;
        //recurse when found, delete all with said id... ?&lt;br /&gt;
        cancelEvent(id);&lt;br /&gt;
        &lt;br /&gt;
        setTimer(FALSE);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer setTimer(integer executing) {&lt;br /&gt;
    if ((events != []) &amp;gt; 0) { // Are there any list items?&lt;br /&gt;
        integer id = llList2Integer(events, 1);&lt;br /&gt;
 &lt;br /&gt;
        integer time = llList2Integer(events, 0);&lt;br /&gt;
        nextEvent = id;&lt;br /&gt;
 &lt;br /&gt;
        float t = (float)(time - llGetUnixTime());&lt;br /&gt;
        if (t &amp;lt;= 0.0) {&lt;br /&gt;
            if (executing) return TRUE;&lt;br /&gt;
            else t = 0.01;&lt;br /&gt;
        }&lt;br /&gt;
        llSetTimerEvent(t);&lt;br /&gt;
    } else {&lt;br /&gt;
        llSetTimerEvent(0.0);&lt;br /&gt;
        nextEvent = -1;&lt;br /&gt;
    }&lt;br /&gt;
    return FALSE;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
handleEvent(integer id, string data) {&lt;br /&gt;
&lt;br /&gt;
    if (id==timer_versioncheck) {&lt;br /&gt;
            //time to display our dialog&lt;br /&gt;
            if ([]==victimsWithRelay) {&lt;br /&gt;
                llRegionSayTo (grabberID, 0, &amp;quot;No eligible victims found (they must wear a relay).&amp;quot;);&lt;br /&gt;
                requestMenu(grabberID);&lt;br /&gt;
            } else {&lt;br /&gt;
                list nn;&lt;br /&gt;
                integer i;&lt;br /&gt;
                for (i=0; (i&amp;lt;llGetListLength(victimsWithRelay)) &amp;amp;&amp;amp; (i&amp;lt;23); i+=2) {&lt;br /&gt;
                    string s=llKey2Name(llList2Key(victimsWithRelay, i));&lt;br /&gt;
                    if (s)&lt;br /&gt;
                        nn+=llGetSubString(s,0,23);                     &lt;br /&gt;
                }&lt;br /&gt;
                &lt;br /&gt;
                llListenControl(rlv_victim_dialog_handle, TRUE);          &lt;br /&gt;
                scheduleEvent (timer_closechannel, 90, (string)rlv_victim_dialog_handle);&lt;br /&gt;
                llDialog (grabberID, &amp;quot;Choose a victim&amp;quot;, nn, rlv_victim_dialog_channel);&lt;br /&gt;
                //scheduleEvent (timer_versioncheck, 5, &amp;quot;&amp;quot;);                 &lt;br /&gt;
            }  &lt;br /&gt;
&lt;br /&gt;
            //set timer to new timeout&lt;br /&gt;
            &lt;br /&gt;
            //llSetTimerEvent(TIMER_TIMEOUT);&lt;br /&gt;
            //llListenControl (version_handle, FALSE);            &lt;br /&gt;
            //return;   &lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    if ((id==timer_closechannel) || (id==timer_closechannel2)) {&lt;br /&gt;
        llListenControl ((integer)data, FALSE);            &lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    if (id==timer_defaultpose) {&lt;br /&gt;
        llMessageLinked(LINK_THIS, MSG_DO_DEFAULT_POSE, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);        &lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    if (id==timer_cleargrabbing) {&lt;br /&gt;
        grabbingVictims=[];   &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
upgrade() {string self = llGetScriptName(); string basename = self; if (llSubStringIndex(self, &amp;quot; &amp;quot;) &amp;gt;= 0) {integer start = 2; string tail = llGetSubString(self, llStringLength(self) - start, -1); while (llGetSubString(tail, 0, 0) != &amp;quot; &amp;quot;) {start++; tail = llGetSubString(self, llStringLength(self) - start, -1);} if ((integer)tail &amp;gt; 0) {basename = llGetSubString(self, 0, -llStringLength(tail) - 1);}} integer n = llGetInventoryNumber(INVENTORY_SCRIPT); while (n-- &amp;gt; 0) {string item = llGetInventoryName(INVENTORY_SCRIPT, n); if (item != self &amp;amp;&amp;amp; 0 == llSubStringIndex(item, basename)) {llRemoveInventory(item);}}}&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        upgrade();&lt;br /&gt;
        llOwnerSay (&amp;quot;sitmanager memory free : &amp;quot;+(string)llGetFreeMemory());&lt;br /&gt;
        state active;  &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state active {   &lt;br /&gt;
    state_entry() {&lt;br /&gt;
        setSitTarget();&lt;br /&gt;
        llMessageLinked (LINK_THIS, MSG_QUERY_SITSCRIPT, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
        &lt;br /&gt;
        rlv_victim_dialog_channel = 124904342+llFloor(llFrand(42902543));&lt;br /&gt;
        rlv_victim_dialog_handle = llListen(rlv_victim_dialog_channel, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
        llListenControl (rlv_victim_dialog_handle, FALSE); &lt;br /&gt;
        relay_handle=llListen(RELAY_CHANNEL, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
        llListenControl(relay_handle, FALSE);   &lt;br /&gt;
    } &lt;br /&gt;
    link_message(integer sn, integer n, string m, key id) {&lt;br /&gt;
        &lt;br /&gt;
        if (n==MSG_RESET)&lt;br /&gt;
            llResetScript();&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_ENABLE_SITTING) {&lt;br /&gt;
            MAX_SITTING=llGetListLength(sitScripts);&lt;br /&gt;
            setSitTarget();&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_AGENT_UNSIT) {&lt;br /&gt;
            //unsit agent                &lt;br /&gt;
            llUnSit(id);&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_ALL_UNSIT) {&lt;br /&gt;
            //just kick everyone&lt;br /&gt;
            unsitAll();    &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_DISABLE_SITTING) {&lt;br /&gt;
            //state inactive;&lt;br /&gt;
            MAX_SITTING=0;&lt;br /&gt;
            setSitTarget();&lt;br /&gt;
        }        &lt;br /&gt;
        &lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_REGISTER_SITSCRIPT) {&lt;br /&gt;
            if (m)&lt;br /&gt;
            if (INVENTORY_SCRIPT==llGetInventoryType(m))&lt;br /&gt;
            if (-1==llListFindList(sitScripts, [m])) {&lt;br /&gt;
                sitScripts+=m;    &lt;br /&gt;
                MAX_SITTING=llGetListLength(sitScripts);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_PLAY_ANIM) {&lt;br /&gt;
            currentAnim=m;&lt;br /&gt;
            applyAnims();   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_MENU_SWAP) {&lt;br /&gt;
            makeSwapMenu (id, (integer)m);   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_DO_SWAP) {&lt;br /&gt;
            swapAgent(id, (integer)m);   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_MENU_META) {&lt;br /&gt;
            menuMeta=llParseString2List(m, [&amp;quot;|&amp;quot;, &amp;quot; &amp;quot;], []);   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_DO_STOP) {&lt;br /&gt;
            llUnSit(id); //let changed event handle the rest   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_MODE_BALLUSERS) {&lt;br /&gt;
            mode_ballusers=(integer)m;   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_RLV_GRAB) {&lt;br /&gt;
            RLVGrabMenu(id);       &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_RLV_RELEASE) {&lt;br /&gt;
            RLVReleaseAll();&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    changed (integer c) {&lt;br /&gt;
        if (c &amp;amp; CHANGED_LINK) {&lt;br /&gt;
            //don&#039;t even bother about getting sitted or not or leaving..&lt;br /&gt;
            //just fetch all current avatars and match them against our list of known avis&lt;br /&gt;
            inventarise();   &lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    timer() {&lt;br /&gt;
        // Clear timer or it might fire again before we&#039;re done&lt;br /&gt;
        llSetTimerEvent(0.0);&lt;br /&gt;
 &lt;br /&gt;
        do {&lt;br /&gt;
            // Fire the event&lt;br /&gt;
            handleEvent(nextEvent, llList2String(events, 2));&lt;br /&gt;
 &lt;br /&gt;
            // Get rid of the first item as we&#039;ve executed it&lt;br /&gt;
            integer l = events != [];&lt;br /&gt;
            if (l &amp;gt; 0) {&lt;br /&gt;
                if (l &amp;gt; 3)&lt;br /&gt;
                    events = llList2List((events = []) + events, 3, -1);&lt;br /&gt;
                else events = [];&lt;br /&gt;
            }&lt;br /&gt;
 &lt;br /&gt;
            // Prepare the timer for the next event&lt;br /&gt;
        } while (setTimer(TRUE));&lt;br /&gt;
    }    &lt;br /&gt;
    &lt;br /&gt;
    /*&lt;br /&gt;
    timer() {&lt;br /&gt;
        /* default pose.. do somewhere else please&lt;br /&gt;
        llSetTimerEvent(0.);&lt;br /&gt;
        llMessageLinked(LINK_THIS, MSG_DO_DEFAULT_POSE, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);   &lt;br /&gt;
        */&lt;br /&gt;
        /*&lt;br /&gt;
    }&lt;br /&gt;
    */&lt;br /&gt;
    &lt;br /&gt;
    no_sensor()&lt;br /&gt;
    {        &lt;br /&gt;
        llRegionSayTo (grabberID, 0, &amp;quot;No nearby potentional victims found&amp;quot;);&lt;br /&gt;
        requestMenu(grabberID);&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    // some av in sensor range&lt;br /&gt;
    sensor(integer total_number)&lt;br /&gt;
    {&lt;br /&gt;
        //llListenControl (rlv_victim_dialog_handle, TRUE);&lt;br /&gt;
        //scheduleEvent (timer_closechannel, 120, (string)rlv_victim_dialog_handle);&lt;br /&gt;
        llListenControl (relay_handle, TRUE);&lt;br /&gt;
        scheduleEvent (timer_closechannel2, 7, (string)relay_handle);&lt;br /&gt;
        &lt;br /&gt;
        &lt;br /&gt;
        potentionalVictims=[];&lt;br /&gt;
        victimsWithRelay=[];&lt;br /&gt;
        integer i;&lt;br /&gt;
        for(i=0; i &amp;lt; total_number; i++)&lt;br /&gt;
        {&lt;br /&gt;
            key id = llDetectedKey(i);&lt;br /&gt;
            string name = llKey2Name(id);&lt;br /&gt;
            if (llStringLength(name) &amp;gt; 24)&lt;br /&gt;
            {&lt;br /&gt;
                name = llGetSubString(name, 0, 23);&lt;br /&gt;
            }&lt;br /&gt;
            potentionalVictims+=[id, name];&lt;br /&gt;
            rlv_checkversion(id);            &lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        // show dialog if list contains names&lt;br /&gt;
        /*&lt;br /&gt;
        if (llGetListLength(sensor_names) &amp;gt; 0)&lt;br /&gt;
        {&lt;br /&gt;
            llListenControl(dialog_handle, TRUE);&lt;br /&gt;
            llSetTimerEvent(TIMER_TIMEOUT);&lt;br /&gt;
            llDialog(avatar_menu, MSG_CHOOSE_AV, sensor_names, dialog_channel);&lt;br /&gt;
        }&lt;br /&gt;
        */&lt;br /&gt;
        scheduleEvent (timer_versioncheck, 5, (string)grabberID);&lt;br /&gt;
        llRegionSayTo (grabberID, 0, &amp;quot;Verifying &amp;quot;+(string)total_number+&amp;quot; potentional victims. Menu in 5.. 4.. 3..&amp;quot;);          }    &lt;br /&gt;
    &lt;br /&gt;
    listen (integer ch, string n, key id, string m) {&lt;br /&gt;
        if (ch==RELAY_CHANNEL) {&lt;br /&gt;
            if (-1!=llSubStringIndex(m, &amp;quot;version=&amp;quot;)) {//bit dirty, we might catch other objects too&lt;br /&gt;
                //victims+=llGetOwnerKey(id);&lt;br /&gt;
                //victim selected, grab it   &lt;br /&gt;
                victimsWithRelay+=[llGetOwnerKey(id),llGetSubString(llKey2Name(llGetOwnerKey(id)),0,23)];                &lt;br /&gt;
            }            &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (ch==rlv_victim_dialog_channel) {&lt;br /&gt;
            //victim selected, grab it&lt;br /&gt;
            integer i=llListFindList (victimsWithRelay, [m]);&lt;br /&gt;
            if (-1&amp;lt;i) {&lt;br /&gt;
                key vid=llList2Key(victimsWithRelay, i-1);&lt;br /&gt;
                rlv_capture (vid);&lt;br /&gt;
                if (-1==llListFindList(grabbingVictims, [vid])) {&lt;br /&gt;
                    grabbingVictims+=vid;&lt;br /&gt;
                }&lt;br /&gt;
                scheduleEvent (timer_cleargrabbing, 120, (string)id);                &lt;br /&gt;
            }&lt;br /&gt;
            requestMenu(grabberID);   &lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
state inactive {&lt;br /&gt;
    state_entry() {&lt;br /&gt;
        llSitTarget(ZERO_VECTOR, ZERO_ROTATION);&lt;br /&gt;
    }   &lt;br /&gt;
    link_message(integer sn, integer n, string m, key id) {&lt;br /&gt;
        if (n==MSG_RESET)&lt;br /&gt;
            llResetScript();&lt;br /&gt;
        else&lt;br /&gt;
        if (n=MSG_ENABLE_SITTING)&lt;br /&gt;
            state active;&lt;br /&gt;
    }    &lt;br /&gt;
}&lt;br /&gt;
*/&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==TMCP - pose==&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
key ourAgent;&lt;br /&gt;
string currentAnim;&lt;br /&gt;
&lt;br /&gt;
integer hasPerms;&lt;br /&gt;
&lt;br /&gt;
integer MSG_AGENT_PLAY_ANIM=395; // to notify the slave script&lt;br /&gt;
integer MSG_AGENT_STOP_ANIM=396;&lt;br /&gt;
integer MSG_ATTACH_AGENT = 398;&lt;br /&gt;
integer MSG_DETACH_AGENT = 399;&lt;br /&gt;
integer MSG_REGISTER_SITSCRIPT =383;&lt;br /&gt;
integer MSG_QUERY_SITSCRIPT = 385;&lt;br /&gt;
integer MSG_SYNC_ANIM=361;&lt;br /&gt;
&lt;br /&gt;
integer MSG_ADJUST_POSROT=520;&lt;br /&gt;
integer MSG_TEMPORARY_POSROT=521;&lt;br /&gt;
&lt;br /&gt;
integer MSG_MODE_ADJUST=368;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
vector o=ZERO_VECTOR;&lt;br /&gt;
vector r=ZERO_VECTOR;&lt;br /&gt;
integer hastimer;&lt;br /&gt;
&lt;br /&gt;
integer is_adjusting;&lt;br /&gt;
integer cursormode;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
stopAnim() {&lt;br /&gt;
    if (hasPerms) if (currentAnim)&lt;br /&gt;
        llStopAnimation(currentAnim);   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
runAnim() {&lt;br /&gt;
    if (hasPerms) if (currentAnim)&lt;br /&gt;
        llStartAnimation(currentAnim);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer checkPerms() {&lt;br /&gt;
    if (llGetPermissionsKey()!=ourAgent) {&lt;br /&gt;
        hasPerms = FALSE;&lt;br /&gt;
        return FALSE;   &lt;br /&gt;
    }&lt;br /&gt;
    hasPerms=(PERMISSION_TAKE_CONTROLS|PERMISSION_TRIGGER_ANIMATION) == ((PERMISSION_TAKE_CONTROLS|PERMISSION_TRIGGER_ANIMATION) &amp;amp; llGetPermissions());&lt;br /&gt;
    return hasPerms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
queryPerms() {&lt;br /&gt;
    if (!checkPerms()) {&lt;br /&gt;
        //must query them&lt;br /&gt;
        llRequestPermissions(ourAgent, PERMISSION_TAKE_CONTROLS|PERMISSION_TRIGGER_ANIMATION);   &lt;br /&gt;
    } else {&lt;br /&gt;
        stopDefAnims();&lt;br /&gt;
        if (currentAnim)&lt;br /&gt;
            llStartAnimation(currentAnim);&lt;br /&gt;
        getControls();   &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
stopDefAnims() {&lt;br /&gt;
    //easy way would be:&lt;br /&gt;
    //llStopAnimation(&amp;quot;sit&amp;quot;);   &lt;br /&gt;
    //let&#039;s go for the hard way&lt;br /&gt;
    list a=llGetAnimationList(ourAgent);&lt;br /&gt;
    integer i;&lt;br /&gt;
    for (i=0; i&amp;lt;llGetListLength(a); i++)&lt;br /&gt;
        llStopAnimation(llList2Key(a,i));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
register() {&lt;br /&gt;
    llMessageLinked (LINK_THIS, MSG_REGISTER_SITSCRIPT, llGetScriptName(), &amp;quot;&amp;quot;);   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
getControls() {&lt;br /&gt;
    llTakeControls (CONTROL_UP|CONTROL_DOWN|CONTROL_LEFT|CONTROL_RIGHT|CONTROL_FWD|CONTROL_BACK|CONTROL_ROT_LEFT|CONTROL_ROT_RIGHT, TRUE, FALSE);&lt;br /&gt;
    //llInstantMessage (ourAgent, &amp;quot;Adjust your position with PGUP, PGDOWN and cursorkeys. Shift rotates.&amp;quot;);   &lt;br /&gt;
    whispHelp(ourAgent);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
parseControls (integer level, integer edge) {&lt;br /&gt;
&lt;br /&gt;
    integer l = level; //hold down&lt;br /&gt;
    &lt;br /&gt;
    if ((CONTROL_UP|CONTROL_DOWN)==(l &amp;amp; edge &amp;amp; (CONTROL_UP | CONTROL_DOWN))) {&lt;br /&gt;
        cursormode=!cursormode;&lt;br /&gt;
        whispHelp(ourAgent);&lt;br /&gt;
        return;   &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    if (is_adjusting) {&lt;br /&gt;
        integer cm=cursormode;&lt;br /&gt;
        if (l &amp;amp; edge &amp;amp; CONTROL_LEFT) &lt;br /&gt;
            cursormode--;&lt;br /&gt;
        if (l &amp;amp; edge &amp;amp; CONTROL_RIGHT)&lt;br /&gt;
            cursormode++;&lt;br /&gt;
        if (cursormode&amp;lt;1)&lt;br /&gt;
            cursormode=3;&lt;br /&gt;
        if (cursormode&amp;gt;3)&lt;br /&gt;
            cursormode=1;&lt;br /&gt;
        if (cm!=cursormode)&lt;br /&gt;
            whispHelp(ourAgent);        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    if (cursormode==1) {//fine adjust    &lt;br /&gt;
        if (l &amp;amp; CONTROL_FWD) o+=&amp;lt;0,2,0&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; CONTROL_BACK) o+=&amp;lt;0,-2,0&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; CONTROL_ROT_LEFT) o+=&amp;lt;-2,0,0&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; CONTROL_ROT_RIGHT) o+=&amp;lt;2,0,0&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; CONTROL_UP) o+=&amp;lt;0,0,2&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; CONTROL_DOWN) o+=&amp;lt;0,0,-2&amp;gt;;&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    if (cursormode==2) {//90 degrees rotation    &lt;br /&gt;
        if (l &amp;amp; edge &amp;amp; CONTROL_FWD) r+=&amp;lt;0,90,0&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; edge &amp;amp; CONTROL_BACK) r+=&amp;lt;0,-90,0&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; edge &amp;amp; CONTROL_ROT_LEFT) r+=&amp;lt;0,0,-90&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; edge &amp;amp; CONTROL_ROT_RIGHT) r+=&amp;lt;0,0,90&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; edge &amp;amp; CONTROL_UP) r+=&amp;lt;90,0,0&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; edge &amp;amp; CONTROL_DOWN) r+=&amp;lt;-90,-0,0&amp;gt;;&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    if (cursormode==3) {//fine rotation    &lt;br /&gt;
        if (l &amp;amp; CONTROL_FWD) r+=&amp;lt;0,1,0&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; CONTROL_BACK) r+=&amp;lt;0,-1,0&amp;gt;; &lt;br /&gt;
        if (l &amp;amp; CONTROL_ROT_LEFT) r+=&amp;lt;0,0,-1&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; CONTROL_ROT_RIGHT) r+=&amp;lt;0,0,1&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; CONTROL_UP) r+=&amp;lt;1,0,0&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; CONTROL_DOWN) r+=&amp;lt;-1,0,0&amp;gt;;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //if (l &amp;amp; edge &amp;amp; CONTROL_LEFT) r += &amp;lt;0,0,90&amp;gt;;&lt;br /&gt;
    //if (l &amp;amp; edge &amp;amp; CONTROL_RIGHT) r += &amp;lt;0,-90,0&amp;gt;;    &lt;br /&gt;
        &lt;br /&gt;
    if (!hastimer) {&lt;br /&gt;
        llSetTimerEvent (0.25);&lt;br /&gt;
        hastimer=TRUE;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
whispHelp (key id) {&lt;br /&gt;
    if (!is_adjusting) {&lt;br /&gt;
        if (!cursormode) {&lt;br /&gt;
            llRegionSayTo (id, 0, &amp;quot;Press PAGE-UP and PAGE-DOWN simultanious to fine adjust position&amp;quot;);&lt;br /&gt;
        } else {&lt;br /&gt;
            llRegionSayTo (id, 0, &amp;quot;Use the cursor keys and up/down to adjust position. Changes made are temporary.&amp;quot;);&lt;br /&gt;
        }        &lt;br /&gt;
    } else {&lt;br /&gt;
        if (!cursormode)&lt;br /&gt;
            llRegionSayTo (id, 0, &amp;quot;Use PAGE-UP and PAGE-DOWN to start adjusting&amp;quot;);&lt;br /&gt;
        if (1==cursormode)&lt;br /&gt;
            llRegionSayTo (id, 0, &amp;quot;Mode: position (fine adjust). Use cursor keys and up/down to adjust position. Shift-left or shift-right to change mode&amp;quot;);&lt;br /&gt;
        if (2==cursormode)&lt;br /&gt;
            llRegionSayTo (id, 0, &amp;quot;Mode: rotation (90 degrees) . Use cursor keys and up/down to adjust rotation. Shift-left or shift-right to change mode&amp;quot;);&lt;br /&gt;
        if (3==cursormode)&lt;br /&gt;
            llRegionSayTo (id, 0, &amp;quot;Mode: rotation (fine adjust). Use cursor keys and up/down to adjust rotation. Shift-left or shift-right to change mode&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
upgrade() {string self = llGetScriptName(); string basename = self; if (llSubStringIndex(self, &amp;quot; &amp;quot;) &amp;gt;= 0) {integer start = 2; string tail = llGetSubString(self, llStringLength(self) - start, -1); while (llGetSubString(tail, 0, 0) != &amp;quot; &amp;quot;) {start++; tail = llGetSubString(self, llStringLength(self) - start, -1);} if ((integer)tail &amp;gt; 0) {basename = llGetSubString(self, 0, -llStringLength(tail) - 1);}} integer n = llGetInventoryNumber(INVENTORY_SCRIPT); while (n-- &amp;gt; 0) {string item = llGetInventoryName(INVENTORY_SCRIPT, n); if (item != self &amp;amp;&amp;amp; 0 == llSubStringIndex(item, basename)) {llRemoveInventory(item);}}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        //upgrade();&lt;br /&gt;
        register();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    link_message(integer sn, integer n, string m, key id) {&lt;br /&gt;
        if (n==MSG_ATTACH_AGENT) {&lt;br /&gt;
            if (m==llGetScriptName()) {&lt;br /&gt;
                if (ourAgent)&lt;br /&gt;
                    stopAnim();&lt;br /&gt;
                currentAnim=&amp;quot;&amp;quot;;   &lt;br /&gt;
                ourAgent = id;&lt;br /&gt;
                queryPerms();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_DETACH_AGENT) {&lt;br /&gt;
            if (ourAgent==id) {&lt;br /&gt;
                llReleaseControls();&lt;br /&gt;
                stopAnim();&lt;br /&gt;
            }&lt;br /&gt;
            ourAgent=NULL_KEY;&lt;br /&gt;
            currentAnim=&amp;quot;&amp;quot;;   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_AGENT_PLAY_ANIM) {&lt;br /&gt;
            if (ourAgent==id) {&lt;br /&gt;
                stopAnim();&lt;br /&gt;
                currentAnim=m;&lt;br /&gt;
                runAnim();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_AGENT_STOP_ANIM) {&lt;br /&gt;
            if (ourAgent==id) {&lt;br /&gt;
                stopAnim();&lt;br /&gt;
                currentAnim=&amp;quot;&amp;quot;;    &lt;br /&gt;
            }   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_SYNC_ANIM) {&lt;br /&gt;
            if (ourAgent) {&lt;br /&gt;
                stopAnim();&lt;br /&gt;
                runAnim();&lt;br /&gt;
            }   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_QUERY_SITSCRIPT) {&lt;br /&gt;
            register();&lt;br /&gt;
            //llOwnerSay (&amp;quot;Registering&amp;quot;);   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_MODE_ADJUST) {&lt;br /&gt;
            is_adjusting = (integer)m;&lt;br /&gt;
            if (!is_adjusting)&lt;br /&gt;
                cursormode=0;&lt;br /&gt;
            else&lt;br /&gt;
                cursormode=1;&lt;br /&gt;
            if (id==ourAgent)&lt;br /&gt;
                whispHelp(id);   &lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    run_time_permissions(integer p) {&lt;br /&gt;
        if (checkPerms()) {&lt;br /&gt;
            stopDefAnims();&lt;br /&gt;
            if (currentAnim)&lt;br /&gt;
                llStartAnimation(currentAnim);   &lt;br /&gt;
            getControls();&lt;br /&gt;
        } &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    control (key id, integer level, integer edge) {&lt;br /&gt;
        if (id!=ourAgent)&lt;br /&gt;
            return;&lt;br /&gt;
        parseControls (level, edge);   &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    timer () {&lt;br /&gt;
        llSetTimerEvent (0.);&lt;br /&gt;
        hastimer=FALSE;&lt;br /&gt;
        if (ZERO_VECTOR!=(o+r)) {&lt;br /&gt;
            if (is_adjusting)&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_ADJUST_POSROT, (string)(0.005*o)+&amp;quot;&amp;amp;&amp;quot;+(string)r, ourAgent);    &lt;br /&gt;
            else&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_TEMPORARY_POSROT, (string)(0.005*o)+&amp;quot;&amp;amp;&amp;quot;+(string)r, ourAgent);            &lt;br /&gt;
        }&lt;br /&gt;
        o=ZERO_VECTOR;&lt;br /&gt;
        r=ZERO_VECTOR;&lt;br /&gt;
        &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==TMCP - positions==&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
//basically, we need a large datastore for our command set&lt;br /&gt;
list poseNames;&lt;br /&gt;
list poseData;&lt;br /&gt;
&lt;br /&gt;
list positionNames;&lt;br /&gt;
list positionData;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
integer MSG_DATA_MENU=310;&lt;br /&gt;
integer MSG_DATA_TYPE=320;&lt;br /&gt;
integer MSG_DATA_POSE=330;&lt;br /&gt;
integer MSG_DATA_POSITION=331;&lt;br /&gt;
integer MSG_DATA_LM=335;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_POSE=350;&lt;br /&gt;
integer MSG_DO_LM=351;&lt;br /&gt;
integer MSG_DO_SPECIAL=352;&lt;br /&gt;
&lt;br /&gt;
integer MSG_SET_RUNNING=390;&lt;br /&gt;
integer MSG_STORAGE_RESET=391;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DATA_READY=309;&lt;br /&gt;
&lt;br /&gt;
integer MSG_RUN_ANIMS=379;&lt;br /&gt;
&lt;br /&gt;
integer MSG_AGENT_PLAY_ANIM=395;&lt;br /&gt;
&lt;br /&gt;
integer MSG_SET_SITTARGET=375;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DUMP_POSITIONS=389;&lt;br /&gt;
integer MSG_UPDATE_POS=363;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_DEFAULT_POSE = 358;&lt;br /&gt;
integer MSG_SET_DEFAULT_POSE = 359;&lt;br /&gt;
&lt;br /&gt;
integer MSG_MLP_SETTING = 1;&lt;br /&gt;
&lt;br /&gt;
integer MSG_ADJUST_POSROT=520;&lt;br /&gt;
integer MSG_TEMPORARY_POSROT=521;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
string currentPose=&amp;quot;default&amp;quot;;&lt;br /&gt;
list currentAnims;&lt;br /&gt;
list currentPositions;&lt;br /&gt;
&lt;br /&gt;
list agentPoseIdx;&lt;br /&gt;
&lt;br /&gt;
list agentAdjust;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
string defaultPose=&amp;quot;default&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
runAnims() {&lt;br /&gt;
    list data=agentPoseIdx;&lt;br /&gt;
    integer i;&lt;br /&gt;
    list idpos;&lt;br /&gt;
    for (i=0; i&amp;lt;llGetListLength(data); i+=2) {&lt;br /&gt;
        key id=(key)llList2String(data, i);&lt;br /&gt;
        integer idx=-1+(integer)llList2String(data, i+1);&lt;br /&gt;
        if (id) if (idx&amp;gt;=0) {&lt;br /&gt;
            if (idx&amp;gt;=llGetListLength(currentAnims))&lt;br /&gt;
                llWhisper (0, &amp;quot;No animation available for &amp;quot;+llKey2Name(id));&lt;br /&gt;
            else {&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_AGENT_PLAY_ANIM, llList2String(currentAnims, idx), id);&lt;br /&gt;
                //llOwnerSay (&amp;quot;Playing anim &amp;quot;+llList2String(currentAnims, idx)+&amp;quot; on id &amp;quot;+(string)id);&lt;br /&gt;
            }&lt;br /&gt;
                &lt;br /&gt;
            if (idx/2&amp;gt;=llGetListLength(currentPositions))&lt;br /&gt;
                llSay (0, &amp;quot;No position data for &amp;quot;+llKey2Name(id));   &lt;br /&gt;
            else {&lt;br /&gt;
                //set agents position&lt;br /&gt;
                idpos+=[id, (vector)llList2String(currentPositions, idx*2),(vector)llList2String(currentPositions, idx*2+1)];&lt;br /&gt;
            }&lt;br /&gt;
        } else {&lt;br /&gt;
            //llOwnerSay (&amp;quot;Corrupt agent anim position request&amp;quot;);   &lt;br /&gt;
        }&lt;br /&gt;
    }    &lt;br /&gt;
    //apply positions&lt;br /&gt;
    for (i=0; i&amp;lt;=llGetNumberOfPrims(); i++) {&lt;br /&gt;
        integer j=llListFindList(idpos, [llGetLinkKey(i)]);&lt;br /&gt;
        if (-1&amp;lt;j) {&lt;br /&gt;
            vector pos = llList2Vector(idpos, j+1)+(&amp;lt;0,0,0.42+0.01*(integer)llGetObjectDesc()&amp;gt;/llGetRot());&lt;br /&gt;
            vector rot = llList2Vector(idpos, j+2) * DEG_TO_RAD;&lt;br /&gt;
            integer l=llListFindList (agentAdjust, [llGetLinkKey(i)]);&lt;br /&gt;
            if (-1&amp;lt;l) {&lt;br /&gt;
                pos+=llList2Vector (agentAdjust, l+1);&lt;br /&gt;
                rot=llRot2Euler(llEuler2Rot(llList2Vector (agentAdjust, l+2)) * llEuler2Rot(rot));                   &lt;br /&gt;
            }&lt;br /&gt;
            llSetLinkPrimitiveParamsFast(i, [PRIM_POS_LOCAL, pos,PRIM_ROT_LOCAL, llEuler2Rot(rot)]);&lt;br /&gt;
            //llOwnerSay (&amp;quot;Setting position for &amp;quot;+llKey2Name(llGetLinkKey(i))+&amp;quot; position: &amp;quot;+(string)pos+&amp;quot; rotation: &amp;quot;+ (string)rot );&lt;br /&gt;
        }        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setSitTarget(integer poseidx) {&lt;br /&gt;
    poseidx--;&lt;br /&gt;
    vector v=(vector)llList2String(currentPositions, poseidx*2);&lt;br /&gt;
    vector r=(vector)llList2String(currentPositions, poseidx*2+1);&lt;br /&gt;
    llSitTarget (v+(&amp;lt;0,0,0.42+0.01*(integer)llGetObjectDesc()&amp;gt;/llGetRot()) , llEuler2Rot(r*DEG_TO_RAD));&lt;br /&gt;
    //llOwnerSay (&amp;quot;Sit target #&amp;quot;+(string)poseidx+&amp;quot; &amp;quot;+(string)(v+(&amp;lt;0,0,0.42&amp;gt;/llGetRot()))+&amp;quot; &amp;quot;+(string)(r));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string shortString (float n) {&lt;br /&gt;
    string s=(string)n;&lt;br /&gt;
    while (llStringLength(s)&amp;gt;1) {&lt;br /&gt;
        integer hasdot=-1!=llSubStringIndex(s, &amp;quot;.&amp;quot;);&lt;br /&gt;
        string d=llGetSubString(s,-1,-1);&lt;br /&gt;
        if ((hasdot &amp;amp;&amp;amp; (d==&amp;quot;0&amp;quot;)) || (d==&amp;quot;.&amp;quot;))&lt;br /&gt;
            s=llDeleteSubString(s,-1,-1);&lt;br /&gt;
        else&lt;br /&gt;
            jump ok;   &lt;br /&gt;
    }&lt;br /&gt;
    @ok;&lt;br /&gt;
    return s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string shortVec (vector v) {&lt;br /&gt;
    return &amp;quot;&amp;lt;&amp;quot;+shortString(v.x)+&amp;quot;,&amp;quot;+shortString(v.y)+&amp;quot;,&amp;quot;+shortString(v.z)+&amp;quot;&amp;gt;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
dumpPos() {&lt;br /&gt;
    llOwnerSay (&amp;quot;TMCP Position Dump&amp;quot;);&lt;br /&gt;
    integer i;&lt;br /&gt;
    for (i=0; i&amp;lt;llGetListLength(positionNames); i++) {&lt;br /&gt;
        //llOwnerSay (&amp;quot;{&amp;quot;+llList2String(positionNames, i)+&amp;quot;} &amp;quot;+llList2String(positionData, i));    &lt;br /&gt;
        list v=llParseString2List(llList2String(positionData, i), [&amp;quot;&amp;amp;&amp;quot;], []);&lt;br /&gt;
        string s=&amp;quot;{&amp;quot;+llList2String(positionNames, i)+&amp;quot;}&amp;quot;;&lt;br /&gt;
        integer j;&lt;br /&gt;
        for (j=0; j&amp;lt;llGetListLength(v); j++)&lt;br /&gt;
            //notice that function shortvec takes string as param&lt;br /&gt;
            s+=&amp;quot; &amp;quot;+shortVec((vector)llList2String(v, j));        &lt;br /&gt;
        llOwnerSay (s);&lt;br /&gt;
    }   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
doPose (string m) {&lt;br /&gt;
    if (m!=currentPose)&lt;br /&gt;
        agentAdjust=[];&lt;br /&gt;
        &lt;br /&gt;
            currentPose=m;&lt;br /&gt;
            currentAnims=[];&lt;br /&gt;
            currentPositions=[];&lt;br /&gt;
            integer i=llListFindList(positionNames, [m]);&lt;br /&gt;
            integer j=llListFindList(poseNames, [m]);&lt;br /&gt;
            currentAnims=llParseString2List (llList2String(poseData, j), [&amp;quot;|&amp;quot;], []);&lt;br /&gt;
            currentPositions=llParseString2List (llList2String(positionData, i), [&amp;quot;&amp;amp;&amp;quot;], []);&lt;br /&gt;
            &lt;br /&gt;
            //fill missing data with defaults&lt;br /&gt;
            i = llListFindList(positionNames, [&amp;quot;default&amp;quot;]);&lt;br /&gt;
            j = llListFindList(poseNames, [&amp;quot;default&amp;quot;]);&lt;br /&gt;
            list animdef=llParseString2List (llList2String(poseData, j), [&amp;quot;|&amp;quot;], []);&lt;br /&gt;
            list posdef=llParseString2List (llList2String(positionData, i), [&amp;quot;&amp;amp;&amp;quot;], []);&lt;br /&gt;
            currentAnims+=llList2List (animdef, llGetListLength(currentAnims), -1);&lt;br /&gt;
            currentPositions+=llList2List(posdef, llGetListLength(currentPositions), -1);            &lt;br /&gt;
            &lt;br /&gt;
            //this should be obsolete now:&lt;br /&gt;
            if (/*(i&amp;gt;=0) &amp;amp;&amp;amp; */(j&amp;gt;=0)) {&lt;br /&gt;
                //list l=llParseString2List(llList2String(lmAction, i), [&amp;quot;,&amp;quot;],[]);&lt;br /&gt;
                //parse pose data. todo.&lt;br /&gt;
                if (i&amp;lt;0) {&lt;br /&gt;
                    //need to fetch default data... just try it.&lt;br /&gt;
                    i=llListFindList(positionNames, [&amp;quot;default&amp;quot;]);&lt;br /&gt;
                }&lt;br /&gt;
                //llOwnerSay (&amp;quot;Do pose &amp;quot;+m+&amp;quot; anims &amp;quot;+llList2String(poseData,j)+&amp;quot; data &amp;quot;+llList2String(positionData, i));&lt;br /&gt;
            } else {                                &lt;br /&gt;
                //llOwnerSay (&amp;quot;No animations defined for &amp;quot;+m);&lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
            runAnims();  &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setAgentPosRot (key id, string data) {&lt;br /&gt;
    //set temporary agent adjustment.&lt;br /&gt;
    list l=llParseString2List(data, [&amp;quot;&amp;amp;&amp;quot;], []);&lt;br /&gt;
    vector p=(vector)llList2String(l,0);&lt;br /&gt;
    vector r=DEG_TO_RAD * (vector)llList2String(l,1);&lt;br /&gt;
    integer i=llListFindList (agentAdjust, [id]);&lt;br /&gt;
    if (-1&amp;lt;i) {&lt;br /&gt;
        p+=llList2Vector(agentAdjust, i+1);&lt;br /&gt;
        r=llRot2Euler(llEuler2Rot(llList2Vector(agentAdjust, i+2))*llEuler2Rot(r));        &lt;br /&gt;
        agentAdjust = llDeleteSubList(agentAdjust, i, i+2);&lt;br /&gt;
    }&lt;br /&gt;
    if (llVecMag(p)&amp;gt;1)&lt;br /&gt;
        p=llVecNorm(p);&lt;br /&gt;
    agentAdjust+=[id,p,r];       &lt;br /&gt;
    runAnims();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
adjustPosition (string name, integer index, vector p, vector r) {&lt;br /&gt;
                              //positionNames&lt;br /&gt;
    integer i=llListFindList (positionNames, [name]); &lt;br /&gt;
    if (-1&amp;lt;i) {&lt;br /&gt;
        string data=llList2String(positionData, i);&lt;br /&gt;
        list pos=llParseString2List(data, [&amp;quot;&amp;amp;&amp;quot;], []);&lt;br /&gt;
        if (index&amp;gt;0) {&lt;br /&gt;
            //alter only index   &lt;br /&gt;
            integer j=(index-1)*2;&lt;br /&gt;
            if (j&amp;lt;llGetListLength(positionData)) {&lt;br /&gt;
                vector v=(vector)llList2String(pos, j);   &lt;br /&gt;
                v+=p;&lt;br /&gt;
                vector R0=(vector)llList2String(pos, j+1);   &lt;br /&gt;
                rotation R1=llEuler2Rot(DEG_TO_RAD *R0);&lt;br /&gt;
                rotation Rd=llEuler2Rot(DEG_TO_RAD * r);&lt;br /&gt;
                R1 = R1 * Rd;&lt;br /&gt;
                R0=RAD_TO_DEG * llRot2Euler(R1);                &lt;br /&gt;
                pos=llListReplaceList(pos, [shortVec(v),shortVec(R0)], j, j+1);                             &lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
        } else {&lt;br /&gt;
            //alter all&lt;br /&gt;
            integer j;&lt;br /&gt;
            for (j=0; j&amp;lt;llGetListLength(pos); j+=2) {&lt;br /&gt;
                vector v=(vector)llList2String(pos, j);   &lt;br /&gt;
                v+=p;&lt;br /&gt;
                vector R0=(vector)llList2String(pos, j+1);   &lt;br /&gt;
                rotation R1=llEuler2Rot(DEG_TO_RAD *R0);&lt;br /&gt;
                rotation Rd=llEuler2Rot(DEG_TO_RAD * r);&lt;br /&gt;
                R1 = R1 * Rd;&lt;br /&gt;
                R0=RAD_TO_DEG * llRot2Euler(R1);                &lt;br /&gt;
                pos=llListReplaceList(pos, [shortVec(v),shortVec(R0)], j, j+1);                &lt;br /&gt;
            }               &lt;br /&gt;
        }&lt;br /&gt;
        data=llDumpList2String(pos, &amp;quot;&amp;amp;&amp;quot;);&lt;br /&gt;
        //llOwnerSay (&amp;quot;new pos data for &amp;quot;+name+&amp;quot; : &amp;quot;+data);&lt;br /&gt;
        positionData=llListReplaceList (positionData, [data], i, i);&lt;br /&gt;
           &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
adjustAllPositions (vector p, vector r) {&lt;br /&gt;
    //loop all pose, adjust them&lt;br /&gt;
    integer i;&lt;br /&gt;
    for (i=0; i&amp;lt;llGetListLength(positionNames); i++) {&lt;br /&gt;
        adjustPosition (llList2String(positionNames, i),-1, p,r);&lt;br /&gt;
    }   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
parseSetting (string m, key id) {&lt;br /&gt;
    //seperated by =&lt;br /&gt;
    //might contain ROT or POS adjustments&lt;br /&gt;
    list l=llParseString2List(m, [&amp;quot; = &amp;quot;, &amp;quot; =&amp;quot;, &amp;quot;=&amp;quot;, &amp;quot;= &amp;quot;,&amp;quot;=&amp;quot;],[]);&lt;br /&gt;
    string cmd=llList2String(l, 0);&lt;br /&gt;
    string cmd2=llList2String(l,1);&lt;br /&gt;
    if (cmd==&amp;quot;REORIENT&amp;quot;) {&lt;br /&gt;
        vector v=(vector)llList2String(l,2);&lt;br /&gt;
        /*&lt;br /&gt;
        list lv=llParseString2List(llList2String(l,2), [&amp;quot;&amp;lt;&amp;quot;,&amp;quot;,&amp;quot;,&amp;quot;&amp;gt;&amp;quot;], []); //rotations come as vector too&lt;br /&gt;
        llOwnerSay (&amp;quot;P: &amp;quot;+llList2String(l,2)+&amp;quot; : &amp;quot;+llDumpList2String(lv, &amp;quot;*&amp;quot;));&lt;br /&gt;
        v.x=(float)llList2String(lv,0);&lt;br /&gt;
        v.y=(float)llList2String(lv,1);&lt;br /&gt;
        v.z=(float)llList2String(lv,2);&lt;br /&gt;
        */&lt;br /&gt;
        &lt;br /&gt;
        llOwnerSay (&amp;quot;adjust &amp;quot;+cmd2+&amp;quot; &amp;quot;+(string)v);&lt;br /&gt;
        if (cmd2==&amp;quot;OFF&amp;quot;) {&lt;br /&gt;
            adjustAllPositions (0.01*v, ZERO_VECTOR);    &lt;br /&gt;
        } else&lt;br /&gt;
        if (cmd2==&amp;quot;ROT&amp;quot;) {&lt;br /&gt;
            adjustAllPositions (ZERO_VECTOR,v);    &lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        doPose(currentPose);&lt;br /&gt;
        //runAnims();&lt;br /&gt;
    }    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
adjustPosRot (key id, string data) {&lt;br /&gt;
    list l=llParseString2List(data, [&amp;quot;&amp;amp;&amp;quot;], []);&lt;br /&gt;
    integer i=llListFindList (agentPoseIdx, [(string)id]);&lt;br /&gt;
    //llOwnerSay (&amp;quot;posrot &amp;quot;+(string)i+&amp;quot; &amp;quot;+(string)id+&amp;quot; &amp;quot;+data);&lt;br /&gt;
    if ((-1&amp;lt;i)&amp;amp;&amp;amp;(llGetListLength(l)==2)) {&lt;br /&gt;
        integer lidx=llList2Integer (agentPoseIdx, i+1);&lt;br /&gt;
        adjustPosition (currentPose, lidx, (vector)llList2String(l,0), (vector)llList2String(l,1));&lt;br /&gt;
        doPose(currentPose);        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
upgrade() {string self = llGetScriptName(); string basename = self; if (llSubStringIndex(self, &amp;quot; &amp;quot;) &amp;gt;= 0) {integer start = 2; string tail = llGetSubString(self, llStringLength(self) - start, -1); while (llGetSubString(tail, 0, 0) != &amp;quot; &amp;quot;) {start++; tail = llGetSubString(self, llStringLength(self) - start, -1);} if ((integer)tail &amp;gt; 0) {basename = llGetSubString(self, 0, -llStringLength(tail) - 1);}} integer n = llGetInventoryNumber(INVENTORY_SCRIPT); while (n-- &amp;gt; 0) {string item = llGetInventoryName(INVENTORY_SCRIPT, n); if (item != self &amp;amp;&amp;amp; 0 == llSubStringIndex(item, basename)) {llRemoveInventory(item);}}}&lt;br /&gt;
&lt;br /&gt;
default &lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        upgrade();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    link_message (integer sn, integer n, string m, key id) {&lt;br /&gt;
        if (n==MSG_DATA_POSE) {&lt;br /&gt;
            //add posedata    &lt;br /&gt;
            poseNames+=m;&lt;br /&gt;
            poseData+=(string)id;&lt;br /&gt;
        } else&lt;br /&gt;
        if (n==MSG_DATA_POSITION) {&lt;br /&gt;
            positionNames+=m;&lt;br /&gt;
            positionData+=(string)id;            &lt;br /&gt;
        } else&lt;br /&gt;
        if (n==MSG_SET_DEFAULT_POSE) {&lt;br /&gt;
                defaultPose=m;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_SET_RUNNING)&lt;br /&gt;
            state running;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state running {&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llOwnerSay (&amp;quot;Position free memory: &amp;quot;+(string)llGetFreeMemory());&lt;br /&gt;
        doPose(defaultPose);&lt;br /&gt;
    }&lt;br /&gt;
    link_message (integer sn, integer n, string m, key id) {&lt;br /&gt;
        if (n==MSG_DO_POSE) {&lt;br /&gt;
            doPose(m);&lt;br /&gt;
        } else&lt;br /&gt;
        if (n==MSG_STORAGE_RESET)&lt;br /&gt;
            llResetScript();&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_RUN_ANIMS) {&lt;br /&gt;
            agentPoseIdx=llCSV2List(m);&lt;br /&gt;
            runAnims();    &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_SET_SITTARGET) {&lt;br /&gt;
            setSitTarget((integer)m);    &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_DUMP_POSITIONS) {&lt;br /&gt;
            dumpPos();&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_UPDATE_POS) {&lt;br /&gt;
            runAnims();       &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_SET_DEFAULT_POSE)&lt;br /&gt;
            defaultPose=m;&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_DO_DEFAULT_POSE)&lt;br /&gt;
            doPose(defaultPose);&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_MLP_SETTING) {&lt;br /&gt;
            parseSetting (m, id);   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_ADJUST_POSROT) {&lt;br /&gt;
            adjustPosRot(id, m);      &lt;br /&gt;
        }&lt;br /&gt;
        if (n==MSG_TEMPORARY_POSROT) {&lt;br /&gt;
            setAgentPosRot(id, m);      &lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==TMCP - actions==&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
//basically, we need a large datastore for our command set&lt;br /&gt;
list lmNames;&lt;br /&gt;
list lmAction;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DATA_MENU=310;&lt;br /&gt;
integer MSG_DATA_TYPE=320;&lt;br /&gt;
integer MSG_DATA_POSE=330;&lt;br /&gt;
integer MSG_DATA_LM=335;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_POSE=350;&lt;br /&gt;
integer MSG_DO_LM=351;&lt;br /&gt;
integer MSG_DO_SPECIAL=352;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_SOUND=356;&lt;br /&gt;
&lt;br /&gt;
integer MSG_SET_RUNNING=390;&lt;br /&gt;
integer MSG_STORAGE_RESET=391;&lt;br /&gt;
integer MSG_DATA_READY=309;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
upgrade() {string self = llGetScriptName(); string basename = self; if (llSubStringIndex(self, &amp;quot; &amp;quot;) &amp;gt;= 0) {integer start = 2; string tail = llGetSubString(self, llStringLength(self) - start, -1); while (llGetSubString(tail, 0, 0) != &amp;quot; &amp;quot;) {start++; tail = llGetSubString(self, llStringLength(self) - start, -1);} if ((integer)tail &amp;gt; 0) {basename = llGetSubString(self, 0, -llStringLength(tail) - 1);}} integer n = llGetInventoryNumber(INVENTORY_SCRIPT); while (n-- &amp;gt; 0) {string item = llGetInventoryName(INVENTORY_SCRIPT, n); if (item != self &amp;amp;&amp;amp; 0 == llSubStringIndex(item, basename)) {llRemoveInventory(item);}}}&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        upgrade();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    link_message (integer sn, integer n, string m, key id) {&lt;br /&gt;
        if (n==MSG_DATA_LM) {&lt;br /&gt;
            //add action    &lt;br /&gt;
            lmNames+=m;&lt;br /&gt;
            lmAction+=(string)id;&lt;br /&gt;
        } else&lt;br /&gt;
        if (n==MSG_SET_RUNNING)&lt;br /&gt;
            state running;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state running {&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llOwnerSay (&amp;quot;Action manager free memory : &amp;quot;+(string)llGetFreeMemory());    &lt;br /&gt;
    }    &lt;br /&gt;
    link_message (integer sn, integer n, string m, key id) {&lt;br /&gt;
        if (n==MSG_DO_LM) {&lt;br /&gt;
            integer i=llListFindList(lmNames, [m]);&lt;br /&gt;
            if (i&amp;gt;=0) {&lt;br /&gt;
                list l=llParseString2List(llList2String(lmAction, i), [&amp;quot;,&amp;quot;],[]);&lt;br /&gt;
                integer set=(integer)llList2String(l,1);    &lt;br /&gt;
                integer num=(integer)llList2String(l,2);    &lt;br /&gt;
                //string mess=llStringTrim(llList2String(l,3),STRING_TRIM);&lt;br /&gt;
                string mess=llDumpList2String(llList2List(l,3,-1), &amp;quot;,&amp;quot;);&lt;br /&gt;
                integer nomenu=(integer)llList2String(l,0);    &lt;br /&gt;
                //perform requested action&lt;br /&gt;
                llMessageLinked (set, num, mess, id);&lt;br /&gt;
                &lt;br /&gt;
                if (!nomenu) //this will fail when not found, which it shouldnt.&lt;br /&gt;
                    llMessageLinked (LINK_THIS, 370, &amp;quot;&amp;quot;, id);&lt;br /&gt;
            }   &lt;br /&gt;
        } else&lt;br /&gt;
        if (n==MSG_DO_SOUND) {&lt;br /&gt;
            //LM list was abused for sound info&lt;br /&gt;
            integer i=llListFindList(lmNames, [m]);&lt;br /&gt;
            if (i&amp;gt;=0)&lt;br /&gt;
                llTriggerSound(llList2String(lmAction, i), 1.);&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_STORAGE_RESET)&lt;br /&gt;
            llResetScript();&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==TMCP - menurender==&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
string version = &amp;quot;TMCP v0.3x&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//Render menu&lt;br /&gt;
&lt;br /&gt;
list menuNames;&lt;br /&gt;
list menuEntries; //menus that appear in &#039;auto&#039; menu&lt;br /&gt;
list menuDetails;&lt;br /&gt;
&lt;br /&gt;
//some hardcoded stuff that this script adds, not any menu. prefill.&lt;br /&gt;
list itemNames=[&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;,&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;,&amp;quot;&amp;lt;BACK&amp;quot;];&lt;br /&gt;
list itemTypes=[7,7,7];&lt;br /&gt;
&lt;br /&gt;
list menuHistory;&lt;br /&gt;
string currentMenu;&lt;br /&gt;
string currentPose=&amp;quot;default&amp;quot;;&lt;br /&gt;
string defaultPose=&amp;quot;default&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
integer channel=999; &lt;br /&gt;
integer listenhandle;&lt;br /&gt;
&lt;br /&gt;
integer mode_chat=1;&lt;br /&gt;
integer mode_adjust=0;&lt;br /&gt;
integer mode_menu=3; //user&lt;br /&gt;
integer mode_ball=0; //all&lt;br /&gt;
&lt;br /&gt;
integer hibernate;&lt;br /&gt;
&lt;br /&gt;
list rlvVictims;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
integer TYPE_MENU=1;&lt;br /&gt;
integer TYPE_POSE=2;&lt;br /&gt;
integer TYPE_LM_NOMENU=3;&lt;br /&gt;
integer TYPE_LM_MENU=4;&lt;br /&gt;
integer TYPE_IGNORE=5;&lt;br /&gt;
integer TYPE_SPECIAL=6;&lt;br /&gt;
integer TYPE_UNKNOWN=7;&lt;br /&gt;
integer TYPE_SOUND=8;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
integer MSG_DATA_MENU=310;&lt;br /&gt;
integer MSG_DATA_MENU_DETAILS=311;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DATA_TYPE=320;&lt;br /&gt;
integer MSG_DATA_POSE=330;&lt;br /&gt;
integer MSG_DATA_POSITION=331;&lt;br /&gt;
integer MSG_DATA_LM=335;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_POSE=350;&lt;br /&gt;
integer MSG_DO_LM=351;&lt;br /&gt;
integer MSG_DO_SPECIAL=352;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_STOP=353;&lt;br /&gt;
integer MSG_DO_SWAP=354;&lt;br /&gt;
integer MSG_MENU_SWAP=355;&lt;br /&gt;
integer MSG_DO_SOUND=356;&lt;br /&gt;
&lt;br /&gt;
integer MSG_SET_RUNNING=390;&lt;br /&gt;
integer MSG_STORAGE_RESET=391;&lt;br /&gt;
integer MSG_DATA_READY=309;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DATA_START_READ=301;&lt;br /&gt;
&lt;br /&gt;
integer MSG_MENU_META=333;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DUMP_POSITIONS=389;&lt;br /&gt;
integer MSG_MODE_ADJUST=368;&lt;br /&gt;
integer MSG_MODE_CHAT=367;&lt;br /&gt;
integer MSG_MODE_BALLUSERS=366;&lt;br /&gt;
integer MSG_MODE_OFF=365;&lt;br /&gt;
&lt;br /&gt;
integer MSG_UPDATE_POS=363;&lt;br /&gt;
integer MSG_ALL_UNSIT =381;&lt;br /&gt;
&lt;br /&gt;
integer MSG_SET_DEFAULT_POSE = 359;&lt;br /&gt;
integer MSG_DO_DEFAULT_POSE = 358;&lt;br /&gt;
&lt;br /&gt;
integer MSG_RLV_GRAB=308;&lt;br /&gt;
integer MSG_RLV_RELEASE=309;&lt;br /&gt;
integer MSG_RLV_VICTIM_LIST=307;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_MENU_CURRENTMENU = 305;&lt;br /&gt;
&lt;br /&gt;
//incoming&lt;br /&gt;
integer MSG_DO_MENU_COMMAND = -12002;&lt;br /&gt;
&lt;br /&gt;
verbose(string text) {&lt;br /&gt;
    //llOwnerSay (text);&lt;br /&gt;
    if (mode_chat)&lt;br /&gt;
        llSay (0, text);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string onOff(integer value) {&lt;br /&gt;
    if (value) return &amp;quot;On&amp;quot;; else return &amp;quot;Off&amp;quot;;   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string aclMode(integer value) {&lt;br /&gt;
    if (0==value)&lt;br /&gt;
        return &amp;quot;ALL&amp;quot;;&lt;br /&gt;
    else&lt;br /&gt;
    if (1==value)&lt;br /&gt;
        return &amp;quot;GROUP&amp;quot;;&lt;br /&gt;
    else&lt;br /&gt;
    if (2==value)&lt;br /&gt;
        return &amp;quot;OWNER&amp;quot;;&lt;br /&gt;
    else&lt;br /&gt;
    if (3==value)&lt;br /&gt;
        return &amp;quot;USER&amp;quot;;&lt;br /&gt;
    else&lt;br /&gt;
        return &amp;quot;UNKNOWN&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
reset(integer resetSelf) {&lt;br /&gt;
    integer i;&lt;br /&gt;
    for (i=0; i&amp;lt;llGetInventoryNumber(INVENTORY_SCRIPT); i++) {&lt;br /&gt;
        string s=llGetInventoryName(INVENTORY_SCRIPT, i);&lt;br /&gt;
        if (-1&amp;lt;llSubStringIndex(s, &amp;quot;~TMCP &amp;quot;)) {&lt;br /&gt;
            if (s!=llGetScriptName()) {&lt;br /&gt;
                llResetOtherScript(s);    &lt;br /&gt;
            }   &lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    if (resetSelf)&lt;br /&gt;
        llResetScript();        &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setRunning(integer running) {&lt;br /&gt;
    integer i;&lt;br /&gt;
    for (i=0; i&amp;lt;llGetInventoryNumber(INVENTORY_SCRIPT); i++) {&lt;br /&gt;
        string s=llGetInventoryName(INVENTORY_SCRIPT, i);&lt;br /&gt;
        if (-1&amp;lt;llSubStringIndex(s, &amp;quot;~TMCP &amp;quot;)) {&lt;br /&gt;
            if (s!=llGetScriptName()) {&lt;br /&gt;
                llSetScriptState (s, running);&lt;br /&gt;
            }   &lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
integer hasDialogAccess(key id) {&lt;br /&gt;
    &lt;br /&gt;
    //OWNER ALWAYS&lt;br /&gt;
    if (id==llGetOwner())&lt;br /&gt;
        return TRUE;&lt;br /&gt;
        &lt;br /&gt;
    if (-1&amp;lt;llListFindList(rlvVictims, [(string)id]))&lt;br /&gt;
        return FALSE;&lt;br /&gt;
        &lt;br /&gt;
    //ALL&lt;br /&gt;
    if ((!mode_menu)/* || (id==llGetOwner())*/)&lt;br /&gt;
        return TRUE; //little speed optimalization to avoid call to samegroup&lt;br /&gt;
        &lt;br /&gt;
    //USER&lt;br /&gt;
    if (mode_menu==3) {&lt;br /&gt;
        //user must be sitted to access, or no-one sitted at all&lt;br /&gt;
        integer someSit=FALSE;&lt;br /&gt;
        integer i;&lt;br /&gt;
        for (i=0; i&amp;lt;=llGetNumberOfPrims(); i++) {&lt;br /&gt;
            if (llGetLinkKey(i)==id)&lt;br /&gt;
                return TRUE;&lt;br /&gt;
            if (llGetAgentSize(llGetLinkKey(i)))&lt;br /&gt;
                someSit=TRUE;   &lt;br /&gt;
        }&lt;br /&gt;
        return (!someSit);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //GROUP&lt;br /&gt;
    return (mode_menu==1) &amp;amp;&amp;amp; llSameGroup(id);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer hasMenuAccess (key id, string menu) {&lt;br /&gt;
    //supposed to be trimmed already?&lt;br /&gt;
    if (id==llGetOwner())&lt;br /&gt;
        return TRUE;&lt;br /&gt;
    string access=&lt;br /&gt;
        llStringTrim(&lt;br /&gt;
            llList2String(&lt;br /&gt;
                llParseString2List(&lt;br /&gt;
                    llList2String(menuDetails, 1+llListFindList(menuDetails, [menu]) )&lt;br /&gt;
                , [&amp;quot;|&amp;quot;], [])&lt;br /&gt;
            , 0)&lt;br /&gt;
        , STRING_TRIM);&lt;br /&gt;
    if (access==&amp;quot;OWNER&amp;quot;) {&lt;br /&gt;
        return id==llGetOwner();&lt;br /&gt;
    }&lt;br /&gt;
    if (access==&amp;quot;GROUP&amp;quot;) {&lt;br /&gt;
        return (id==llGetOwner()) || llSameGroup(id);        &lt;br /&gt;
    }&lt;br /&gt;
    if (access==&amp;quot;USER&amp;quot;) {&lt;br /&gt;
        integer i;&lt;br /&gt;
        for (i=0; i&amp;lt;=llGetNumberOfPrims(); i++)&lt;br /&gt;
            if (llGetLinkKey(i)==id)&lt;br /&gt;
                return TRUE;&lt;br /&gt;
        return FALSE;   &lt;br /&gt;
    }&lt;br /&gt;
    //defaults to all.. learn to edit notecards if you made an error.&lt;br /&gt;
    //future options might be a name or some. dunnow.&lt;br /&gt;
    return TRUE;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
makeMenu(string name, key id) {&lt;br /&gt;
    &lt;br /&gt;
    if (id); else return; //might be invoked by remote scripts. can&#039;t pop menu&#039;s to none-avi&#039;s.&lt;br /&gt;
    &lt;br /&gt;
    //present user a fine menu   &lt;br /&gt;
    integer idx=0;&lt;br /&gt;
    &lt;br /&gt;
    integer offset;&lt;br /&gt;
    &lt;br /&gt;
    if ((name==&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;) || (name==&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;)) {&lt;br /&gt;
        //offset making&lt;br /&gt;
        //rename to the last found menu&lt;br /&gt;
        /*&lt;br /&gt;
        if (name==&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;)&lt;br /&gt;
            offset+=10;&lt;br /&gt;
        if (name==&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;)&lt;br /&gt;
            offset-=10;                   &lt;br /&gt;
        */&lt;br /&gt;
        menuHistory+=name; //next step will fix this&lt;br /&gt;
        //llOwnerSay (&amp;quot;history: &amp;quot;+(string)menuHistory);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    integer ho=llGetListLength(menuHistory)-1;&lt;br /&gt;
    while ((ho&amp;gt;1) &amp;amp;&amp;amp; (-1&amp;lt;llListFindList([&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;, &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;], [llList2String(menuHistory, ho)])) ) {&lt;br /&gt;
        //adjust offset&lt;br /&gt;
        string s=llList2String(menuHistory, ho);&lt;br /&gt;
        if (s==&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;)&lt;br /&gt;
            offset-=10;&lt;br /&gt;
        if (s==&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;)&lt;br /&gt;
            offset+=10;&lt;br /&gt;
        name=llList2String(menuHistory, ho-1);&lt;br /&gt;
        ho--;            &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
        &lt;br /&gt;
    if (name) {&lt;br /&gt;
        idx=llListFindList(menuNames, [name]);&lt;br /&gt;
        if (idx&amp;lt;0) {            &lt;br /&gt;
            //llOwnerSay (&amp;quot;No menu entry for &amp;quot;+name);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
    } else {&lt;br /&gt;
        //make it main menu&lt;br /&gt;
        name=llList2String(menuNames, 0); //assume at least 1 menu item please.. else its bugged anyways.&lt;br /&gt;
        menuHistory=[];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    currentMenu=name;&lt;br /&gt;
        &lt;br /&gt;
    integer i=llListFindList (menuHistory, [name]);&lt;br /&gt;
    if (i&amp;gt;=0) {&lt;br /&gt;
        //truncate rest from history, maybe we went back.&lt;br /&gt;
        menuHistory = llList2List(menuHistory, 0, i);   &lt;br /&gt;
    } else &lt;br /&gt;
        menuHistory += name;&lt;br /&gt;
&lt;br /&gt;
        &lt;br /&gt;
    list present=llCSV2List(llList2String(menuEntries, idx));&lt;br /&gt;
&lt;br /&gt;
    if (llAbs(offset)&amp;gt;=(llGetListLength(present))) offset=0;&lt;br /&gt;
                                &lt;br /&gt;
    integer o=offset;&lt;br /&gt;
    while (o&amp;gt;0) {&lt;br /&gt;
        menuHistory += &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;;&lt;br /&gt;
        o-=10;   &lt;br /&gt;
        if (o&amp;lt;0)&lt;br /&gt;
            o=0;&lt;br /&gt;
    }&lt;br /&gt;
    while (o&amp;lt;0) {&lt;br /&gt;
        menuHistory += &amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;;&lt;br /&gt;
        o+=10;   &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    string h=&amp;quot;&amp;gt;&amp;gt;&amp;quot;;&lt;br /&gt;
    for (i=0; i&amp;lt;llGetListLength(menuHistory); i++)&lt;br /&gt;
        h+=&amp;quot;&amp;gt; &amp;quot;+llList2String(menuHistory,i)+&amp;quot; &amp;quot;;&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    if (currentPose)&lt;br /&gt;
        h+=&amp;quot;\n\nCurrent pose: &amp;quot;+currentPose;&lt;br /&gt;
    //todo somewhere. some better wrap around.&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    if ((offset) || (llGetListLength(present)&amp;gt;12))&lt;br /&gt;
        present = llList2List(present, offset, offset+8) + [&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;, &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;, &amp;quot;BACK&amp;quot;];        &lt;br /&gt;
    &lt;br /&gt;
    if (llGetListLength(rlvVictims)) {&lt;br /&gt;
        h+=&amp;quot;\nCaptured (RLV): &amp;quot;;&lt;br /&gt;
        for (i=0; i&amp;lt;llGetListLength(rlvVictims); i++)&lt;br /&gt;
            h+=llKey2Name((key)llList2String(rlvVictims, i))+&amp;quot;\n&amp;quot;;&lt;br /&gt;
    }    &lt;br /&gt;
    &lt;br /&gt;
    //got our filled up menu here? prolly need to sort it, for now just present it&lt;br /&gt;
    //llOwnerSay (name+&amp;quot;:&amp;quot;+llList2CSV(present));&lt;br /&gt;
    &lt;br /&gt;
    //invert our list&lt;br /&gt;
    list p;&lt;br /&gt;
    for (i=0; i&amp;lt;12; i+=3)&lt;br /&gt;
        p = p+llList2List (present, -i-3, -i-1);&lt;br /&gt;
    &lt;br /&gt;
    llDialog (id, version+&amp;quot;\n&amp;quot;+h, p, channel);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
processCommand (key id, string message) {&lt;br /&gt;
        integer typeidx=llListFindList (itemNames, [message]);&lt;br /&gt;
        string param;&lt;br /&gt;
        integer newMenu=TRUE;&lt;br /&gt;
        &lt;br /&gt;
        if (typeidx&amp;lt;0) {&lt;br /&gt;
            list l=llParseString2List(message, [&amp;quot;::&amp;quot;], []);&lt;br /&gt;
            message=llList2String(l,0);&lt;br /&gt;
            param=llList2String(l,1);&lt;br /&gt;
            typeidx=llListFindList (itemNames, [message]);&lt;br /&gt;
            //llOwnerSay (&amp;quot;Message &amp;quot;+message+&amp;quot; got param &amp;quot;+param);            &lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if (typeidx&amp;lt;0) {&lt;br /&gt;
            //llOwnerSay (&amp;quot;Error - no menu entry for &amp;quot;+message);&lt;br /&gt;
            return;    &lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
           &lt;br /&gt;
        integer type=llList2Integer(itemTypes, typeidx);&lt;br /&gt;
        //llOwnerSay (&amp;quot;Type for &amp;quot;+message+&amp;quot; is &amp;quot;+(string)type);&lt;br /&gt;
        if (type==TYPE_MENU) {&lt;br /&gt;
            if (hasMenuAccess(id, message)) {&lt;br /&gt;
                makeMenu(message, id);           &lt;br /&gt;
                newMenu=FALSE;                &lt;br /&gt;
            } else {&lt;br /&gt;
                llRegionSayTo (id, 0, &amp;quot;Access to menu &amp;quot;+message+&amp;quot; is denied.&amp;quot;);&lt;br /&gt;
                //makeMenu(currentMenu, id);                   &lt;br /&gt;
                //return;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (type==TYPE_POSE) {&lt;br /&gt;
            llMessageLinked (LINK_THIS, MSG_DO_POSE, message, &amp;quot;&amp;quot;);&lt;br /&gt;
            currentPose=message;&lt;br /&gt;
            llMessageLinked (LINK_THIS, MSG_MENU_META,llList2String(menuDetails, 1+llListFindList(menuDetails, [currentMenu])), &amp;quot;&amp;quot;);            &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (type==TYPE_LM_NOMENU) {&lt;br /&gt;
            llMessageLinked (LINK_THIS, MSG_DO_LM, message, id);&lt;br /&gt;
            newMenu=FALSE;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (type==TYPE_LM_MENU) {&lt;br /&gt;
            llMessageLinked (LINK_THIS, MSG_DO_LM, message, id);&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (type==TYPE_SOUND) {&lt;br /&gt;
            llMessageLinked (LINK_THIS, MSG_DO_SOUND, message, id);               &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        //some built in messages&lt;br /&gt;
        if (type=TYPE_SPECIAL) {&lt;br /&gt;
        &lt;br /&gt;
            if  (message==&amp;quot;SWAP&amp;quot;) {&lt;br /&gt;
                &lt;br /&gt;
                if ((integer)param) {            &lt;br /&gt;
                    llMessageLinked (LINK_THIS, MSG_DO_SWAP, param, id);&lt;br /&gt;
                }&lt;br /&gt;
                else {&lt;br /&gt;
                    llMessageLinked (LINK_THIS, MSG_MENU_SWAP, (string)channel, id);             &lt;br /&gt;
                    newMenu=FALSE;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
    &lt;br /&gt;
            if  (message==&amp;quot;STOP&amp;quot;) {&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_DO_STOP, &amp;quot;&amp;quot;, id);&lt;br /&gt;
                newMenu=FALSE;&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
                &lt;br /&gt;
            if  (message==&amp;quot;BACK&amp;quot;) {&lt;br /&gt;
                //check menu history&lt;br /&gt;
                string newM=&amp;quot;&amp;quot;;&lt;br /&gt;
                integer i=llGetListLength (menuHistory)-1;            &lt;br /&gt;
                while ((i&amp;gt;0) &amp;amp;&amp;amp; (-1&amp;lt;llListFindList([&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;, &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;], [llList2String(menuHistory, i)]))) i--;&lt;br /&gt;
                if (i&amp;gt;0) {&lt;br /&gt;
                    menuHistory=llList2List(menuHistory, 0, i);&lt;br /&gt;
                    newM=llList2String(menuHistory,i-1);                        &lt;br /&gt;
                }&lt;br /&gt;
                makeMenu(newM, id);&lt;br /&gt;
                newMenu=FALSE;&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if ((message==&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;) || (message==&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;)) {&lt;br /&gt;
                //previous and next. let menumaker solve this.&lt;br /&gt;
                makeMenu(message, id);&lt;br /&gt;
                newMenu=FALSE;&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if (message==&amp;quot;&amp;lt;BACK&amp;quot;) {&lt;br /&gt;
                //makeMenu(currentMenu, id);&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            //anything we don&#039;t know off for some reason. include it anyways.&lt;br /&gt;
            if (message==&amp;quot;DUMP&amp;quot;) {&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_DUMP_POSITIONS, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);                   &lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if (message==&amp;quot;CHAT&amp;quot;) {&lt;br /&gt;
                mode_chat=!mode_chat;&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_MODE_CHAT, (string)mode_chat, id);&lt;br /&gt;
                llRegionSayTo (id, 0, &amp;quot;Chat &amp;quot;+onOff(mode_chat));   &lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if (message==&amp;quot;ADJUST&amp;quot;) {&lt;br /&gt;
                mode_adjust=!mode_adjust;&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_MODE_ADJUST, (string)mode_adjust, id);                &lt;br /&gt;
                llRegionSayTo (id, 0, &amp;quot;Adjusting : &amp;quot;+onOff(mode_adjust));   &lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if (message==&amp;quot;MENUUSERS&amp;quot;) {&lt;br /&gt;
                mode_menu++;&lt;br /&gt;
                if (mode_menu&amp;gt;3)&lt;br /&gt;
                    mode_menu=0;&lt;br /&gt;
                llRegionSayTo (id, 0, &amp;quot;Menu access set to &amp;quot;+aclMode(mode_menu));                   &lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if (message==&amp;quot;BALLUSERS&amp;quot;) {&lt;br /&gt;
                mode_ball++;&lt;br /&gt;
                if (mode_ball&amp;gt;2)&lt;br /&gt;
                    mode_ball=0;&lt;br /&gt;
                llRegionSayTo (id, 0, &amp;quot;Usage access set to &amp;quot;+aclMode(mode_ball));                   &lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_MODE_BALLUSERS, (string)mode_ball, id);                                &lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if (-1&amp;lt;llListFindList ([&amp;quot;RESET&amp;quot;, &amp;quot;RESTART&amp;quot;, &amp;quot;RELOAD&amp;quot;], [message])) {&lt;br /&gt;
                llSay (0, &amp;quot;Reset sequence started... Touch me again in a few seconds to reload the configuration.&amp;quot;);&lt;br /&gt;
                reset(TRUE);   &lt;br /&gt;
                newMenu=FALSE;&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if (message==&amp;quot;Z&amp;quot;) {&lt;br /&gt;
                if (&amp;quot;+&amp;quot;==llGetSubString(param,0,0))&lt;br /&gt;
                    param=llGetSubString(param,1,-1);                &lt;br /&gt;
                llSetObjectDesc((string)((integer)llGetObjectDesc()+(integer)param)+llGetSubString(llGetObjectDesc(), llStringLength((string)((integer)llGetObjectDesc())), -1));&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_UPDATE_POS, (string)mode_ball, id);                &lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if (message==&amp;quot;OFF&amp;quot;) {&lt;br /&gt;
                state Off;&lt;br /&gt;
                newMenu=FALSE;&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if (message==&amp;quot;SAVE&amp;quot;) {&lt;br /&gt;
                defaultPose=currentPose;&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_SET_DEFAULT_POSE, currentPose, &amp;quot;&amp;quot;);&lt;br /&gt;
   &lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if (message==&amp;quot;GRAB&amp;quot;) {&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_RLV_GRAB, &amp;quot;&amp;quot;, id);&lt;br /&gt;
                newMenu=FALSE;                               &lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if (message==&amp;quot;RELEASE&amp;quot;) {&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_RLV_RELEASE, &amp;quot;&amp;quot;, id);                            &lt;br /&gt;
            }&lt;br /&gt;
            else {&lt;br /&gt;
                //forward to whoever handles it&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_DO_SPECIAL, message, id);            &lt;br /&gt;
            }&lt;br /&gt;
        }  &lt;br /&gt;
                  &lt;br /&gt;
        if (newMenu)&lt;br /&gt;
            makeMenu(currentMenu, id);            &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
upgrade() {string self = llGetScriptName(); string basename = self; if (llSubStringIndex(self, &amp;quot; &amp;quot;) &amp;gt;= 0) {integer start = 2; string tail = llGetSubString(self, llStringLength(self) - start, -1); while (llGetSubString(tail, 0, 0) != &amp;quot; &amp;quot;) {start++; tail = llGetSubString(self, llStringLength(self) - start, -1);} if ((integer)tail &amp;gt; 0) {basename = llGetSubString(self, 0, -llStringLength(tail) - 1);}} integer n = llGetInventoryNumber(INVENTORY_SCRIPT); while (n-- &amp;gt; 0) {string item = llGetInventoryName(INVENTORY_SCRIPT, n); if (item != self &amp;amp;&amp;amp; 0 == llSubStringIndex(item, basename)) {llRemoveInventory(item);}}}&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        upgrade();&lt;br /&gt;
        state WaitTouch;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state WaitTouch&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        reset(FALSE);&lt;br /&gt;
        llSay (0,&amp;quot;TMCP resetted - Touch me to load the configuration&amp;quot;);&lt;br /&gt;
    }    &lt;br /&gt;
    touch_start (integer n) {&lt;br /&gt;
        llSay (0,&amp;quot;TMCP startup - reading data&amp;quot;);&lt;br /&gt;
        state reading_data;   &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
state reading_data&lt;br /&gt;
{    &lt;br /&gt;
    state_entry() {&lt;br /&gt;
        llMessageLinked (LINK_THIS, MSG_DATA_START_READ, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);   &lt;br /&gt;
    }&lt;br /&gt;
    link_message (integer sn, integer n, string m, key id) {&lt;br /&gt;
        if (n==MSG_DATA_MENU) {&lt;br /&gt;
            //add action    &lt;br /&gt;
            menuNames+=m;&lt;br /&gt;
            menuEntries+=(string)id;&lt;br /&gt;
        } else&lt;br /&gt;
        if (n==MSG_DATA_MENU_DETAILS) {&lt;br /&gt;
            //add action    &lt;br /&gt;
            menuDetails+= [m, (string)id];&lt;br /&gt;
        } else&lt;br /&gt;
        &lt;br /&gt;
        if (n==MSG_DATA_TYPE) {&lt;br /&gt;
            //set type&lt;br /&gt;
            itemNames+=m;&lt;br /&gt;
            itemTypes+=(integer)((string)id);   &lt;br /&gt;
        }&lt;br /&gt;
        if (n==MSG_SET_RUNNING)&lt;br /&gt;
            state running;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state running {&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llOwnerSay (&amp;quot;Menu ready. &amp;quot;+(string)llGetFreeMemory());&lt;br /&gt;
        channel=-(integer)llFrand(1309123)-492345;&lt;br /&gt;
        listenhandle=llListen (channel, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    touch_start(integer total_number)&lt;br /&gt;
    {&lt;br /&gt;
        key id=llDetectedKey(0);&lt;br /&gt;
        if (!hasDialogAccess(id)) {&lt;br /&gt;
            if (mode_chat)&lt;br /&gt;
                llWhisper (0, &amp;quot;Sorry &amp;quot;+llKey2Name(id)+&amp;quot;, but menu usage is limited to &amp;quot;+aclMode(mode_menu));&lt;br /&gt;
            return;   &lt;br /&gt;
        }        &lt;br /&gt;
        makeMenu(&amp;quot;&amp;quot;,id);&lt;br /&gt;
    } &lt;br /&gt;
    &lt;br /&gt;
    listen (integer ch, string name, key id, string message) {&lt;br /&gt;
        &lt;br /&gt;
        if (!hasDialogAccess(id)) {&lt;br /&gt;
            if (mode_chat)&lt;br /&gt;
                llWhisper (0, &amp;quot;Sorry &amp;quot;+llKey2Name(id)+&amp;quot;, but menu usage is limited to &amp;quot;+aclMode(mode_menu));&lt;br /&gt;
            return;   &lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if (hibernate) {&lt;br /&gt;
            setRunning(TRUE);&lt;br /&gt;
            hibernate=FALSE;   &lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        //llSetTimerEvent (3600.);&lt;br /&gt;
        &lt;br /&gt;
        processCommand (id, message);&lt;br /&gt;
        &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    link_message (integer sn, integer n, string m, key id) {&lt;br /&gt;
        if (n==MSG_DO_MENU_COMMAND) {&lt;br /&gt;
            processCommand (id, m);    &lt;br /&gt;
        }   &lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_DO_DEFAULT_POSE) {&lt;br /&gt;
            currentPose = defaultPose;   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_RLV_VICTIM_LIST) {&lt;br /&gt;
            rlvVictims=llCSV2List(m);   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_DO_MENU_CURRENTMENU) {&lt;br /&gt;
            makeMenu(currentMenu, id);   &lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    timer() {&lt;br /&gt;
        //inactivity detected, sleep all other scripts.        &lt;br /&gt;
        llSetTimerEvent(0.);&lt;br /&gt;
        hibernate=TRUE;&lt;br /&gt;
        setRunning(FALSE);   &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state Off {&lt;br /&gt;
    state_entry() {&lt;br /&gt;
        llMessageLinked (LINK_THIS, MSG_ALL_UNSIT, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);    &lt;br /&gt;
        llWhisper (0,&amp;quot;Switching off in 10... 9...&amp;quot;);&lt;br /&gt;
        llSleep (5.0);&lt;br /&gt;
        setRunning(FALSE);        &lt;br /&gt;
        llSleep (5.0);&lt;br /&gt;
        llSitTarget(ZERO_VECTOR, ZERO_ROTATION);        &lt;br /&gt;
    }   &lt;br /&gt;
    &lt;br /&gt;
    touch_start(integer n) {&lt;br /&gt;
        key id=llDetectedKey(0);&lt;br /&gt;
        if (id==llGetOwner())&lt;br /&gt;
            state running;&lt;br /&gt;
        if ((mode_menu==1) &amp;amp;&amp;amp; llSameGroup(id))&lt;br /&gt;
            state running;&lt;br /&gt;
        llRegionSayTo (id, 0, &amp;quot;Sorry, but this object is switched OFF. Ask the owner to turn it on.&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    state_exit() {&lt;br /&gt;
        setRunning(TRUE);&lt;br /&gt;
        hibernate=FALSE; &lt;br /&gt;
        llWhisper (0, &amp;quot;Switching on&amp;quot;);&lt;br /&gt;
          &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==TMCP - notecard reader==&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
//read MLP notecards&lt;br /&gt;
//see how much memory headroom we got after for other stuff&lt;br /&gt;
&lt;br /&gt;
integer notecardidx;&lt;br /&gt;
key notecardkey;&lt;br /&gt;
integer notecardtype;&lt;br /&gt;
integer notecardline;&lt;br /&gt;
string notecardname;&lt;br /&gt;
list positions;&lt;br /&gt;
list tempMenu;&lt;br /&gt;
list menuNames;&lt;br /&gt;
list menuEntries; //menus that appear in &#039;auto&#039; menu&lt;br /&gt;
list toMenu; //menus with pointers&lt;br /&gt;
list linkedMsg;&lt;br /&gt;
&lt;br /&gt;
integer hasReset=FALSE; //indicates if there is a reset option in *some* menu. If absent, we add it for safety.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
integer TYPE_MENU=1;&lt;br /&gt;
integer TYPE_POSE=2;&lt;br /&gt;
integer TYPE_LM_NOMENU=3;&lt;br /&gt;
integer TYPE_LM_MENU=4;&lt;br /&gt;
integer TYPE_IGNORE=5;&lt;br /&gt;
integer TYPE_SPECIAL=6;&lt;br /&gt;
integer TYPE_UNKNOWN=7;&lt;br /&gt;
integer TYPE_SOUND=8;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DATA_MENU=310;&lt;br /&gt;
integer MSG_DATA_MENU_DETAILS=311;&lt;br /&gt;
integer MSG_DATA_TYPE=320;&lt;br /&gt;
integer MSG_DATA_POSE=330;&lt;br /&gt;
integer MSG_DATA_POSITION=331;&lt;br /&gt;
integer MSG_DATA_LM=335;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_POSE=350;&lt;br /&gt;
integer MSG_DO_LM=351;&lt;br /&gt;
integer MSG_DO_SPECIAL=352;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_STOP=353;&lt;br /&gt;
integer MSG_DO_SWAP=354;&lt;br /&gt;
&lt;br /&gt;
integer MSG_SET_RUNNING=390;&lt;br /&gt;
integer MSG_STORAGE_RESET=391;&lt;br /&gt;
integer MSG_DATA_READY=309;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DATA_START_READ=301;&lt;br /&gt;
&lt;br /&gt;
verbose(string text) {&lt;br /&gt;
    llOwnerSay (text);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
startNotecard() {&lt;br /&gt;
    integer i;&lt;br /&gt;
    notecardline=0;    &lt;br /&gt;
    for (;notecardidx&amp;lt;llGetInventoryNumber(INVENTORY_NOTECARD); notecardidx++) {                &lt;br /&gt;
        //loop until we found appropiate card&lt;br /&gt;
        notecardname=llGetInventoryName(INVENTORY_NOTECARD, notecardidx);&lt;br /&gt;
        if (llGetSubString(notecardname,0,9)==&amp;quot;.MENUITEMS&amp;quot;) {&lt;br /&gt;
            //neato. go fetch it&lt;br /&gt;
            notecardtype=1;&lt;br /&gt;
            notecardkey=llGetNotecardLine(notecardname, 0);&lt;br /&gt;
            verbose (&amp;quot;Reading menu from &amp;quot;+notecardname);&lt;br /&gt;
            return;            &lt;br /&gt;
        }&lt;br /&gt;
        if (llGetSubString(notecardname,0,9)==&amp;quot;.POSITIONS&amp;quot;) {&lt;br /&gt;
            //neato. go fetch it&lt;br /&gt;
            notecardtype=2;&lt;br /&gt;
            notecardkey=llGetNotecardLine(notecardname, 0);&lt;br /&gt;
            verbose (&amp;quot;Reading positions from &amp;quot;+notecardname);&lt;br /&gt;
            return;            &lt;br /&gt;
        }     &lt;br /&gt;
        verbose (&amp;quot;Skipping &amp;quot;+notecardname);&lt;br /&gt;
        &lt;br /&gt;
    }&lt;br /&gt;
    //still here? then we&#039;r done&lt;br /&gt;
    //verbose (&amp;quot;Done reading all notecards&amp;quot;);&lt;br /&gt;
    postFixMenu();&lt;br /&gt;
    sendMenuItems();&lt;br /&gt;
    llSleep (2.0);&lt;br /&gt;
    llMessageLinked (LINK_THIS, MSG_SET_RUNNING, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;); //set to running&lt;br /&gt;
    verbose (&amp;quot;Ready.&amp;quot;);&lt;br /&gt;
    //llOwnerSay (&amp;quot;Notecard reader free memory: &amp;quot;+(string)llGetFreeMemory());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
addPose (string name, list data) {&lt;br /&gt;
    //add pose info.. link to position info exactly when again?   &lt;br /&gt;
    //positions+=[name, data];&lt;br /&gt;
    llMessageLinked (LINK_THIS, MSG_DATA_POSE, name, llDumpList2String(data, &amp;quot;|&amp;quot;));       &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
addMenuDetails (string name, list data) {&lt;br /&gt;
    //add menu details.. access, color of balls.&lt;br /&gt;
    llMessageLinked (LINK_THIS, MSG_DATA_MENU_DETAILS, name, llDumpList2String(data, &amp;quot;|&amp;quot;));       &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
addLM (string name, string data) {&lt;br /&gt;
    llMessageLinked (LINK_THIS, MSG_DATA_LM, name, data);   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setType (string name, integer type) {&lt;br /&gt;
    llMessageLinked (LINK_THIS, MSG_DATA_TYPE, name, (string)type);       &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
parseMenu() {&lt;br /&gt;
    //parse our temporary menu to a real menu;   &lt;br /&gt;
    //this is where the real stuff happens.&lt;br /&gt;
    integer i;&lt;br /&gt;
    string menuName=&amp;quot;&amp;quot;; //MLP 1 compatability: don&#039;t add stuff to menu as long as menu name is empty. add poses though.&lt;br /&gt;
    list options;&lt;br /&gt;
    for (i=0; i&amp;lt;llGetListLength(tempMenu); i++) {&lt;br /&gt;
        string data=llList2String(tempMenu, i);&lt;br /&gt;
        integer posspace=llSubStringIndex(data, &amp;quot; &amp;quot;);&lt;br /&gt;
        string cmd=data;&lt;br /&gt;
        string param=&amp;quot;&amp;quot;;&lt;br /&gt;
        string option=&amp;quot;&amp;quot;;&lt;br /&gt;
        if (posspace&amp;gt;0) {&lt;br /&gt;
            cmd=llGetSubString(data,0,posspace-1);&lt;br /&gt;
            param=llGetSubString(data, posspace+1, -1);   &lt;br /&gt;
        }&lt;br /&gt;
        list paramsTmp=llParseString2List(param, [&amp;quot;|&amp;quot;], []);&lt;br /&gt;
        integer j;&lt;br /&gt;
        list params;&lt;br /&gt;
        for (j=0; j&amp;lt;llGetListLength(paramsTmp); j++)&lt;br /&gt;
            params+=llStringTrim(llList2String(paramsTmp, j), STRING_TRIM);&lt;br /&gt;
        //params are now nice seperated on |, still allowed to contain spaces in the middle but trimmed from the outside.&lt;br /&gt;
        string p1=llList2String(params, 0);&lt;br /&gt;
        string p2=llList2String(params, 1);&lt;br /&gt;
        string p3=llList2String(params, 2);&lt;br /&gt;
        //got our set of command and optional parameters now. let&#039;s test them.&lt;br /&gt;
        if (cmd==&amp;quot;MENU&amp;quot;) {&lt;br /&gt;
            addMenuDetails (p1, llDeleteSubList(params,0,0));&lt;br /&gt;
            //menuEntries+=p1;&lt;br /&gt;
            menuName=p1; //additional params hint the number of available seats            &lt;br /&gt;
            setType (p1, TYPE_MENU);  &lt;br /&gt;
        } else&lt;br /&gt;
        if (cmd==&amp;quot;POSE&amp;quot;) {&lt;br /&gt;
            addPose (p1, llDeleteSubList(params,0,0));   &lt;br /&gt;
            option = p1;&lt;br /&gt;
            setType (p1, TYPE_POSE);&lt;br /&gt;
        } else&lt;br /&gt;
        if (cmd==&amp;quot;SOUND&amp;quot;) {&lt;br /&gt;
            addLM (p1, p2);   &lt;br /&gt;
            option = p1;&lt;br /&gt;
            setType (p1, TYPE_SOUND);&lt;br /&gt;
        } else&lt;br /&gt;
        if (-1 != llListFindList ([&amp;quot;BACK&amp;quot;, &amp;quot;STOP&amp;quot;,&amp;quot;SWAP&amp;quot;,&amp;quot;RESET&amp;quot;,&amp;quot;RESTART&amp;quot;, &amp;quot;MENUUSERS&amp;quot;, &amp;quot;BALLUSERS&amp;quot;,&amp;quot;ADJUST&amp;quot;, &amp;quot;DUMP&amp;quot;, &amp;quot;CHAT&amp;quot;, &amp;quot;RELOAD&amp;quot;, &amp;quot;OFF&amp;quot;], [cmd])) {&lt;br /&gt;
            //recognized simple options&lt;br /&gt;
            option = cmd;   &lt;br /&gt;
            setType (cmd, TYPE_SPECIAL);&lt;br /&gt;
            if (-1!= llListFindList ([&amp;quot;RESET&amp;quot;,&amp;quot;RESTART&amp;quot;, &amp;quot;RELOAD&amp;quot;], [cmd]))&lt;br /&gt;
                hasReset=TRUE;&lt;br /&gt;
        } else&lt;br /&gt;
        if (-1 != llListFindList ([&amp;quot;SAVE&amp;quot;, &amp;quot;CHECK&amp;quot;], [cmd])) {&lt;br /&gt;
            //recognized simple options&lt;br /&gt;
            option = cmd;   &lt;br /&gt;
            setType (cmd, TYPE_IGNORE);&lt;br /&gt;
        } else&lt;br /&gt;
        if (cmd==&amp;quot;TOMENU&amp;quot;) {&lt;br /&gt;
            if (p1!=&amp;quot;-&amp;quot;)&lt;br /&gt;
                toMenu+=p1;&lt;br /&gt;
            option=p1;   &lt;br /&gt;
        } else&lt;br /&gt;
        if (cmd==&amp;quot;LINKMSG&amp;quot;) {&lt;br /&gt;
            //linkedMsg+=[p1,p2];&lt;br /&gt;
            addLM (p1, p2);&lt;br /&gt;
            option=p1;&lt;br /&gt;
            if ((integer)p2)&lt;br /&gt;
                setType (p1, TYPE_LM_NOMENU);&lt;br /&gt;
            else&lt;br /&gt;
                setType (p1, TYPE_LM_MENU);&lt;br /&gt;
        } else&lt;br /&gt;
        if (-1&amp;lt;llListFindList([&amp;quot;Z+&amp;quot;, &amp;quot;Z-&amp;quot;], [llGetSubString(cmd, 0, 1)])) {&lt;br /&gt;
            //Z command, we&#039;ll rewrite it&lt;br /&gt;
            option = &amp;quot;Z::&amp;quot;+llGetSubString(cmd, 1, -1);&lt;br /&gt;
            setType (&amp;quot;Z&amp;quot;, TYPE_SPECIAL);&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (-1&amp;lt;llListFindList ([&amp;quot;GRAB&amp;quot;, &amp;quot;Grab.Fem&amp;quot;], [cmd])) {&lt;br /&gt;
            option = &amp;quot;GRAB&amp;quot;;&lt;br /&gt;
            setType (&amp;quot;GRAB&amp;quot;, TYPE_SPECIAL);               &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (-1&amp;lt;llListFindList ([&amp;quot;Grab.Male&amp;quot;,&amp;quot;RELEASE&amp;quot;], [cmd])) {&lt;br /&gt;
            option = &amp;quot;RELEASE&amp;quot;;&lt;br /&gt;
            setType (&amp;quot;RELEASE&amp;quot;, TYPE_SPECIAL);                           &lt;br /&gt;
        }&lt;br /&gt;
        //todo.. fill in a bunch of MLP commands here, implemented or not&lt;br /&gt;
        else&lt;br /&gt;
        { //we checked all commands. Anything defined here is considered undefined and we list it just as is.&lt;br /&gt;
            option = cmd;&lt;br /&gt;
            //don&#039;t set type. it may be defined elsewhere.&lt;br /&gt;
            //setType (cmd, TYPE_UNKNOWN);            &lt;br /&gt;
        }&lt;br /&gt;
        if (menuName) if (option)&lt;br /&gt;
            options+=option;&lt;br /&gt;
    }&lt;br /&gt;
    tempMenu=[];&lt;br /&gt;
    if (options!=[]) {&lt;br /&gt;
        llOwnerSay (&amp;quot;Menu &amp;quot;+menuName +&amp;quot; [&amp;quot;+(string)llGetListLength(options)+&amp;quot;]&amp;quot;);&lt;br /&gt;
        //menuAll+=options+&amp;quot;!--!&amp;quot;;&lt;br /&gt;
        //menuAll+=[menuName,llList2CSV(options)];&lt;br /&gt;
        menuNames+=menuName;&lt;br /&gt;
        menuEntries+=llList2CSV(options);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
addMenuItem(string data) {&lt;br /&gt;
    integer posslash=llSubStringIndex(data, &amp;quot;//&amp;quot;);&lt;br /&gt;
    if (posslash&amp;gt;=0) {&lt;br /&gt;
        data=llDeleteSubString(data, posslash, -1);&lt;br /&gt;
    }&lt;br /&gt;
    data=llStringTrim(data,STRING_TRIM);&lt;br /&gt;
    //llOwnerSay (&amp;quot;menu data: &amp;quot;+data);&lt;br /&gt;
    &lt;br /&gt;
    if (data==&amp;quot;&amp;quot;) //comment or some but not empty line, silently ignore&lt;br /&gt;
        return;&lt;br /&gt;
    &lt;br /&gt;
    if (llGetSubString (data,0,3+1)==&amp;quot;MENU &amp;quot;) {&lt;br /&gt;
        //what a surprise, new menu. finish old one.&lt;br /&gt;
        parseMenu();&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //what&#039;s left, add it to our temp menu. We&#039;l parse it later.&lt;br /&gt;
    tempMenu+=data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
postFixMenu() {&lt;br /&gt;
    //on failed configurations - add some default stuff&lt;br /&gt;
    if (!llGetListLength(menuNames)) {&lt;br /&gt;
        &lt;br /&gt;
        llOwnerSay (&amp;quot;Warning - no reset function found in menu cards. Adding menu &#039;Reset&#039;.&amp;quot;);&lt;br /&gt;
        //add a default menu with a reset button.&lt;br /&gt;
        &lt;br /&gt;
        addMenuItem (&amp;quot;MENU Reset...|OWNER&amp;quot;);&lt;br /&gt;
        addMenuItem (&amp;quot;RESET&amp;quot;);&lt;br /&gt;
        parseMenu();&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    //dont add mainmenu&lt;br /&gt;
    list entries=llDeleteSubList(menuNames,0,0);&lt;br /&gt;
    &lt;br /&gt;
    integer i;&lt;br /&gt;
    &lt;br /&gt;
    //llOwnerSay (&amp;quot;PF entries: &amp;quot;+(string)entries);&lt;br /&gt;
    //llOwnerSay (&amp;quot;PF tomenu: &amp;quot;+(string)toMenu);    &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    for (i=0; i&amp;lt;llGetListLength(toMenu); i++) {        &lt;br /&gt;
        integer j=llListFindList (entries, [llList2String(toMenu, i)]);&lt;br /&gt;
        if (j&amp;gt;-1) {&lt;br /&gt;
            entries=llDeleteSubList(entries, j, j);&lt;br /&gt;
        }        &lt;br /&gt;
    }&lt;br /&gt;
    //llOwnerSay (&amp;quot;PF entries after: &amp;quot;+(string)entries);&lt;br /&gt;
    &lt;br /&gt;
    list MainMenu=llCSV2List(llList2String(menuEntries, 0));&lt;br /&gt;
    for (i=0; i&amp;lt;llGetListLength(entries); i++) {&lt;br /&gt;
        integer j=llListFindList(MainMenu, [&amp;quot;-&amp;quot;]);&lt;br /&gt;
        if (j&amp;gt;-1) {&lt;br /&gt;
            MainMenu=llListReplaceList(MainMenu, [llList2String(entries, i)], j, j);            &lt;br /&gt;
        }   &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    i=llListFindList(MainMenu, [&amp;quot;-&amp;quot;]);&lt;br /&gt;
    while (-1&amp;lt;i) {&lt;br /&gt;
        MainMenu=llDeleteSubList(MainMenu, i, i);&lt;br /&gt;
        i=llListFindList(MainMenu, [&amp;quot;-&amp;quot;]);               &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    if (MainMenu)&lt;br /&gt;
        menuEntries = llListReplaceList(menuEntries, [llList2CSV(MainMenu)], 0, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sendMenuItems() {&lt;br /&gt;
    //llOwnerSay (&amp;quot;Applying menu information&amp;quot;);&lt;br /&gt;
    &lt;br /&gt;
    integer i;&lt;br /&gt;
    for (i=0; i&amp;lt;llGetListLength(menuNames); i++) {&lt;br /&gt;
        llMessageLinked (LINK_THIS, MSG_DATA_MENU, llList2String(menuNames, i), llList2String(menuEntries, i));            &lt;br /&gt;
        llSleep (0.25);&lt;br /&gt;
    }    &lt;br /&gt;
    &lt;br /&gt;
    llMessageLinked (LINK_THIS, MSG_DATA_READY, &amp;quot;Done&amp;quot;, &amp;quot;TTP&amp;quot;);    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
addPosition(string data) {&lt;br /&gt;
    //some memory optimalization possible here in last half.&lt;br /&gt;
    integer curlyopen = llSubStringIndex(data, &amp;quot;{&amp;quot;);&lt;br /&gt;
    integer curlyclose = llSubStringIndex(data, &amp;quot;}&amp;quot;);&lt;br /&gt;
    if ((curlyopen&amp;lt;0) || (curlyclose&amp;lt;curlyopen))&lt;br /&gt;
        return;&lt;br /&gt;
    string pose=llGetSubString(data, curlyopen+1, curlyclose-1);&lt;br /&gt;
    data=llGetSubString(data, curlyclose+1, -1);&lt;br /&gt;
    list posrotsraw=llParseString2List(data, [&amp;quot;&amp;gt;&amp;quot;], []);&lt;br /&gt;
    //llOwnerSay (&amp;quot;raw pos data &amp;quot;+data+&amp;quot; convert to &amp;quot;+(string)posrotsraw);&lt;br /&gt;
    &lt;br /&gt;
    list posrots;&lt;br /&gt;
    integer i;&lt;br /&gt;
    for (i=0; i&amp;lt;llGetListLength(posrotsraw); i++) {&lt;br /&gt;
        if (-1&amp;lt;llSubStringIndex (llList2String(posrotsraw,i), &amp;quot;&amp;lt;&amp;quot;)) {&lt;br /&gt;
            list v=llParseString2List(llList2String(posrotsraw,i), [&amp;quot;&amp;lt;&amp;quot;, &amp;quot;,&amp;quot;, &amp;quot; &amp;quot;], []);         &lt;br /&gt;
            posrots += &amp;lt;(float)llList2String(v,0), (float)llList2String(v,1),(float)llList2String(v,2)&amp;gt;;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //llOwnerSay (&amp;quot;position data for &amp;quot;+pose+&amp;quot; : &amp;quot;+(string)posrots);&lt;br /&gt;
    //positions+=[pose, llList2CSV(posrots)];&lt;br /&gt;
    llMessageLinked (LINK_THIS,MSG_DATA_POSITION, pose, llDumpList2String(posrots,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
upgrade() {string self = llGetScriptName(); string basename = self; if (llSubStringIndex(self, &amp;quot; &amp;quot;) &amp;gt;= 0) {integer start = 2; string tail = llGetSubString(self, llStringLength(self) - start, -1); while (llGetSubString(tail, 0, 0) != &amp;quot; &amp;quot;) {start++; tail = llGetSubString(self, llStringLength(self) - start, -1);} if ((integer)tail &amp;gt; 0) {basename = llGetSubString(self, 0, -llStringLength(tail) - 1);}} integer n = llGetInventoryNumber(INVENTORY_SCRIPT); while (n-- &amp;gt; 0) {string item = llGetInventoryName(INVENTORY_SCRIPT, n); if (item != self &amp;amp;&amp;amp; 0 == llSubStringIndex(item, basename)) {llRemoveInventory(item);}}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
default &lt;br /&gt;
{&lt;br /&gt;
    state_entry() {        &lt;br /&gt;
        upgrade();&lt;br /&gt;
        //state ReadMenu;           &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    link_message (integer sn, integer n, string m, key id) {&lt;br /&gt;
        if (n==301)&lt;br /&gt;
            state ReadMenu;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state ReadMenu&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llMessageLinked (LINK_THIS, MSG_STORAGE_RESET, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;); //reset data storage scripts&lt;br /&gt;
        llSleep (2.0);&lt;br /&gt;
        //fetch first notecard, go on from there&lt;br /&gt;
        startNotecard ();&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    dataserver(key id, string data) {&lt;br /&gt;
        //llOwnerSay (&amp;quot;card &amp;quot;+notecardname+&amp;quot; line &amp;quot;+(string)notecardline+&amp;quot; data &amp;quot;+data);&lt;br /&gt;
        &lt;br /&gt;
        if (id!=notecardkey)&lt;br /&gt;
            return; //not for us&lt;br /&gt;
            &lt;br /&gt;
        if (data==EOF) {&lt;br /&gt;
            if (notecardtype==1)&lt;br /&gt;
                parseMenu(); //clean up any menu leftovers&lt;br /&gt;
            //read next notecard&lt;br /&gt;
            notecardidx++;&lt;br /&gt;
            startNotecard();&lt;br /&gt;
        } else   &lt;br /&gt;
        {&lt;br /&gt;
            if (notecardtype==1)&lt;br /&gt;
                addMenuItem(data);&lt;br /&gt;
            else&lt;br /&gt;
                addPosition(data);&lt;br /&gt;
            notecardkey=llGetNotecardLine(notecardname, ++notecardline);&lt;br /&gt;
&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==TMCP RLV extensions (optional)==&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
//Changes by Tano Toll for seamless MLCP compatability, and to dodge &#039;double locking&#039;:&lt;br /&gt;
&lt;br /&gt;
//*sit and unsit events do not trigger an RLV command (master script already does this)&lt;br /&gt;
//*identifier is changed to object name, url encoded.&lt;br /&gt;
//*delayed but automatic notecard read on inventory change&lt;br /&gt;
&lt;br /&gt;
// ----------------------------------------------------------------------------------&lt;br /&gt;
// MLPV2 Plugin for RLV Script V1.02&lt;br /&gt;
//&lt;br /&gt;
// Use with a notecard named .RLV with the format:&lt;br /&gt;
// Pose|Ball no.: 0,1...*|@RLV-Command&lt;br /&gt;
// e.g.&lt;br /&gt;
// Missionary|1|@unsit=n&lt;br /&gt;
// stand|*|!release&lt;br /&gt;
// ----------------------------------------------------------------------------------&lt;br /&gt;
// Copyright (c) 2010, Jenni Eales. All rights reserved.&lt;br /&gt;
// ----------------------------------------------------------------------------------&lt;br /&gt;
// Redistribution and use in source and binary forms, with or without modification,&lt;br /&gt;
// are permitted provided that the following conditions are met:&lt;br /&gt;
//&lt;br /&gt;
//    * Redistributions of source code must retain the above copyright notice,&lt;br /&gt;
//      this list of conditions and the following disclaimer.&lt;br /&gt;
//    * Redistributions in binary form must reproduce the above copyright notice,&lt;br /&gt;
//      this list of conditions and the following disclaimer in the documentation&lt;br /&gt;
//      and/or other materials provided with the distribution.&lt;br /&gt;
//    * The names of its contributors may not be used to endorse or promote products&lt;br /&gt;
//      derived from this software without specific prior written permission.&lt;br /&gt;
//&lt;br /&gt;
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &amp;quot;AS IS&amp;quot; AND ANY&lt;br /&gt;
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES&lt;br /&gt;
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.&lt;br /&gt;
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,&lt;br /&gt;
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,&lt;br /&gt;
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,&lt;br /&gt;
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,&lt;br /&gt;
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)&lt;br /&gt;
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY&lt;br /&gt;
// OF SUCH DAMAGE.&lt;br /&gt;
//&lt;br /&gt;
// Changes:&lt;br /&gt;
// ----------------------------------------------------------------------------------&lt;br /&gt;
// Version 1.02&lt;br /&gt;
// - use | as seperator&lt;br /&gt;
// - support multiple lines for one pose&lt;br /&gt;
// - additional link message for direct call from ball menu&lt;br /&gt;
//&lt;br /&gt;
// Version 1.01&lt;br /&gt;
// - use ; instead of | as seperator&lt;br /&gt;
//&lt;br /&gt;
// Version 1.0&lt;br /&gt;
// - first version released&lt;br /&gt;
// ----------------------------------------------------------------------------------&lt;br /&gt;
//&lt;br /&gt;
// constants&lt;br /&gt;
string NOTECARD         = &amp;quot;.RLV&amp;quot;; // name of config notecard&lt;br /&gt;
integer DEBUG           = FALSE;  // switch debug on/off&lt;br /&gt;
integer RELAY_CHANNEL   = -1812221819; // channel for RLV relay&lt;br /&gt;
float TIMER_SEC         = 1800.0; // 30 min.&lt;br /&gt;
string CMD_RELEASE      = &amp;quot;!release&amp;quot;;  // release command&lt;br /&gt;
integer LM_NUMBER       = -1819;  // number for link message&lt;br /&gt;
 &lt;br /&gt;
// internal use&lt;br /&gt;
key kQuery;&lt;br /&gt;
integer iLine;&lt;br /&gt;
 &lt;br /&gt;
string pose = &amp;quot;stand&amp;quot;; // pose set by the Ball Menu&lt;br /&gt;
list poses    = [];    // configured poses&lt;br /&gt;
list balls    = [];    // configured balls&lt;br /&gt;
list commands = [];    // configured commands&lt;br /&gt;
list avatars  = [];    // avatars sitting on balls&lt;br /&gt;
&lt;br /&gt;
integer wants_init;&lt;br /&gt;
 &lt;br /&gt;
// log a message&lt;br /&gt;
log(string message)&lt;br /&gt;
{&lt;br /&gt;
    if(DEBUG) llOwnerSay(message);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// only for testing purposes&lt;br /&gt;
log_data()&lt;br /&gt;
{&lt;br /&gt;
    log(&amp;quot;List:&amp;quot;);&lt;br /&gt;
    integer total_number = llGetListLength(commands);&lt;br /&gt;
    integer i;&lt;br /&gt;
    for(i=0; i&amp;lt;total_number; i++)&lt;br /&gt;
    {&lt;br /&gt;
        log(&amp;quot;- &amp;quot; + llList2String(poses, i) + &amp;quot;: (&amp;quot; + llList2String(balls, i) + &amp;quot;) &amp;quot;+ llList2String(commands, i));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// write a message to the RLV Relay&lt;br /&gt;
relay(key avatar, string message)&lt;br /&gt;
{&lt;br /&gt;
    list tokens = llParseString2List(message, [&amp;quot;|&amp;quot;], [&amp;quot;&amp;quot;]);&lt;br /&gt;
    integer total_number = llGetListLength(tokens);&lt;br /&gt;
    integer i;&lt;br /&gt;
    for(i=0; i&amp;lt;total_number; i++)&lt;br /&gt;
    {&lt;br /&gt;
        string token = llList2String(tokens, i);&lt;br /&gt;
        log(&amp;quot;RLV: MLPV2,&amp;quot; + (string) avatar + &amp;quot;,&amp;quot; + token);&lt;br /&gt;
        llSay(RELAY_CHANNEL, llEscapeURL(llGetObjectName())+&amp;quot;,&amp;quot; + (string) avatar + &amp;quot;,&amp;quot; + token);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// find commands for pose and play it for avatars on ball&lt;br /&gt;
rlv(string pose)&lt;br /&gt;
{&lt;br /&gt;
    log(&amp;quot;command for: &amp;quot; + pose);&lt;br /&gt;
    llSetTimerEvent(TIMER_SEC);&lt;br /&gt;
 &lt;br /&gt;
    integer total_number = llGetListLength(poses);&lt;br /&gt;
    integer i;&lt;br /&gt;
    for(i=0; i&amp;lt;total_number; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if (pose == llList2String(poses, i))&lt;br /&gt;
        {&lt;br /&gt;
            string ball = llList2String(balls, i);&lt;br /&gt;
            log(&amp;quot;command for pose: &amp;quot; + pose + &amp;quot; (&amp;quot; + ball + &amp;quot;)&amp;quot;);&lt;br /&gt;
            if (ball == &amp;quot;*&amp;quot;)&lt;br /&gt;
            {&lt;br /&gt;
                integer b;&lt;br /&gt;
                for (b=0; b&amp;lt;6; b++)&lt;br /&gt;
                {&lt;br /&gt;
                    // get avatar for ball index&lt;br /&gt;
                    key avatar = llList2Key(avatars, b);&lt;br /&gt;
                    if(avatar != NULL_KEY) relay(avatar, llList2String(commands, i));&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                key avatar = llList2Key(avatars, (integer) ball);&lt;br /&gt;
                if(avatar != NULL_KEY) relay(avatar, llList2String(commands, i));&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// new find: pose and ball needs to match&lt;br /&gt;
integer find_pose(string pose, string ball)&lt;br /&gt;
{&lt;br /&gt;
    integer total_number = llGetListLength(poses);&lt;br /&gt;
    integer i;&lt;br /&gt;
    for(i=0; i&amp;lt;total_number; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if (pose == llList2String(poses, i) &amp;amp;&amp;amp; ball == llList2String(balls, i))&lt;br /&gt;
        {&lt;br /&gt;
            return i;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return -1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// add a pose/ball/command entry&lt;br /&gt;
add_pose(string pose, string ball, string command)&lt;br /&gt;
{&lt;br /&gt;
    // look for existing entry for pose&lt;br /&gt;
    integer found = find_pose(pose, ball);&lt;br /&gt;
    if (found == -1)&lt;br /&gt;
    {&lt;br /&gt;
        // add a new pose&lt;br /&gt;
        poses += [pose];&lt;br /&gt;
        balls += [ball];&lt;br /&gt;
        commands += [command];&lt;br /&gt;
 &lt;br /&gt;
        log(&amp;quot;Added from &amp;quot; + NOTECARD + &amp;quot;: &amp;quot; + pose + &amp;quot; | &amp;quot; + ball + &amp;quot; | &amp;quot; + command);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        // append to existing pose&lt;br /&gt;
        string c = llList2String(commands, found) + &amp;quot;|&amp;quot; + command;&lt;br /&gt;
        commands = llListReplaceList(commands, [c], found, found);&lt;br /&gt;
 &lt;br /&gt;
        log(&amp;quot;Added &amp;quot; + command + &amp;quot; to pose &amp;quot; + pose);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// parse and store a line&lt;br /&gt;
process_line(string line)&lt;br /&gt;
{&lt;br /&gt;
    list tokens = llParseString2List(line, [&amp;quot;  |  &amp;quot;,&amp;quot;  | &amp;quot;,&amp;quot; |  &amp;quot;,&amp;quot; | &amp;quot;,&amp;quot; |&amp;quot;,&amp;quot;| &amp;quot;,&amp;quot;|&amp;quot;],[&amp;quot;&amp;quot;]);&lt;br /&gt;
    if(llGetListLength(tokens) &amp;lt; 3) return;&lt;br /&gt;
 &lt;br /&gt;
    string pose = llList2String(tokens, 0);&lt;br /&gt;
    string ball = llList2String(tokens, 1);&lt;br /&gt;
 &lt;br /&gt;
    integer total_number = llGetListLength(tokens);&lt;br /&gt;
    integer i;&lt;br /&gt;
    for(i=2; i&amp;lt;total_number; i++)&lt;br /&gt;
    {&lt;br /&gt;
        add_pose(pose, ball, llList2String(tokens, i));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// check if object is in the inventory&lt;br /&gt;
integer exists_notecard(string notecard) {&lt;br /&gt;
    return llGetInventoryType(notecard) == INVENTORY_NOTECARD;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// initialize me&lt;br /&gt;
initialize()&lt;br /&gt;
{&lt;br /&gt;
    log(&amp;quot;Initializing...&amp;quot;);&lt;br /&gt;
    poses = [];&lt;br /&gt;
    balls = [];&lt;br /&gt;
    commands = [];&lt;br /&gt;
    avatars = [NULL_KEY, NULL_KEY, NULL_KEY, NULL_KEY, NULL_KEY, NULL_KEY];&lt;br /&gt;
 &lt;br /&gt;
    if (exists_notecard(NOTECARD))&lt;br /&gt;
    {&lt;br /&gt;
        log(&amp;quot;Reading &amp;quot; + NOTECARD + &amp;quot;...&amp;quot;);&lt;br /&gt;
        iLine = 0;&lt;br /&gt;
        kQuery = llGetNotecardLine(NOTECARD, iLine);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        llOwnerSay(&amp;quot;Not found: &amp;quot; + NOTECARD );&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
upgrade() {string self = llGetScriptName(); string basename = self; if (llSubStringIndex(self, &amp;quot; &amp;quot;) &amp;gt;= 0) {integer start = 2; string tail = llGetSubString(self, llStringLength(self) - start, -1); while (llGetSubString(tail, 0, 0) != &amp;quot; &amp;quot;) {start++; tail = llGetSubString(self, llStringLength(self) - start, -1);} if ((integer)tail &amp;gt; 0) {basename = llGetSubString(self, 0, -llStringLength(tail) - 1);}} integer n = llGetInventoryNumber(INVENTORY_SCRIPT); while (n-- &amp;gt; 0) {string item = llGetInventoryName(INVENTORY_SCRIPT, n); if (item != self &amp;amp;&amp;amp; 0 == llSubStringIndex(item, basename)) {llRemoveInventory(item);}}}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    // on state entry initialize me&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        upgrade();&lt;br /&gt;
        &lt;br /&gt;
        initialize();&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    // reset on Inventory change&lt;br /&gt;
    changed(integer change)&lt;br /&gt;
    {&lt;br /&gt;
        if (change &amp;amp; CHANGED_INVENTORY) {&lt;br /&gt;
            wants_init=TRUE;&lt;br /&gt;
            llSetTimerEvent (15.0);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    // read a line from notecard&lt;br /&gt;
    dataserver(key _query_id, string _data) {&lt;br /&gt;
        // were we called to work on notecard?&lt;br /&gt;
        if (_query_id == kQuery) {&lt;br /&gt;
            // this is a line of our notecard&lt;br /&gt;
            if (_data == EOF) {&lt;br /&gt;
                if (DEBUG) log_data();&lt;br /&gt;
                log(NOTECARD + &amp;quot; read.&amp;quot;);&lt;br /&gt;
            } else {&lt;br /&gt;
                    // increment line count&lt;br /&gt;
                    // data has the current line from this notecard&lt;br /&gt;
                    if(_data != &amp;quot;&amp;quot;) {&lt;br /&gt;
                        process_line(_data);&lt;br /&gt;
                    }&lt;br /&gt;
 &lt;br /&gt;
                // request next line&lt;br /&gt;
                // read another line when you can&lt;br /&gt;
                iLine++;&lt;br /&gt;
                kQuery = llGetNotecardLine(NOTECARD, iLine);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    timer()&lt;br /&gt;
    {&lt;br /&gt;
        if (wants_init) {&lt;br /&gt;
            wants_init = FALSE;&lt;br /&gt;
              initialize();        &lt;br /&gt;
            llSetTimerEvent (0.0);&lt;br /&gt;
            return;    &lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        integer b;&lt;br /&gt;
        for (b=0; b&amp;lt;6; b++)&lt;br /&gt;
        {&lt;br /&gt;
            // get avatar for ball index&lt;br /&gt;
            key avatar = llList2Key(avatars, b);&lt;br /&gt;
 &lt;br /&gt;
            // if not null send command&lt;br /&gt;
            if(avatar != NULL_KEY) relay(avatar, CMD_RELEASE);&lt;br /&gt;
        }&lt;br /&gt;
        llSetTimerEvent(0.0);&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    // link message from MLPV2&lt;br /&gt;
    link_message(integer sender_number, integer number, string message, key id)&lt;br /&gt;
    {&lt;br /&gt;
        /*&lt;br /&gt;
        // pose from ball menu selected&lt;br /&gt;
        if (number == 0 &amp;amp;&amp;amp; message == &amp;quot;POSEB&amp;quot;) {&lt;br /&gt;
            pose = (string)id;&lt;br /&gt;
            rlv(pose);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        */&lt;br /&gt;
 &lt;br /&gt;
        // direct call from ball menu&lt;br /&gt;
        // configure in .MENUITEMS with&lt;br /&gt;
        // LINKMSG Resctriction | 0,-1,-1819,Restriction&lt;br /&gt;
        if (number == LM_NUMBER) {&lt;br /&gt;
            //llOwnerSay (&amp;quot;RLV: -- &amp;quot;+message);&lt;br /&gt;
            pose = message;&lt;br /&gt;
            rlv(pose);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        // unsit avatar&lt;br /&gt;
        if (number == -11001)&lt;br /&gt;
        {&lt;br /&gt;
            integer ball = (integer) message;&lt;br /&gt;
            log(&amp;quot;Avatar unsit from ball &amp;quot; + (string) ball +&amp;quot;: &amp;quot; + (string) llList2Key(avatars, ball));&lt;br /&gt;
            //relay(llList2Key(avatars, ball), CMD_RELEASE);&lt;br /&gt;
            avatars = llListReplaceList(avatars, [NULL_KEY], ball, ball);&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        // sit avatar&lt;br /&gt;
        if (number == -11000)&lt;br /&gt;
        {&lt;br /&gt;
            list tokens = llParseString2List(message, [&amp;quot;|&amp;quot;], [&amp;quot; &amp;quot;]);&lt;br /&gt;
            integer ball = llList2Integer(tokens, 0);&lt;br /&gt;
            log(&amp;quot;Avatar sit on ball &amp;quot; + (string) ball +&amp;quot;: &amp;quot; + (string) id);&lt;br /&gt;
            avatars = llListReplaceList(avatars, [id], ball, ball);&lt;br /&gt;
            //rlv(pose);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tano Toll</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:Tano_Toll&amp;diff=1171656</id>
		<title>User:Tano Toll</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:Tano_Toll&amp;diff=1171656"/>
		<updated>2012-08-15T13:38:16Z</updated>

		<summary type="html">&lt;p&gt;Tano Toll: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some of my work for the public domain:&lt;br /&gt;
&lt;br /&gt;
* [[TMCP]] - Tano&#039;s MLP Compatible Pose Scripts - poseball free drop-in replacement for MLPv2&lt;br /&gt;
&lt;br /&gt;
* [[ParcelChatRelay]] - Parcel Chat Relay efficiently allows parcel-wide channel0 talk&lt;br /&gt;
&lt;br /&gt;
* [[Stream_Music_In_PHP]] - Stream a static mp3 stream, synchronized for all listeners, using php&lt;/div&gt;</summary>
		<author><name>Tano Toll</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=TMCP&amp;diff=1171655</id>
		<title>TMCP</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=TMCP&amp;diff=1171655"/>
		<updated>2012-08-15T13:37:08Z</updated>

		<summary type="html">&lt;p&gt;Tano Toll: TMCP - MLP Compatible Pose Scripts - Open source (BSD license)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TMCP - Tano&#039;s MLP Compatible Pose scripts&lt;br /&gt;
*a drop in replacement for MLPv2&lt;br /&gt;
*configuration notecard compatible&lt;br /&gt;
*Since august 14. 2012 released under the open source BSD license&lt;br /&gt;
&lt;br /&gt;
Collection of scripts as of version 0.37 below, or available on marketplace for your convenience https://marketplace.secondlife.com/p/TMCP-Tanos-MLP-Compatible-Pose-Scripts-Source-Edition/2964611&lt;br /&gt;
&lt;br /&gt;
Resident &#039;Camden McAndrews&#039; voluntueered as new maintainer. I hope the MLPv2 team will pick it up.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==TMCP Sitmanager==&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
//keeps track of sitted target, position them and animate them.&lt;br /&gt;
&lt;br /&gt;
list animPool; //pool of scripts that are able to pose targets&lt;br /&gt;
&lt;br /&gt;
list poolCache; //try re-use same script for same agent, to avoid reasking permissions&lt;br /&gt;
&lt;br /&gt;
list sitted; //strided, holds: AGENT_KEY, logical offset (`ball number`), [animscript?], current animation?, current position?&lt;br /&gt;
integer sittedStride=3;&lt;br /&gt;
&lt;br /&gt;
list sittedAgents;&lt;br /&gt;
list sitScripts;&lt;br /&gt;
&lt;br /&gt;
integer MSG_AGENT_UNSIT = 380;&lt;br /&gt;
integer MSG_ALL_UNSIT =381;&lt;br /&gt;
integer MSG_DISABLE_SITTING =382;&lt;br /&gt;
integer MSG_REGISTER_SITSCRIPT =383;&lt;br /&gt;
integer MSG_QUERY_SITSCRIPT = 385;&lt;br /&gt;
integer MSG_RESET =0;&lt;br /&gt;
integer MSG_ENABLE_SITTING=0;&lt;br /&gt;
integer MSG_SET_SITTARGET=375;&lt;br /&gt;
integer MSG_PLAY_ANIM=390;&lt;br /&gt;
integer MSG_STOP_ANIM=391;&lt;br /&gt;
integer MSG_AGENT_PLAY_ANIM=395; // to notify the slave script&lt;br /&gt;
integer MSG_AGENT_STOP_ANIM=396;&lt;br /&gt;
integer MSG_ATTACH_AGENT = 398;&lt;br /&gt;
integer MSG_DETACH_AGENT = 399;&lt;br /&gt;
integer MSG_RUN_ANIMS=379;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_STOP=353;&lt;br /&gt;
integer MSG_DO_SWAP=354;&lt;br /&gt;
integer MSG_MENU_SWAP=355; &lt;br /&gt;
&lt;br /&gt;
integer MSG_MENU_META=333;&lt;br /&gt;
&lt;br /&gt;
integer MSG_MLP_SITTED=-11000;&lt;br /&gt;
integer MSG_MLP_UNSITTED=-11001;&lt;br /&gt;
&lt;br /&gt;
integer MSG_MODE_BALLUSERS=366;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_DEFAULT_POSE = 358;&lt;br /&gt;
&lt;br /&gt;
integer MSG_RLV_GRAB=308;&lt;br /&gt;
integer MSG_RLV_RELEASE=309;&lt;br /&gt;
integer MSG_RLV_VICTIM_LIST=307;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_MENU_CURRENTMENU = 305;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//keys to controlling:&lt;br /&gt;
//animname+index is key to both real animation name and it&#039;s position.&lt;br /&gt;
&lt;br /&gt;
list agentAnims;&lt;br /&gt;
&lt;br /&gt;
list agentScripts;&lt;br /&gt;
list agentScriptCache;&lt;br /&gt;
&lt;br /&gt;
list agentPoseIdx;&lt;br /&gt;
&lt;br /&gt;
list usedIndexes; //logical pose positions, register in here.&lt;br /&gt;
&lt;br /&gt;
integer MAX_SITTING=1;&lt;br /&gt;
&lt;br /&gt;
string currentAnim;&lt;br /&gt;
integer currentAnimSeats;&lt;br /&gt;
&lt;br /&gt;
list menuMeta;&lt;br /&gt;
&lt;br /&gt;
integer mode_ballusers;&lt;br /&gt;
&lt;br /&gt;
key grabberID;&lt;br /&gt;
&lt;br /&gt;
list potentionalVictims;&lt;br /&gt;
list victimsWithRelay;&lt;br /&gt;
&lt;br /&gt;
list grabbingVictims; //commanded to, but not yet suited&lt;br /&gt;
list grabbedVictims; //victims tagged as victim, sitted&lt;br /&gt;
&lt;br /&gt;
integer CAPTURE_RANGE = 35;&lt;br /&gt;
integer RELAY_CHANNEL = -1812221819;&lt;br /&gt;
integer relay_handle;&lt;br /&gt;
&lt;br /&gt;
integer timer_reason_versioncheck;&lt;br /&gt;
integer rlv_victim_dialog_handle;&lt;br /&gt;
integer rlv_victim_dialog_channel;&lt;br /&gt;
&lt;br /&gt;
integer timer_versioncheck=50;&lt;br /&gt;
integer timer_closechannel=51;&lt;br /&gt;
integer timer_closechannel2=53;&lt;br /&gt;
integer timer_defaultpose=52;&lt;br /&gt;
integer timer_cleargrabbing=55;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
assignScript (key id) {&lt;br /&gt;
    integer i=llListFindList (agentScripts, [id]);&lt;br /&gt;
    if (i&amp;gt;=0) //agent already got assignment&lt;br /&gt;
        return;    &lt;br /&gt;
    i=llListFindList (agentScriptCache, [id]);&lt;br /&gt;
    string candidate;&lt;br /&gt;
    if (i&amp;gt;=0) {&lt;br /&gt;
        candidate=llList2String(agentScriptCache, i+1);&lt;br /&gt;
        if (-1!=llListFindList(agentScripts, [candidate]))&lt;br /&gt;
            candidate=&amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    if (candidate);else {&lt;br /&gt;
        //try to find a new one&lt;br /&gt;
        for (i=0; i&amp;lt;llGetListLength(sitScripts); i++) {&lt;br /&gt;
            string ss=llList2String(sitScripts, i);&lt;br /&gt;
            if (-1==llListFindList(agentScripts, [ss])) {//found free one&lt;br /&gt;
                candidate=ss;   &lt;br /&gt;
                jump break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        @break;        &lt;br /&gt;
    }&lt;br /&gt;
    if (candidate) {&lt;br /&gt;
        agentScripts+=[id, candidate];&lt;br /&gt;
        i=llListFindList (agentScriptCache, [candidate]);&lt;br /&gt;
        if (-1&amp;lt;i) &lt;br /&gt;
            agentScriptCache=llDeleteSubList(agentScriptCache, i-1, i);    &lt;br /&gt;
        agentScriptCache+=[id, candidate];&lt;br /&gt;
        //llOwnerSay ((string)id+&amp;quot; attached to &amp;quot;+candidate);&lt;br /&gt;
        llMessageLinked(LINK_THIS, MSG_ATTACH_AGENT, candidate, id);&lt;br /&gt;
    } else {&lt;br /&gt;
        llRegionSayTo (id, 0, &amp;quot;Sorry, but there is no available script to animate your avatar.&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer assignPoseIdx (key id) {&lt;br /&gt;
    //start counting at 1.. just because we can.&lt;br /&gt;
    integer i=llListFindList (agentPoseIdx, [id]);&lt;br /&gt;
    if (-1&amp;lt;i)&lt;br /&gt;
        return llList2Integer(agentPoseIdx, i+1); //agent already got a pose assigned&lt;br /&gt;
    for (i=1; i&amp;lt;100; i++) {&lt;br /&gt;
        if (-1==llListFindList(agentPoseIdx, [i])) //found empty one&lt;br /&gt;
        {&lt;br /&gt;
            agentPoseIdx+=[id, i];   &lt;br /&gt;
            //llInstantMessage (id, &amp;quot;You are assigned to pose index &amp;quot;+(string)i);&lt;br /&gt;
            return i;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
dropAgent (key id) {&lt;br /&gt;
    //clean up stuff agent had&lt;br /&gt;
       &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
stopAnims(key id) {&lt;br /&gt;
    llMessageLinked (LINK_THIS, MSG_AGENT_STOP_ANIM, &amp;quot;&amp;quot;, id);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
applyAnims() {&lt;br /&gt;
    //apply animation (and position?) for all agents involved&lt;br /&gt;
    &lt;br /&gt;
    //send list of keys with indexes to position. it should know which anim is current.&lt;br /&gt;
    llMessageLinked (LINK_THIS, MSG_RUN_ANIMS, llList2CSV(agentPoseIdx), &amp;quot;&amp;quot;);&lt;br /&gt;
    //llOwnerSay (&amp;quot;anims/poses &amp;quot;+llList2CSV(agentPoseIdx));&lt;br /&gt;
       &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
cleanUp(key id) {&lt;br /&gt;
    stopAnims(id);&lt;br /&gt;
    integer i=llListFindList (agentScripts, [id]);&lt;br /&gt;
    if (-1&amp;lt;i)&lt;br /&gt;
        agentScripts = llDeleteSubList (agentScripts, i, i+1);&lt;br /&gt;
    i=llListFindList (agentPoseIdx, [id]);&lt;br /&gt;
    if (-1&amp;lt;i)&lt;br /&gt;
        agentPoseIdx = llDeleteSubList (agentPoseIdx, i, i+1);&lt;br /&gt;
&lt;br /&gt;
    i=llListFindList (grabbedVictims, [id]);&lt;br /&gt;
    if (-1&amp;lt;i)&lt;br /&gt;
        grabbedVictims = llDeleteSubList (grabbedVictims, i, i);&lt;br /&gt;
           &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setSitTarget() {&lt;br /&gt;
  //needs pose info.. so we calculate the first available index, and match info with current pose.. it&#039;s for position script, i think.&lt;br /&gt;
    //linkedmessage (setsittarget, [posename,] index)..    &lt;br /&gt;
    //posename might be cached by positioner and/or set to defaults.&lt;br /&gt;
    integer idx=1;&lt;br /&gt;
    //find first available&lt;br /&gt;
    while (-1&amp;lt;llListFindList(agentPoseIdx, [idx]))&lt;br /&gt;
        idx++;&lt;br /&gt;
    if (idx&amp;gt;MAX_SITTING) {&lt;br /&gt;
        llSitTarget (ZERO_VECTOR, ZERO_ROTATION/llGetRot());   &lt;br /&gt;
    } else {&lt;br /&gt;
        llSitTarget (&amp;lt;0,0,0.01&amp;gt;, ZERO_ROTATION/llGetRot()); //backup option.&lt;br /&gt;
        llMessageLinked(LINK_THIS, MSG_SET_SITTARGET, (string)idx, &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer maySit(key id) {&lt;br /&gt;
    if (!mode_ballusers) //everyone&lt;br /&gt;
        return TRUE;&lt;br /&gt;
    if (id==llGetOwner()) //always&lt;br /&gt;
        return TRUE;&lt;br /&gt;
    if (mode_ballusers==1) //group&lt;br /&gt;
        return llSameGroup(id);&lt;br /&gt;
    return FALSE; //nope&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
broadcastVictims() {&lt;br /&gt;
    llMessageLinked (LINK_THIS, MSG_RLV_VICTIM_LIST, llList2CSV(grabbedVictims), &amp;quot;&amp;quot;);   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
requestMenu(key id) {&lt;br /&gt;
    llMessageLinked (LINK_THIS, MSG_DO_MENU_CURRENTMENU, &amp;quot;&amp;quot;, id);      &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
inventarise() {&lt;br /&gt;
    //someone sitted or unsitted. do the bookkeeping&lt;br /&gt;
    list agents;&lt;br /&gt;
    integer i;&lt;br /&gt;
    &lt;br /&gt;
    //get sitted avatars&lt;br /&gt;
    for (i=0; i&amp;lt;=llGetNumberOfPrims(); i++) {&lt;br /&gt;
        key id=llGetLinkKey(i);&lt;br /&gt;
        if (llGetAgentSize(id)) {&lt;br /&gt;
            //this is an agent..&lt;br /&gt;
            agents+=id;&lt;br /&gt;
            if (-1!=llListFindList(grabbingVictims, [id])) {&lt;br /&gt;
                //grabbingVictims=[]; //should really do this somewhere else&lt;br /&gt;
                if (-1==llListFindList(grabbedVictims, [id])) {&lt;br /&gt;
                    rlv_lock(id);&lt;br /&gt;
                    grabbedVictims+=id;&lt;br /&gt;
                    broadcastVictims();&lt;br /&gt;
                }&lt;br /&gt;
            }   &lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //now cross reference against existing agents&lt;br /&gt;
    //first see, who&#039;s all gone&lt;br /&gt;
    for (i=0;i&amp;lt;llGetListLength(sittedAgents); i++) {&lt;br /&gt;
        key id=llList2Key(sittedAgents, i);&lt;br /&gt;
        if (-1==llListFindList(agents, [id])) {&lt;br /&gt;
            //agent unsitted, remove him&lt;br /&gt;
            msgUnsit(id, llList2Integer(agentPoseIdx, llListFindList(agentPoseIdx, [id])+1));&lt;br /&gt;
            if (-1!=llListFindList(grabbedVictims, [id])) {&lt;br /&gt;
                //rlv catch, unlock it&lt;br /&gt;
                rlv_release(id);   &lt;br /&gt;
            }&lt;br /&gt;
            cleanUp(id);                           &lt;br /&gt;
            broadcastVictims();            &lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //now, lets see who&#039;s all added&lt;br /&gt;
    for (i=0;i&amp;lt;llGetListLength(agents); i++) {&lt;br /&gt;
        key id=llList2Key(agents, i);&lt;br /&gt;
        if (-1==llListFindList(sittedAgents, [id])) {&lt;br /&gt;
            //freshy added, assign it a script, if possible, and a logical offset&lt;br /&gt;
            if (maySit(id)) {&lt;br /&gt;
                assignScript(id);&lt;br /&gt;
                msgSit(id, assignPoseIdx(id));&lt;br /&gt;
            } else {&lt;br /&gt;
                llUnSit(id);&lt;br /&gt;
                llWhisper (0, &amp;quot;Sorry &amp;quot;+llKey2Name(id)+&amp;quot; but you cannot use this object.&amp;quot;);&lt;br /&gt;
            }&lt;br /&gt;
            //play anim &lt;br /&gt;
            &lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//    if (sittedAgents != agents)&lt;br /&gt;
//        setSitTarget();    &lt;br /&gt;
    sittedAgents = agents;&lt;br /&gt;
    setSitTarget();&lt;br /&gt;
    applyAnims();&lt;br /&gt;
    &lt;br /&gt;
    // default pose switching on idle&lt;br /&gt;
    if (agents==[])&lt;br /&gt;
        scheduleEvent (timer_defaultpose, 120, &amp;quot;&amp;quot;);&lt;br /&gt;
    else&lt;br /&gt;
        cancelEvent (timer_defaultpose);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
makeSwapMenu(key id, integer channel) {&lt;br /&gt;
    //offer nice swap menu&lt;br /&gt;
    //list sitted avatars&lt;br /&gt;
    string text=&amp;quot;&amp;quot;;&lt;br /&gt;
    integer i;&lt;br /&gt;
    integer m=10;&lt;br /&gt;
    list buttons=[&amp;quot;&amp;lt;BACK&amp;quot;];&lt;br /&gt;
    if (MAX_SITTING&amp;lt;m)&lt;br /&gt;
        m=MAX_SITTING;&lt;br /&gt;
    for (i=1; i&amp;lt;=m; i++) {&lt;br /&gt;
        integer j=llListFindList(agentPoseIdx, [i]);&lt;br /&gt;
        string agent = &amp;quot;&amp;lt;Nobody&amp;gt;&amp;quot;;&lt;br /&gt;
        key aid;&lt;br /&gt;
        if (-1&amp;lt;j) {&lt;br /&gt;
            aid=llList2Key(agentPoseIdx, j-1);&lt;br /&gt;
            agent=llKey2Name(aid);&lt;br /&gt;
        }&lt;br /&gt;
        text+=(string)i + &amp;quot;. &amp;quot; + llList2String(menuMeta, i) + &amp;quot; &amp;quot;+agent+&amp;quot;\n&amp;quot;;&lt;br /&gt;
                   &lt;br /&gt;
        if (aid!=id)&lt;br /&gt;
            buttons+=[&amp;quot;SWAP::&amp;quot;+(string)i];&lt;br /&gt;
    }&lt;br /&gt;
    llDialog (id, text, buttons, channel);       &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//consideration: send out sit/unsit events or not.. i think, might as well not. in order not to confuse rlv.&lt;br /&gt;
swapAgent (key id, integer newpos) {&lt;br /&gt;
    //llSay (0, &amp;quot;Swapping &amp;quot;+llKey2Name(id)+&amp;quot; to position #&amp;quot;+(string)newpos);&lt;br /&gt;
    integer o=llListFindList(agentPoseIdx, [id]);&lt;br /&gt;
    if (o&amp;lt;0) {&lt;br /&gt;
        //llOwnerSay (&amp;quot;swap key not found &amp;quot;+(string)id);&lt;br /&gt;
        //agent not found. see if we have a rlv target&lt;br /&gt;
        if (llGetListLength(grabbedVictims)) {&lt;br /&gt;
            //just default to first best sitted. Stuff gets complex with multiple RLV but who cares that.&lt;br /&gt;
            id=llList2Key(grabbedVictims,0);&lt;br /&gt;
            o=llListFindList(agentPoseIdx, [id]);&lt;br /&gt;
            if (o&amp;lt;0) //OUCH, should nevah happen&lt;br /&gt;
                return;            &lt;br /&gt;
        }        &lt;br /&gt;
        else return;&lt;br /&gt;
    }&lt;br /&gt;
    integer oldidx=llList2Integer(agentPoseIdx, o+1);&lt;br /&gt;
    if (oldidx==newpos) {&lt;br /&gt;
        llRegionSayTo (id, 0, &amp;quot;You choosen the same position&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    agentPoseIdx=llDeleteSubList(agentPoseIdx, o, o+1);&lt;br /&gt;
    integer topos=llListFindList(agentPoseIdx, [newpos]);&lt;br /&gt;
    if (-1&amp;lt;topos) {&lt;br /&gt;
        agentPoseIdx=llDeleteSubList(agentPoseIdx, topos-1, topos) + [llList2Key(agentPoseIdx, topos-1),oldidx];        &lt;br /&gt;
    }&lt;br /&gt;
    agentPoseIdx += [id, newpos];&lt;br /&gt;
    applyAnims();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsitAll() {&lt;br /&gt;
    integer i;&lt;br /&gt;
    for (i=0; i&amp;lt;=llGetNumberOfPrims(); i++) {&lt;br /&gt;
        key id=llGetLinkKey(i);&lt;br /&gt;
        if (llGetAgentSize(id))&lt;br /&gt;
            llUnSit(id);    &lt;br /&gt;
    }   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
msgSit(key id, integer poseidx) {&lt;br /&gt;
    //we start count at 1, mlp at zero. fix right here&lt;br /&gt;
    llMessageLinked(LINK_THIS, MSG_MLP_SITTED, (string)(poseidx-1), id);   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
msgUnsit(key id, integer poseidx) {&lt;br /&gt;
    //we start count at 1, mlp at zero. fix right here&lt;br /&gt;
    llMessageLinked(LINK_THIS, MSG_MLP_UNSITTED, (string)(poseidx-1), id);   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
log(string t){&lt;br /&gt;
    //llOwnerSay(t);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
RLVGrabMenu(key id) {&lt;br /&gt;
    grabberID = id;&lt;br /&gt;
    llSensor(&amp;quot;&amp;quot;, NULL_KEY, AGENT, CAPTURE_RANGE, TWO_PI);    &lt;br /&gt;
//    llInstantMessage (id, &amp;quot;Scanning ... menu in 5.. 4.. 3..&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
RLVReleaseAll() {&lt;br /&gt;
    integer i;&lt;br /&gt;
    for (i=0; i&amp;lt;llGetListLength(grabbedVictims); i++) {&lt;br /&gt;
        key id=llList2Key(grabbedVictims,i);&lt;br /&gt;
        rlv_release (id);&lt;br /&gt;
        llWhisper (0,&amp;quot;releasing &amp;quot;+llKey2Name(id));&lt;br /&gt;
        //unsit?&lt;br /&gt;
        llUnSit(id);&lt;br /&gt;
    }&lt;br /&gt;
    grabbedVictims=[];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
rlv_checkversion (key id) {&lt;br /&gt;
    rlv_relay(id, &amp;quot;!version=&amp;quot; + (string)1);    //version_handle&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
rlv_capture(key avatar)&lt;br /&gt;
{&lt;br /&gt;
    rlv_relay(avatar, &amp;quot;@sit:&amp;quot; + (string)llGetKey() + &amp;quot;=force&amp;quot;);&lt;br /&gt;
    //llSay (menu_ban_channel, &amp;quot;- &amp;quot;+(string)avatar);    &lt;br /&gt;
    llWhisper (0, llKey2Name(grabberID)+&amp;quot; captures &amp;quot;+llKey2Name(avatar));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
rlv_lock(key avatar)&lt;br /&gt;
{&lt;br /&gt;
    rlv_relay(avatar, &amp;quot;@unsit=n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
rlv_release(key avatar)&lt;br /&gt;
{&lt;br /&gt;
    rlv_relay(avatar, &amp;quot;@unsit=y&amp;quot;);&lt;br /&gt;
    rlv_relay(avatar, &amp;quot;!release&amp;quot;);&lt;br /&gt;
    //llSay (menu_ban_channel, &amp;quot;- &amp;quot;+(string)avatar);    &lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// write a message to the RLV Relay&lt;br /&gt;
rlv_relay(key avatar, string message)&lt;br /&gt;
{&lt;br /&gt;
    if (avatar != NULL_KEY)&lt;br /&gt;
    {&lt;br /&gt;
        llSay(RELAY_CHANNEL, llEscapeURL(llGetObjectName()) + &amp;quot;,&amp;quot; + (string) avatar + &amp;quot;,&amp;quot; + message);&lt;br /&gt;
        log(&amp;quot;RLV: &amp;quot; + llGetObjectName() + &amp;quot;,&amp;quot; + (string) avatar + &amp;quot;,&amp;quot; + message);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//scheduler&lt;br /&gt;
&lt;br /&gt;
list events = [];&lt;br /&gt;
integer nextEvent = 0;&lt;br /&gt;
&lt;br /&gt;
scheduleEvent(integer id, integer time, string data) {&lt;br /&gt;
    //adjust timestamp&lt;br /&gt;
    time+=llGetUnixTime();&lt;br /&gt;
    &lt;br /&gt;
    //cancel any previous requests, this case we only want one per type, really&lt;br /&gt;
    cancelEvent(id);    &lt;br /&gt;
    &lt;br /&gt;
    events = llListSort(events + [time, id, data], 3, TRUE);&lt;br /&gt;
    setTimer(FALSE);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
cancelEvent(integer id) {&lt;br /&gt;
    //reasonable failsafe as long as you don&#039;t use id&#039;s that could be current timestamp.    &lt;br /&gt;
    integer i=llListFindList(events, [id]);&lt;br /&gt;
    if ((-1&amp;lt;i) &amp;amp;&amp;amp; ((i % 3) == 1)) {&lt;br /&gt;
        //it was an id&lt;br /&gt;
        events=llDeleteSubList(events, i-1, i+1);&lt;br /&gt;
        &lt;br /&gt;
        //recurse when found, delete all with said id... ?&lt;br /&gt;
        cancelEvent(id);&lt;br /&gt;
        &lt;br /&gt;
        setTimer(FALSE);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer setTimer(integer executing) {&lt;br /&gt;
    if ((events != []) &amp;gt; 0) { // Are there any list items?&lt;br /&gt;
        integer id = llList2Integer(events, 1);&lt;br /&gt;
 &lt;br /&gt;
        integer time = llList2Integer(events, 0);&lt;br /&gt;
        nextEvent = id;&lt;br /&gt;
 &lt;br /&gt;
        float t = (float)(time - llGetUnixTime());&lt;br /&gt;
        if (t &amp;lt;= 0.0) {&lt;br /&gt;
            if (executing) return TRUE;&lt;br /&gt;
            else t = 0.01;&lt;br /&gt;
        }&lt;br /&gt;
        llSetTimerEvent(t);&lt;br /&gt;
    } else {&lt;br /&gt;
        llSetTimerEvent(0.0);&lt;br /&gt;
        nextEvent = -1;&lt;br /&gt;
    }&lt;br /&gt;
    return FALSE;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
handleEvent(integer id, string data) {&lt;br /&gt;
&lt;br /&gt;
    if (id==timer_versioncheck) {&lt;br /&gt;
            //time to display our dialog&lt;br /&gt;
            if ([]==victimsWithRelay) {&lt;br /&gt;
                llRegionSayTo (grabberID, 0, &amp;quot;No eligible victims found (they must wear a relay).&amp;quot;);&lt;br /&gt;
                requestMenu(grabberID);&lt;br /&gt;
            } else {&lt;br /&gt;
                list nn;&lt;br /&gt;
                integer i;&lt;br /&gt;
                for (i=0; (i&amp;lt;llGetListLength(victimsWithRelay)) &amp;amp;&amp;amp; (i&amp;lt;23); i+=2) {&lt;br /&gt;
                    string s=llKey2Name(llList2Key(victimsWithRelay, i));&lt;br /&gt;
                    if (s)&lt;br /&gt;
                        nn+=llGetSubString(s,0,23);                     &lt;br /&gt;
                }&lt;br /&gt;
                &lt;br /&gt;
                llListenControl(rlv_victim_dialog_handle, TRUE);          &lt;br /&gt;
                scheduleEvent (timer_closechannel, 90, (string)rlv_victim_dialog_handle);&lt;br /&gt;
                llDialog (grabberID, &amp;quot;Choose a victim&amp;quot;, nn, rlv_victim_dialog_channel);&lt;br /&gt;
                //scheduleEvent (timer_versioncheck, 5, &amp;quot;&amp;quot;);                 &lt;br /&gt;
            }  &lt;br /&gt;
&lt;br /&gt;
            //set timer to new timeout&lt;br /&gt;
            &lt;br /&gt;
            //llSetTimerEvent(TIMER_TIMEOUT);&lt;br /&gt;
            //llListenControl (version_handle, FALSE);            &lt;br /&gt;
            //return;   &lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    if ((id==timer_closechannel) || (id==timer_closechannel2)) {&lt;br /&gt;
        llListenControl ((integer)data, FALSE);            &lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    if (id==timer_defaultpose) {&lt;br /&gt;
        llMessageLinked(LINK_THIS, MSG_DO_DEFAULT_POSE, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);        &lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    if (id==timer_cleargrabbing) {&lt;br /&gt;
        grabbingVictims=[];   &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
upgrade() {string self = llGetScriptName(); string basename = self; if (llSubStringIndex(self, &amp;quot; &amp;quot;) &amp;gt;= 0) {integer start = 2; string tail = llGetSubString(self, llStringLength(self) - start, -1); while (llGetSubString(tail, 0, 0) != &amp;quot; &amp;quot;) {start++; tail = llGetSubString(self, llStringLength(self) - start, -1);} if ((integer)tail &amp;gt; 0) {basename = llGetSubString(self, 0, -llStringLength(tail) - 1);}} integer n = llGetInventoryNumber(INVENTORY_SCRIPT); while (n-- &amp;gt; 0) {string item = llGetInventoryName(INVENTORY_SCRIPT, n); if (item != self &amp;amp;&amp;amp; 0 == llSubStringIndex(item, basename)) {llRemoveInventory(item);}}}&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        upgrade();&lt;br /&gt;
        llOwnerSay (&amp;quot;sitmanager memory free : &amp;quot;+(string)llGetFreeMemory());&lt;br /&gt;
        state active;  &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state active {   &lt;br /&gt;
    state_entry() {&lt;br /&gt;
        setSitTarget();&lt;br /&gt;
        llMessageLinked (LINK_THIS, MSG_QUERY_SITSCRIPT, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
        &lt;br /&gt;
        rlv_victim_dialog_channel = 124904342+llFloor(llFrand(42902543));&lt;br /&gt;
        rlv_victim_dialog_handle = llListen(rlv_victim_dialog_channel, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
        llListenControl (rlv_victim_dialog_handle, FALSE); &lt;br /&gt;
        relay_handle=llListen(RELAY_CHANNEL, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
        llListenControl(relay_handle, FALSE);   &lt;br /&gt;
    } &lt;br /&gt;
    link_message(integer sn, integer n, string m, key id) {&lt;br /&gt;
        &lt;br /&gt;
        if (n==MSG_RESET)&lt;br /&gt;
            llResetScript();&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_ENABLE_SITTING) {&lt;br /&gt;
            MAX_SITTING=llGetListLength(sitScripts);&lt;br /&gt;
            setSitTarget();&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_AGENT_UNSIT) {&lt;br /&gt;
            //unsit agent                &lt;br /&gt;
            llUnSit(id);&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_ALL_UNSIT) {&lt;br /&gt;
            //just kick everyone&lt;br /&gt;
            unsitAll();    &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_DISABLE_SITTING) {&lt;br /&gt;
            //state inactive;&lt;br /&gt;
            MAX_SITTING=0;&lt;br /&gt;
            setSitTarget();&lt;br /&gt;
        }        &lt;br /&gt;
        &lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_REGISTER_SITSCRIPT) {&lt;br /&gt;
            if (m)&lt;br /&gt;
            if (INVENTORY_SCRIPT==llGetInventoryType(m))&lt;br /&gt;
            if (-1==llListFindList(sitScripts, [m])) {&lt;br /&gt;
                sitScripts+=m;    &lt;br /&gt;
                MAX_SITTING=llGetListLength(sitScripts);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_PLAY_ANIM) {&lt;br /&gt;
            currentAnim=m;&lt;br /&gt;
            applyAnims();   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_MENU_SWAP) {&lt;br /&gt;
            makeSwapMenu (id, (integer)m);   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_DO_SWAP) {&lt;br /&gt;
            swapAgent(id, (integer)m);   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_MENU_META) {&lt;br /&gt;
            menuMeta=llParseString2List(m, [&amp;quot;|&amp;quot;, &amp;quot; &amp;quot;], []);   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_DO_STOP) {&lt;br /&gt;
            llUnSit(id); //let changed event handle the rest   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_MODE_BALLUSERS) {&lt;br /&gt;
            mode_ballusers=(integer)m;   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_RLV_GRAB) {&lt;br /&gt;
            RLVGrabMenu(id);       &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_RLV_RELEASE) {&lt;br /&gt;
            RLVReleaseAll();&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    changed (integer c) {&lt;br /&gt;
        if (c &amp;amp; CHANGED_LINK) {&lt;br /&gt;
            //don&#039;t even bother about getting sitted or not or leaving..&lt;br /&gt;
            //just fetch all current avatars and match them against our list of known avis&lt;br /&gt;
            inventarise();   &lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    timer() {&lt;br /&gt;
        // Clear timer or it might fire again before we&#039;re done&lt;br /&gt;
        llSetTimerEvent(0.0);&lt;br /&gt;
 &lt;br /&gt;
        do {&lt;br /&gt;
            // Fire the event&lt;br /&gt;
            handleEvent(nextEvent, llList2String(events, 2));&lt;br /&gt;
 &lt;br /&gt;
            // Get rid of the first item as we&#039;ve executed it&lt;br /&gt;
            integer l = events != [];&lt;br /&gt;
            if (l &amp;gt; 0) {&lt;br /&gt;
                if (l &amp;gt; 3)&lt;br /&gt;
                    events = llList2List((events = []) + events, 3, -1);&lt;br /&gt;
                else events = [];&lt;br /&gt;
            }&lt;br /&gt;
 &lt;br /&gt;
            // Prepare the timer for the next event&lt;br /&gt;
        } while (setTimer(TRUE));&lt;br /&gt;
    }    &lt;br /&gt;
    &lt;br /&gt;
    /*&lt;br /&gt;
    timer() {&lt;br /&gt;
        /* default pose.. do somewhere else please&lt;br /&gt;
        llSetTimerEvent(0.);&lt;br /&gt;
        llMessageLinked(LINK_THIS, MSG_DO_DEFAULT_POSE, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);   &lt;br /&gt;
        */&lt;br /&gt;
        /*&lt;br /&gt;
    }&lt;br /&gt;
    */&lt;br /&gt;
    &lt;br /&gt;
    no_sensor()&lt;br /&gt;
    {        &lt;br /&gt;
        llRegionSayTo (grabberID, 0, &amp;quot;No nearby potentional victims found&amp;quot;);&lt;br /&gt;
        requestMenu(grabberID);&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    // some av in sensor range&lt;br /&gt;
    sensor(integer total_number)&lt;br /&gt;
    {&lt;br /&gt;
        //llListenControl (rlv_victim_dialog_handle, TRUE);&lt;br /&gt;
        //scheduleEvent (timer_closechannel, 120, (string)rlv_victim_dialog_handle);&lt;br /&gt;
        llListenControl (relay_handle, TRUE);&lt;br /&gt;
        scheduleEvent (timer_closechannel2, 7, (string)relay_handle);&lt;br /&gt;
        &lt;br /&gt;
        &lt;br /&gt;
        potentionalVictims=[];&lt;br /&gt;
        victimsWithRelay=[];&lt;br /&gt;
        integer i;&lt;br /&gt;
        for(i=0; i &amp;lt; total_number; i++)&lt;br /&gt;
        {&lt;br /&gt;
            key id = llDetectedKey(i);&lt;br /&gt;
            string name = llKey2Name(id);&lt;br /&gt;
            if (llStringLength(name) &amp;gt; 24)&lt;br /&gt;
            {&lt;br /&gt;
                name = llGetSubString(name, 0, 23);&lt;br /&gt;
            }&lt;br /&gt;
            potentionalVictims+=[id, name];&lt;br /&gt;
            rlv_checkversion(id);            &lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        // show dialog if list contains names&lt;br /&gt;
        /*&lt;br /&gt;
        if (llGetListLength(sensor_names) &amp;gt; 0)&lt;br /&gt;
        {&lt;br /&gt;
            llListenControl(dialog_handle, TRUE);&lt;br /&gt;
            llSetTimerEvent(TIMER_TIMEOUT);&lt;br /&gt;
            llDialog(avatar_menu, MSG_CHOOSE_AV, sensor_names, dialog_channel);&lt;br /&gt;
        }&lt;br /&gt;
        */&lt;br /&gt;
        scheduleEvent (timer_versioncheck, 5, (string)grabberID);&lt;br /&gt;
        llRegionSayTo (grabberID, 0, &amp;quot;Verifying &amp;quot;+(string)total_number+&amp;quot; potentional victims. Menu in 5.. 4.. 3..&amp;quot;);          }    &lt;br /&gt;
    &lt;br /&gt;
    listen (integer ch, string n, key id, string m) {&lt;br /&gt;
        if (ch==RELAY_CHANNEL) {&lt;br /&gt;
            if (-1!=llSubStringIndex(m, &amp;quot;version=&amp;quot;)) {//bit dirty, we might catch other objects too&lt;br /&gt;
                //victims+=llGetOwnerKey(id);&lt;br /&gt;
                //victim selected, grab it   &lt;br /&gt;
                victimsWithRelay+=[llGetOwnerKey(id),llGetSubString(llKey2Name(llGetOwnerKey(id)),0,23)];                &lt;br /&gt;
            }            &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (ch==rlv_victim_dialog_channel) {&lt;br /&gt;
            //victim selected, grab it&lt;br /&gt;
            integer i=llListFindList (victimsWithRelay, [m]);&lt;br /&gt;
            if (-1&amp;lt;i) {&lt;br /&gt;
                key vid=llList2Key(victimsWithRelay, i-1);&lt;br /&gt;
                rlv_capture (vid);&lt;br /&gt;
                if (-1==llListFindList(grabbingVictims, [vid])) {&lt;br /&gt;
                    grabbingVictims+=vid;&lt;br /&gt;
                }&lt;br /&gt;
                scheduleEvent (timer_cleargrabbing, 120, (string)id);                &lt;br /&gt;
            }&lt;br /&gt;
            requestMenu(grabberID);   &lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
state inactive {&lt;br /&gt;
    state_entry() {&lt;br /&gt;
        llSitTarget(ZERO_VECTOR, ZERO_ROTATION);&lt;br /&gt;
    }   &lt;br /&gt;
    link_message(integer sn, integer n, string m, key id) {&lt;br /&gt;
        if (n==MSG_RESET)&lt;br /&gt;
            llResetScript();&lt;br /&gt;
        else&lt;br /&gt;
        if (n=MSG_ENABLE_SITTING)&lt;br /&gt;
            state active;&lt;br /&gt;
    }    &lt;br /&gt;
}&lt;br /&gt;
*/&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==TMCP - pose==&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
key ourAgent;&lt;br /&gt;
string currentAnim;&lt;br /&gt;
&lt;br /&gt;
integer hasPerms;&lt;br /&gt;
&lt;br /&gt;
integer MSG_AGENT_PLAY_ANIM=395; // to notify the slave script&lt;br /&gt;
integer MSG_AGENT_STOP_ANIM=396;&lt;br /&gt;
integer MSG_ATTACH_AGENT = 398;&lt;br /&gt;
integer MSG_DETACH_AGENT = 399;&lt;br /&gt;
integer MSG_REGISTER_SITSCRIPT =383;&lt;br /&gt;
integer MSG_QUERY_SITSCRIPT = 385;&lt;br /&gt;
integer MSG_SYNC_ANIM=361;&lt;br /&gt;
&lt;br /&gt;
integer MSG_ADJUST_POSROT=520;&lt;br /&gt;
integer MSG_TEMPORARY_POSROT=521;&lt;br /&gt;
&lt;br /&gt;
integer MSG_MODE_ADJUST=368;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
vector o=ZERO_VECTOR;&lt;br /&gt;
vector r=ZERO_VECTOR;&lt;br /&gt;
integer hastimer;&lt;br /&gt;
&lt;br /&gt;
integer is_adjusting;&lt;br /&gt;
integer cursormode;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
stopAnim() {&lt;br /&gt;
    if (hasPerms) if (currentAnim)&lt;br /&gt;
        llStopAnimation(currentAnim);   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
runAnim() {&lt;br /&gt;
    if (hasPerms) if (currentAnim)&lt;br /&gt;
        llStartAnimation(currentAnim);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer checkPerms() {&lt;br /&gt;
    if (llGetPermissionsKey()!=ourAgent) {&lt;br /&gt;
        hasPerms = FALSE;&lt;br /&gt;
        return FALSE;   &lt;br /&gt;
    }&lt;br /&gt;
    hasPerms=(PERMISSION_TAKE_CONTROLS|PERMISSION_TRIGGER_ANIMATION) == ((PERMISSION_TAKE_CONTROLS|PERMISSION_TRIGGER_ANIMATION) &amp;amp; llGetPermissions());&lt;br /&gt;
    return hasPerms;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
queryPerms() {&lt;br /&gt;
    if (!checkPerms()) {&lt;br /&gt;
        //must query them&lt;br /&gt;
        llRequestPermissions(ourAgent, PERMISSION_TAKE_CONTROLS|PERMISSION_TRIGGER_ANIMATION);   &lt;br /&gt;
    } else {&lt;br /&gt;
        stopDefAnims();&lt;br /&gt;
        if (currentAnim)&lt;br /&gt;
            llStartAnimation(currentAnim);&lt;br /&gt;
        getControls();   &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
stopDefAnims() {&lt;br /&gt;
    //easy way would be:&lt;br /&gt;
    //llStopAnimation(&amp;quot;sit&amp;quot;);   &lt;br /&gt;
    //let&#039;s go for the hard way&lt;br /&gt;
    list a=llGetAnimationList(ourAgent);&lt;br /&gt;
    integer i;&lt;br /&gt;
    for (i=0; i&amp;lt;llGetListLength(a); i++)&lt;br /&gt;
        llStopAnimation(llList2Key(a,i));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
register() {&lt;br /&gt;
    llMessageLinked (LINK_THIS, MSG_REGISTER_SITSCRIPT, llGetScriptName(), &amp;quot;&amp;quot;);   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
getControls() {&lt;br /&gt;
    llTakeControls (CONTROL_UP|CONTROL_DOWN|CONTROL_LEFT|CONTROL_RIGHT|CONTROL_FWD|CONTROL_BACK|CONTROL_ROT_LEFT|CONTROL_ROT_RIGHT, TRUE, FALSE);&lt;br /&gt;
    //llInstantMessage (ourAgent, &amp;quot;Adjust your position with PGUP, PGDOWN and cursorkeys. Shift rotates.&amp;quot;);   &lt;br /&gt;
    whispHelp(ourAgent);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
parseControls (integer level, integer edge) {&lt;br /&gt;
&lt;br /&gt;
    integer l = level; //hold down&lt;br /&gt;
    &lt;br /&gt;
    if ((CONTROL_UP|CONTROL_DOWN)==(l &amp;amp; edge &amp;amp; (CONTROL_UP | CONTROL_DOWN))) {&lt;br /&gt;
        cursormode=!cursormode;&lt;br /&gt;
        whispHelp(ourAgent);&lt;br /&gt;
        return;   &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    if (is_adjusting) {&lt;br /&gt;
        integer cm=cursormode;&lt;br /&gt;
        if (l &amp;amp; edge &amp;amp; CONTROL_LEFT) &lt;br /&gt;
            cursormode--;&lt;br /&gt;
        if (l &amp;amp; edge &amp;amp; CONTROL_RIGHT)&lt;br /&gt;
            cursormode++;&lt;br /&gt;
        if (cursormode&amp;lt;1)&lt;br /&gt;
            cursormode=3;&lt;br /&gt;
        if (cursormode&amp;gt;3)&lt;br /&gt;
            cursormode=1;&lt;br /&gt;
        if (cm!=cursormode)&lt;br /&gt;
            whispHelp(ourAgent);        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    if (cursormode==1) {//fine adjust    &lt;br /&gt;
        if (l &amp;amp; CONTROL_FWD) o+=&amp;lt;0,2,0&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; CONTROL_BACK) o+=&amp;lt;0,-2,0&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; CONTROL_ROT_LEFT) o+=&amp;lt;-2,0,0&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; CONTROL_ROT_RIGHT) o+=&amp;lt;2,0,0&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; CONTROL_UP) o+=&amp;lt;0,0,2&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; CONTROL_DOWN) o+=&amp;lt;0,0,-2&amp;gt;;&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    if (cursormode==2) {//90 degrees rotation    &lt;br /&gt;
        if (l &amp;amp; edge &amp;amp; CONTROL_FWD) r+=&amp;lt;0,90,0&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; edge &amp;amp; CONTROL_BACK) r+=&amp;lt;0,-90,0&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; edge &amp;amp; CONTROL_ROT_LEFT) r+=&amp;lt;0,0,-90&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; edge &amp;amp; CONTROL_ROT_RIGHT) r+=&amp;lt;0,0,90&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; edge &amp;amp; CONTROL_UP) r+=&amp;lt;90,0,0&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; edge &amp;amp; CONTROL_DOWN) r+=&amp;lt;-90,-0,0&amp;gt;;&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    if (cursormode==3) {//fine rotation    &lt;br /&gt;
        if (l &amp;amp; CONTROL_FWD) r+=&amp;lt;0,1,0&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; CONTROL_BACK) r+=&amp;lt;0,-1,0&amp;gt;; &lt;br /&gt;
        if (l &amp;amp; CONTROL_ROT_LEFT) r+=&amp;lt;0,0,-1&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; CONTROL_ROT_RIGHT) r+=&amp;lt;0,0,1&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; CONTROL_UP) r+=&amp;lt;1,0,0&amp;gt;;&lt;br /&gt;
        if (l &amp;amp; CONTROL_DOWN) r+=&amp;lt;-1,0,0&amp;gt;;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //if (l &amp;amp; edge &amp;amp; CONTROL_LEFT) r += &amp;lt;0,0,90&amp;gt;;&lt;br /&gt;
    //if (l &amp;amp; edge &amp;amp; CONTROL_RIGHT) r += &amp;lt;0,-90,0&amp;gt;;    &lt;br /&gt;
        &lt;br /&gt;
    if (!hastimer) {&lt;br /&gt;
        llSetTimerEvent (0.25);&lt;br /&gt;
        hastimer=TRUE;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
whispHelp (key id) {&lt;br /&gt;
    if (!is_adjusting) {&lt;br /&gt;
        if (!cursormode) {&lt;br /&gt;
            llRegionSayTo (id, 0, &amp;quot;Press PAGE-UP and PAGE-DOWN simultanious to fine adjust position&amp;quot;);&lt;br /&gt;
        } else {&lt;br /&gt;
            llRegionSayTo (id, 0, &amp;quot;Use the cursor keys and up/down to adjust position. Changes made are temporary.&amp;quot;);&lt;br /&gt;
        }        &lt;br /&gt;
    } else {&lt;br /&gt;
        if (!cursormode)&lt;br /&gt;
            llRegionSayTo (id, 0, &amp;quot;Use PAGE-UP and PAGE-DOWN to start adjusting&amp;quot;);&lt;br /&gt;
        if (1==cursormode)&lt;br /&gt;
            llRegionSayTo (id, 0, &amp;quot;Mode: position (fine adjust). Use cursor keys and up/down to adjust position. Shift-left or shift-right to change mode&amp;quot;);&lt;br /&gt;
        if (2==cursormode)&lt;br /&gt;
            llRegionSayTo (id, 0, &amp;quot;Mode: rotation (90 degrees) . Use cursor keys and up/down to adjust rotation. Shift-left or shift-right to change mode&amp;quot;);&lt;br /&gt;
        if (3==cursormode)&lt;br /&gt;
            llRegionSayTo (id, 0, &amp;quot;Mode: rotation (fine adjust). Use cursor keys and up/down to adjust rotation. Shift-left or shift-right to change mode&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
upgrade() {string self = llGetScriptName(); string basename = self; if (llSubStringIndex(self, &amp;quot; &amp;quot;) &amp;gt;= 0) {integer start = 2; string tail = llGetSubString(self, llStringLength(self) - start, -1); while (llGetSubString(tail, 0, 0) != &amp;quot; &amp;quot;) {start++; tail = llGetSubString(self, llStringLength(self) - start, -1);} if ((integer)tail &amp;gt; 0) {basename = llGetSubString(self, 0, -llStringLength(tail) - 1);}} integer n = llGetInventoryNumber(INVENTORY_SCRIPT); while (n-- &amp;gt; 0) {string item = llGetInventoryName(INVENTORY_SCRIPT, n); if (item != self &amp;amp;&amp;amp; 0 == llSubStringIndex(item, basename)) {llRemoveInventory(item);}}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        //upgrade();&lt;br /&gt;
        register();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    link_message(integer sn, integer n, string m, key id) {&lt;br /&gt;
        if (n==MSG_ATTACH_AGENT) {&lt;br /&gt;
            if (m==llGetScriptName()) {&lt;br /&gt;
                if (ourAgent)&lt;br /&gt;
                    stopAnim();&lt;br /&gt;
                currentAnim=&amp;quot;&amp;quot;;   &lt;br /&gt;
                ourAgent = id;&lt;br /&gt;
                queryPerms();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_DETACH_AGENT) {&lt;br /&gt;
            if (ourAgent==id) {&lt;br /&gt;
                llReleaseControls();&lt;br /&gt;
                stopAnim();&lt;br /&gt;
            }&lt;br /&gt;
            ourAgent=NULL_KEY;&lt;br /&gt;
            currentAnim=&amp;quot;&amp;quot;;   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_AGENT_PLAY_ANIM) {&lt;br /&gt;
            if (ourAgent==id) {&lt;br /&gt;
                stopAnim();&lt;br /&gt;
                currentAnim=m;&lt;br /&gt;
                runAnim();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_AGENT_STOP_ANIM) {&lt;br /&gt;
            if (ourAgent==id) {&lt;br /&gt;
                stopAnim();&lt;br /&gt;
                currentAnim=&amp;quot;&amp;quot;;    &lt;br /&gt;
            }   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_SYNC_ANIM) {&lt;br /&gt;
            if (ourAgent) {&lt;br /&gt;
                stopAnim();&lt;br /&gt;
                runAnim();&lt;br /&gt;
            }   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_QUERY_SITSCRIPT) {&lt;br /&gt;
            register();&lt;br /&gt;
            //llOwnerSay (&amp;quot;Registering&amp;quot;);   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_MODE_ADJUST) {&lt;br /&gt;
            is_adjusting = (integer)m;&lt;br /&gt;
            if (!is_adjusting)&lt;br /&gt;
                cursormode=0;&lt;br /&gt;
            else&lt;br /&gt;
                cursormode=1;&lt;br /&gt;
            if (id==ourAgent)&lt;br /&gt;
                whispHelp(id);   &lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    run_time_permissions(integer p) {&lt;br /&gt;
        if (checkPerms()) {&lt;br /&gt;
            stopDefAnims();&lt;br /&gt;
            if (currentAnim)&lt;br /&gt;
                llStartAnimation(currentAnim);   &lt;br /&gt;
            getControls();&lt;br /&gt;
        } &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    control (key id, integer level, integer edge) {&lt;br /&gt;
        if (id!=ourAgent)&lt;br /&gt;
            return;&lt;br /&gt;
        parseControls (level, edge);   &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    timer () {&lt;br /&gt;
        llSetTimerEvent (0.);&lt;br /&gt;
        hastimer=FALSE;&lt;br /&gt;
        if (ZERO_VECTOR!=(o+r)) {&lt;br /&gt;
            if (is_adjusting)&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_ADJUST_POSROT, (string)(0.005*o)+&amp;quot;&amp;amp;&amp;quot;+(string)r, ourAgent);    &lt;br /&gt;
            else&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_TEMPORARY_POSROT, (string)(0.005*o)+&amp;quot;&amp;amp;&amp;quot;+(string)r, ourAgent);            &lt;br /&gt;
        }&lt;br /&gt;
        o=ZERO_VECTOR;&lt;br /&gt;
        r=ZERO_VECTOR;&lt;br /&gt;
        &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==TMCP - positions==&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
//basically, we need a large datastore for our command set&lt;br /&gt;
list poseNames;&lt;br /&gt;
list poseData;&lt;br /&gt;
&lt;br /&gt;
list positionNames;&lt;br /&gt;
list positionData;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
integer MSG_DATA_MENU=310;&lt;br /&gt;
integer MSG_DATA_TYPE=320;&lt;br /&gt;
integer MSG_DATA_POSE=330;&lt;br /&gt;
integer MSG_DATA_POSITION=331;&lt;br /&gt;
integer MSG_DATA_LM=335;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_POSE=350;&lt;br /&gt;
integer MSG_DO_LM=351;&lt;br /&gt;
integer MSG_DO_SPECIAL=352;&lt;br /&gt;
&lt;br /&gt;
integer MSG_SET_RUNNING=390;&lt;br /&gt;
integer MSG_STORAGE_RESET=391;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DATA_READY=309;&lt;br /&gt;
&lt;br /&gt;
integer MSG_RUN_ANIMS=379;&lt;br /&gt;
&lt;br /&gt;
integer MSG_AGENT_PLAY_ANIM=395;&lt;br /&gt;
&lt;br /&gt;
integer MSG_SET_SITTARGET=375;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DUMP_POSITIONS=389;&lt;br /&gt;
integer MSG_UPDATE_POS=363;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_DEFAULT_POSE = 358;&lt;br /&gt;
integer MSG_SET_DEFAULT_POSE = 359;&lt;br /&gt;
&lt;br /&gt;
integer MSG_MLP_SETTING = 1;&lt;br /&gt;
&lt;br /&gt;
integer MSG_ADJUST_POSROT=520;&lt;br /&gt;
integer MSG_TEMPORARY_POSROT=521;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
string currentPose=&amp;quot;default&amp;quot;;&lt;br /&gt;
list currentAnims;&lt;br /&gt;
list currentPositions;&lt;br /&gt;
&lt;br /&gt;
list agentPoseIdx;&lt;br /&gt;
&lt;br /&gt;
list agentAdjust;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
string defaultPose=&amp;quot;default&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
runAnims() {&lt;br /&gt;
    list data=agentPoseIdx;&lt;br /&gt;
    integer i;&lt;br /&gt;
    list idpos;&lt;br /&gt;
    for (i=0; i&amp;lt;llGetListLength(data); i+=2) {&lt;br /&gt;
        key id=(key)llList2String(data, i);&lt;br /&gt;
        integer idx=-1+(integer)llList2String(data, i+1);&lt;br /&gt;
        if (id) if (idx&amp;gt;=0) {&lt;br /&gt;
            if (idx&amp;gt;=llGetListLength(currentAnims))&lt;br /&gt;
                llWhisper (0, &amp;quot;No animation available for &amp;quot;+llKey2Name(id));&lt;br /&gt;
            else {&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_AGENT_PLAY_ANIM, llList2String(currentAnims, idx), id);&lt;br /&gt;
                //llOwnerSay (&amp;quot;Playing anim &amp;quot;+llList2String(currentAnims, idx)+&amp;quot; on id &amp;quot;+(string)id);&lt;br /&gt;
            }&lt;br /&gt;
                &lt;br /&gt;
            if (idx/2&amp;gt;=llGetListLength(currentPositions))&lt;br /&gt;
                llSay (0, &amp;quot;No position data for &amp;quot;+llKey2Name(id));   &lt;br /&gt;
            else {&lt;br /&gt;
                //set agents position&lt;br /&gt;
                idpos+=[id, (vector)llList2String(currentPositions, idx*2),(vector)llList2String(currentPositions, idx*2+1)];&lt;br /&gt;
            }&lt;br /&gt;
        } else {&lt;br /&gt;
            //llOwnerSay (&amp;quot;Corrupt agent anim position request&amp;quot;);   &lt;br /&gt;
        }&lt;br /&gt;
    }    &lt;br /&gt;
    //apply positions&lt;br /&gt;
    for (i=0; i&amp;lt;=llGetNumberOfPrims(); i++) {&lt;br /&gt;
        integer j=llListFindList(idpos, [llGetLinkKey(i)]);&lt;br /&gt;
        if (-1&amp;lt;j) {&lt;br /&gt;
            vector pos = llList2Vector(idpos, j+1)+(&amp;lt;0,0,0.42+0.01*(integer)llGetObjectDesc()&amp;gt;/llGetRot());&lt;br /&gt;
            vector rot = llList2Vector(idpos, j+2) * DEG_TO_RAD;&lt;br /&gt;
            integer l=llListFindList (agentAdjust, [llGetLinkKey(i)]);&lt;br /&gt;
            if (-1&amp;lt;l) {&lt;br /&gt;
                pos+=llList2Vector (agentAdjust, l+1);&lt;br /&gt;
                rot=llRot2Euler(llEuler2Rot(llList2Vector (agentAdjust, l+2)) * llEuler2Rot(rot));                   &lt;br /&gt;
            }&lt;br /&gt;
            llSetLinkPrimitiveParamsFast(i, [PRIM_POS_LOCAL, pos,PRIM_ROT_LOCAL, llEuler2Rot(rot)]);&lt;br /&gt;
            //llOwnerSay (&amp;quot;Setting position for &amp;quot;+llKey2Name(llGetLinkKey(i))+&amp;quot; position: &amp;quot;+(string)pos+&amp;quot; rotation: &amp;quot;+ (string)rot );&lt;br /&gt;
        }        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setSitTarget(integer poseidx) {&lt;br /&gt;
    poseidx--;&lt;br /&gt;
    vector v=(vector)llList2String(currentPositions, poseidx*2);&lt;br /&gt;
    vector r=(vector)llList2String(currentPositions, poseidx*2+1);&lt;br /&gt;
    llSitTarget (v+(&amp;lt;0,0,0.42+0.01*(integer)llGetObjectDesc()&amp;gt;/llGetRot()) , llEuler2Rot(r*DEG_TO_RAD));&lt;br /&gt;
    //llOwnerSay (&amp;quot;Sit target #&amp;quot;+(string)poseidx+&amp;quot; &amp;quot;+(string)(v+(&amp;lt;0,0,0.42&amp;gt;/llGetRot()))+&amp;quot; &amp;quot;+(string)(r));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string shortString (float n) {&lt;br /&gt;
    string s=(string)n;&lt;br /&gt;
    while (llStringLength(s)&amp;gt;1) {&lt;br /&gt;
        integer hasdot=-1!=llSubStringIndex(s, &amp;quot;.&amp;quot;);&lt;br /&gt;
        string d=llGetSubString(s,-1,-1);&lt;br /&gt;
        if ((hasdot &amp;amp;&amp;amp; (d==&amp;quot;0&amp;quot;)) || (d==&amp;quot;.&amp;quot;))&lt;br /&gt;
            s=llDeleteSubString(s,-1,-1);&lt;br /&gt;
        else&lt;br /&gt;
            jump ok;   &lt;br /&gt;
    }&lt;br /&gt;
    @ok;&lt;br /&gt;
    return s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string shortVec (vector v) {&lt;br /&gt;
    return &amp;quot;&amp;lt;&amp;quot;+shortString(v.x)+&amp;quot;,&amp;quot;+shortString(v.y)+&amp;quot;,&amp;quot;+shortString(v.z)+&amp;quot;&amp;gt;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
dumpPos() {&lt;br /&gt;
    llOwnerSay (&amp;quot;TMCP Position Dump&amp;quot;);&lt;br /&gt;
    integer i;&lt;br /&gt;
    for (i=0; i&amp;lt;llGetListLength(positionNames); i++) {&lt;br /&gt;
        //llOwnerSay (&amp;quot;{&amp;quot;+llList2String(positionNames, i)+&amp;quot;} &amp;quot;+llList2String(positionData, i));    &lt;br /&gt;
        list v=llParseString2List(llList2String(positionData, i), [&amp;quot;&amp;amp;&amp;quot;], []);&lt;br /&gt;
        string s=&amp;quot;{&amp;quot;+llList2String(positionNames, i)+&amp;quot;}&amp;quot;;&lt;br /&gt;
        integer j;&lt;br /&gt;
        for (j=0; j&amp;lt;llGetListLength(v); j++)&lt;br /&gt;
            //notice that function shortvec takes string as param&lt;br /&gt;
            s+=&amp;quot; &amp;quot;+shortVec((vector)llList2String(v, j));        &lt;br /&gt;
        llOwnerSay (s);&lt;br /&gt;
    }   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
doPose (string m) {&lt;br /&gt;
    if (m!=currentPose)&lt;br /&gt;
        agentAdjust=[];&lt;br /&gt;
        &lt;br /&gt;
            currentPose=m;&lt;br /&gt;
            currentAnims=[];&lt;br /&gt;
            currentPositions=[];&lt;br /&gt;
            integer i=llListFindList(positionNames, [m]);&lt;br /&gt;
            integer j=llListFindList(poseNames, [m]);&lt;br /&gt;
            currentAnims=llParseString2List (llList2String(poseData, j), [&amp;quot;|&amp;quot;], []);&lt;br /&gt;
            currentPositions=llParseString2List (llList2String(positionData, i), [&amp;quot;&amp;amp;&amp;quot;], []);&lt;br /&gt;
            &lt;br /&gt;
            //fill missing data with defaults&lt;br /&gt;
            i = llListFindList(positionNames, [&amp;quot;default&amp;quot;]);&lt;br /&gt;
            j = llListFindList(poseNames, [&amp;quot;default&amp;quot;]);&lt;br /&gt;
            list animdef=llParseString2List (llList2String(poseData, j), [&amp;quot;|&amp;quot;], []);&lt;br /&gt;
            list posdef=llParseString2List (llList2String(positionData, i), [&amp;quot;&amp;amp;&amp;quot;], []);&lt;br /&gt;
            currentAnims+=llList2List (animdef, llGetListLength(currentAnims), -1);&lt;br /&gt;
            currentPositions+=llList2List(posdef, llGetListLength(currentPositions), -1);            &lt;br /&gt;
            &lt;br /&gt;
            //this should be obsolete now:&lt;br /&gt;
            if (/*(i&amp;gt;=0) &amp;amp;&amp;amp; */(j&amp;gt;=0)) {&lt;br /&gt;
                //list l=llParseString2List(llList2String(lmAction, i), [&amp;quot;,&amp;quot;],[]);&lt;br /&gt;
                //parse pose data. todo.&lt;br /&gt;
                if (i&amp;lt;0) {&lt;br /&gt;
                    //need to fetch default data... just try it.&lt;br /&gt;
                    i=llListFindList(positionNames, [&amp;quot;default&amp;quot;]);&lt;br /&gt;
                }&lt;br /&gt;
                //llOwnerSay (&amp;quot;Do pose &amp;quot;+m+&amp;quot; anims &amp;quot;+llList2String(poseData,j)+&amp;quot; data &amp;quot;+llList2String(positionData, i));&lt;br /&gt;
            } else {                                &lt;br /&gt;
                //llOwnerSay (&amp;quot;No animations defined for &amp;quot;+m);&lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
            runAnims();  &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setAgentPosRot (key id, string data) {&lt;br /&gt;
    //set temporary agent adjustment.&lt;br /&gt;
    list l=llParseString2List(data, [&amp;quot;&amp;amp;&amp;quot;], []);&lt;br /&gt;
    vector p=(vector)llList2String(l,0);&lt;br /&gt;
    vector r=DEG_TO_RAD * (vector)llList2String(l,1);&lt;br /&gt;
    integer i=llListFindList (agentAdjust, [id]);&lt;br /&gt;
    if (-1&amp;lt;i) {&lt;br /&gt;
        p+=llList2Vector(agentAdjust, i+1);&lt;br /&gt;
        r=llRot2Euler(llEuler2Rot(llList2Vector(agentAdjust, i+2))*llEuler2Rot(r));        &lt;br /&gt;
        agentAdjust = llDeleteSubList(agentAdjust, i, i+2);&lt;br /&gt;
    }&lt;br /&gt;
    if (llVecMag(p)&amp;gt;1)&lt;br /&gt;
        p=llVecNorm(p);&lt;br /&gt;
    agentAdjust+=[id,p,r];       &lt;br /&gt;
    runAnims();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
adjustPosition (string name, integer index, vector p, vector r) {&lt;br /&gt;
                              //positionNames&lt;br /&gt;
    integer i=llListFindList (positionNames, [name]); &lt;br /&gt;
    if (-1&amp;lt;i) {&lt;br /&gt;
        string data=llList2String(positionData, i);&lt;br /&gt;
        list pos=llParseString2List(data, [&amp;quot;&amp;amp;&amp;quot;], []);&lt;br /&gt;
        if (index&amp;gt;0) {&lt;br /&gt;
            //alter only index   &lt;br /&gt;
            integer j=(index-1)*2;&lt;br /&gt;
            if (j&amp;lt;llGetListLength(positionData)) {&lt;br /&gt;
                vector v=(vector)llList2String(pos, j);   &lt;br /&gt;
                v+=p;&lt;br /&gt;
                vector R0=(vector)llList2String(pos, j+1);   &lt;br /&gt;
                rotation R1=llEuler2Rot(DEG_TO_RAD *R0);&lt;br /&gt;
                rotation Rd=llEuler2Rot(DEG_TO_RAD * r);&lt;br /&gt;
                R1 = R1 * Rd;&lt;br /&gt;
                R0=RAD_TO_DEG * llRot2Euler(R1);                &lt;br /&gt;
                pos=llListReplaceList(pos, [shortVec(v),shortVec(R0)], j, j+1);                             &lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
        } else {&lt;br /&gt;
            //alter all&lt;br /&gt;
            integer j;&lt;br /&gt;
            for (j=0; j&amp;lt;llGetListLength(pos); j+=2) {&lt;br /&gt;
                vector v=(vector)llList2String(pos, j);   &lt;br /&gt;
                v+=p;&lt;br /&gt;
                vector R0=(vector)llList2String(pos, j+1);   &lt;br /&gt;
                rotation R1=llEuler2Rot(DEG_TO_RAD *R0);&lt;br /&gt;
                rotation Rd=llEuler2Rot(DEG_TO_RAD * r);&lt;br /&gt;
                R1 = R1 * Rd;&lt;br /&gt;
                R0=RAD_TO_DEG * llRot2Euler(R1);                &lt;br /&gt;
                pos=llListReplaceList(pos, [shortVec(v),shortVec(R0)], j, j+1);                &lt;br /&gt;
            }               &lt;br /&gt;
        }&lt;br /&gt;
        data=llDumpList2String(pos, &amp;quot;&amp;amp;&amp;quot;);&lt;br /&gt;
        //llOwnerSay (&amp;quot;new pos data for &amp;quot;+name+&amp;quot; : &amp;quot;+data);&lt;br /&gt;
        positionData=llListReplaceList (positionData, [data], i, i);&lt;br /&gt;
           &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
adjustAllPositions (vector p, vector r) {&lt;br /&gt;
    //loop all pose, adjust them&lt;br /&gt;
    integer i;&lt;br /&gt;
    for (i=0; i&amp;lt;llGetListLength(positionNames); i++) {&lt;br /&gt;
        adjustPosition (llList2String(positionNames, i),-1, p,r);&lt;br /&gt;
    }   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
parseSetting (string m, key id) {&lt;br /&gt;
    //seperated by =&lt;br /&gt;
    //might contain ROT or POS adjustments&lt;br /&gt;
    list l=llParseString2List(m, [&amp;quot; = &amp;quot;, &amp;quot; =&amp;quot;, &amp;quot;=&amp;quot;, &amp;quot;= &amp;quot;,&amp;quot;=&amp;quot;],[]);&lt;br /&gt;
    string cmd=llList2String(l, 0);&lt;br /&gt;
    string cmd2=llList2String(l,1);&lt;br /&gt;
    if (cmd==&amp;quot;REORIENT&amp;quot;) {&lt;br /&gt;
        vector v=(vector)llList2String(l,2);&lt;br /&gt;
        /*&lt;br /&gt;
        list lv=llParseString2List(llList2String(l,2), [&amp;quot;&amp;lt;&amp;quot;,&amp;quot;,&amp;quot;,&amp;quot;&amp;gt;&amp;quot;], []); //rotations come as vector too&lt;br /&gt;
        llOwnerSay (&amp;quot;P: &amp;quot;+llList2String(l,2)+&amp;quot; : &amp;quot;+llDumpList2String(lv, &amp;quot;*&amp;quot;));&lt;br /&gt;
        v.x=(float)llList2String(lv,0);&lt;br /&gt;
        v.y=(float)llList2String(lv,1);&lt;br /&gt;
        v.z=(float)llList2String(lv,2);&lt;br /&gt;
        */&lt;br /&gt;
        &lt;br /&gt;
        llOwnerSay (&amp;quot;adjust &amp;quot;+cmd2+&amp;quot; &amp;quot;+(string)v);&lt;br /&gt;
        if (cmd2==&amp;quot;OFF&amp;quot;) {&lt;br /&gt;
            adjustAllPositions (0.01*v, ZERO_VECTOR);    &lt;br /&gt;
        } else&lt;br /&gt;
        if (cmd2==&amp;quot;ROT&amp;quot;) {&lt;br /&gt;
            adjustAllPositions (ZERO_VECTOR,v);    &lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        doPose(currentPose);&lt;br /&gt;
        //runAnims();&lt;br /&gt;
    }    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
adjustPosRot (key id, string data) {&lt;br /&gt;
    list l=llParseString2List(data, [&amp;quot;&amp;amp;&amp;quot;], []);&lt;br /&gt;
    integer i=llListFindList (agentPoseIdx, [(string)id]);&lt;br /&gt;
    //llOwnerSay (&amp;quot;posrot &amp;quot;+(string)i+&amp;quot; &amp;quot;+(string)id+&amp;quot; &amp;quot;+data);&lt;br /&gt;
    if ((-1&amp;lt;i)&amp;amp;&amp;amp;(llGetListLength(l)==2)) {&lt;br /&gt;
        integer lidx=llList2Integer (agentPoseIdx, i+1);&lt;br /&gt;
        adjustPosition (currentPose, lidx, (vector)llList2String(l,0), (vector)llList2String(l,1));&lt;br /&gt;
        doPose(currentPose);        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
upgrade() {string self = llGetScriptName(); string basename = self; if (llSubStringIndex(self, &amp;quot; &amp;quot;) &amp;gt;= 0) {integer start = 2; string tail = llGetSubString(self, llStringLength(self) - start, -1); while (llGetSubString(tail, 0, 0) != &amp;quot; &amp;quot;) {start++; tail = llGetSubString(self, llStringLength(self) - start, -1);} if ((integer)tail &amp;gt; 0) {basename = llGetSubString(self, 0, -llStringLength(tail) - 1);}} integer n = llGetInventoryNumber(INVENTORY_SCRIPT); while (n-- &amp;gt; 0) {string item = llGetInventoryName(INVENTORY_SCRIPT, n); if (item != self &amp;amp;&amp;amp; 0 == llSubStringIndex(item, basename)) {llRemoveInventory(item);}}}&lt;br /&gt;
&lt;br /&gt;
default &lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        upgrade();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    link_message (integer sn, integer n, string m, key id) {&lt;br /&gt;
        if (n==MSG_DATA_POSE) {&lt;br /&gt;
            //add posedata    &lt;br /&gt;
            poseNames+=m;&lt;br /&gt;
            poseData+=(string)id;&lt;br /&gt;
        } else&lt;br /&gt;
        if (n==MSG_DATA_POSITION) {&lt;br /&gt;
            positionNames+=m;&lt;br /&gt;
            positionData+=(string)id;            &lt;br /&gt;
        } else&lt;br /&gt;
        if (n==MSG_SET_DEFAULT_POSE) {&lt;br /&gt;
                defaultPose=m;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_SET_RUNNING)&lt;br /&gt;
            state running;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state running {&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llOwnerSay (&amp;quot;Position free memory: &amp;quot;+(string)llGetFreeMemory());&lt;br /&gt;
        doPose(defaultPose);&lt;br /&gt;
    }&lt;br /&gt;
    link_message (integer sn, integer n, string m, key id) {&lt;br /&gt;
        if (n==MSG_DO_POSE) {&lt;br /&gt;
            doPose(m);&lt;br /&gt;
        } else&lt;br /&gt;
        if (n==MSG_STORAGE_RESET)&lt;br /&gt;
            llResetScript();&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_RUN_ANIMS) {&lt;br /&gt;
            agentPoseIdx=llCSV2List(m);&lt;br /&gt;
            runAnims();    &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_SET_SITTARGET) {&lt;br /&gt;
            setSitTarget((integer)m);    &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_DUMP_POSITIONS) {&lt;br /&gt;
            dumpPos();&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_UPDATE_POS) {&lt;br /&gt;
            runAnims();       &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_SET_DEFAULT_POSE)&lt;br /&gt;
            defaultPose=m;&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_DO_DEFAULT_POSE)&lt;br /&gt;
            doPose(defaultPose);&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_MLP_SETTING) {&lt;br /&gt;
            parseSetting (m, id);   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_ADJUST_POSROT) {&lt;br /&gt;
            adjustPosRot(id, m);      &lt;br /&gt;
        }&lt;br /&gt;
        if (n==MSG_TEMPORARY_POSROT) {&lt;br /&gt;
            setAgentPosRot(id, m);      &lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==TMCP - actions==&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
//basically, we need a large datastore for our command set&lt;br /&gt;
list lmNames;&lt;br /&gt;
list lmAction;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DATA_MENU=310;&lt;br /&gt;
integer MSG_DATA_TYPE=320;&lt;br /&gt;
integer MSG_DATA_POSE=330;&lt;br /&gt;
integer MSG_DATA_LM=335;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_POSE=350;&lt;br /&gt;
integer MSG_DO_LM=351;&lt;br /&gt;
integer MSG_DO_SPECIAL=352;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_SOUND=356;&lt;br /&gt;
&lt;br /&gt;
integer MSG_SET_RUNNING=390;&lt;br /&gt;
integer MSG_STORAGE_RESET=391;&lt;br /&gt;
integer MSG_DATA_READY=309;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
upgrade() {string self = llGetScriptName(); string basename = self; if (llSubStringIndex(self, &amp;quot; &amp;quot;) &amp;gt;= 0) {integer start = 2; string tail = llGetSubString(self, llStringLength(self) - start, -1); while (llGetSubString(tail, 0, 0) != &amp;quot; &amp;quot;) {start++; tail = llGetSubString(self, llStringLength(self) - start, -1);} if ((integer)tail &amp;gt; 0) {basename = llGetSubString(self, 0, -llStringLength(tail) - 1);}} integer n = llGetInventoryNumber(INVENTORY_SCRIPT); while (n-- &amp;gt; 0) {string item = llGetInventoryName(INVENTORY_SCRIPT, n); if (item != self &amp;amp;&amp;amp; 0 == llSubStringIndex(item, basename)) {llRemoveInventory(item);}}}&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        upgrade();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    link_message (integer sn, integer n, string m, key id) {&lt;br /&gt;
        if (n==MSG_DATA_LM) {&lt;br /&gt;
            //add action    &lt;br /&gt;
            lmNames+=m;&lt;br /&gt;
            lmAction+=(string)id;&lt;br /&gt;
        } else&lt;br /&gt;
        if (n==MSG_SET_RUNNING)&lt;br /&gt;
            state running;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state running {&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llOwnerSay (&amp;quot;Action manager free memory : &amp;quot;+(string)llGetFreeMemory());    &lt;br /&gt;
    }    &lt;br /&gt;
    link_message (integer sn, integer n, string m, key id) {&lt;br /&gt;
        if (n==MSG_DO_LM) {&lt;br /&gt;
            integer i=llListFindList(lmNames, [m]);&lt;br /&gt;
            if (i&amp;gt;=0) {&lt;br /&gt;
                list l=llParseString2List(llList2String(lmAction, i), [&amp;quot;,&amp;quot;],[]);&lt;br /&gt;
                integer set=(integer)llList2String(l,1);    &lt;br /&gt;
                integer num=(integer)llList2String(l,2);    &lt;br /&gt;
                //string mess=llStringTrim(llList2String(l,3),STRING_TRIM);&lt;br /&gt;
                string mess=llDumpList2String(llList2List(l,3,-1), &amp;quot;,&amp;quot;);&lt;br /&gt;
                integer nomenu=(integer)llList2String(l,0);    &lt;br /&gt;
                //perform requested action&lt;br /&gt;
                llMessageLinked (set, num, mess, id);&lt;br /&gt;
                &lt;br /&gt;
                if (!nomenu) //this will fail when not found, which it shouldnt.&lt;br /&gt;
                    llMessageLinked (LINK_THIS, 370, &amp;quot;&amp;quot;, id);&lt;br /&gt;
            }   &lt;br /&gt;
        } else&lt;br /&gt;
        if (n==MSG_DO_SOUND) {&lt;br /&gt;
            //LM list was abused for sound info&lt;br /&gt;
            integer i=llListFindList(lmNames, [m]);&lt;br /&gt;
            if (i&amp;gt;=0)&lt;br /&gt;
                llTriggerSound(llList2String(lmAction, i), 1.);&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_STORAGE_RESET)&lt;br /&gt;
            llResetScript();&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==TMCP - menurender==&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
string version = &amp;quot;TMCP v0.3x&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//Render menu&lt;br /&gt;
&lt;br /&gt;
list menuNames;&lt;br /&gt;
list menuEntries; //menus that appear in &#039;auto&#039; menu&lt;br /&gt;
list menuDetails;&lt;br /&gt;
&lt;br /&gt;
//some hardcoded stuff that this script adds, not any menu. prefill.&lt;br /&gt;
list itemNames=[&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;,&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;,&amp;quot;&amp;lt;BACK&amp;quot;];&lt;br /&gt;
list itemTypes=[7,7,7];&lt;br /&gt;
&lt;br /&gt;
list menuHistory;&lt;br /&gt;
string currentMenu;&lt;br /&gt;
string currentPose=&amp;quot;default&amp;quot;;&lt;br /&gt;
string defaultPose=&amp;quot;default&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
integer channel=999; &lt;br /&gt;
integer listenhandle;&lt;br /&gt;
&lt;br /&gt;
integer mode_chat=1;&lt;br /&gt;
integer mode_adjust=0;&lt;br /&gt;
integer mode_menu=3; //user&lt;br /&gt;
integer mode_ball=0; //all&lt;br /&gt;
&lt;br /&gt;
integer hibernate;&lt;br /&gt;
&lt;br /&gt;
list rlvVictims;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
integer TYPE_MENU=1;&lt;br /&gt;
integer TYPE_POSE=2;&lt;br /&gt;
integer TYPE_LM_NOMENU=3;&lt;br /&gt;
integer TYPE_LM_MENU=4;&lt;br /&gt;
integer TYPE_IGNORE=5;&lt;br /&gt;
integer TYPE_SPECIAL=6;&lt;br /&gt;
integer TYPE_UNKNOWN=7;&lt;br /&gt;
integer TYPE_SOUND=8;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
integer MSG_DATA_MENU=310;&lt;br /&gt;
integer MSG_DATA_MENU_DETAILS=311;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DATA_TYPE=320;&lt;br /&gt;
integer MSG_DATA_POSE=330;&lt;br /&gt;
integer MSG_DATA_POSITION=331;&lt;br /&gt;
integer MSG_DATA_LM=335;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_POSE=350;&lt;br /&gt;
integer MSG_DO_LM=351;&lt;br /&gt;
integer MSG_DO_SPECIAL=352;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_STOP=353;&lt;br /&gt;
integer MSG_DO_SWAP=354;&lt;br /&gt;
integer MSG_MENU_SWAP=355;&lt;br /&gt;
integer MSG_DO_SOUND=356;&lt;br /&gt;
&lt;br /&gt;
integer MSG_SET_RUNNING=390;&lt;br /&gt;
integer MSG_STORAGE_RESET=391;&lt;br /&gt;
integer MSG_DATA_READY=309;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DATA_START_READ=301;&lt;br /&gt;
&lt;br /&gt;
integer MSG_MENU_META=333;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DUMP_POSITIONS=389;&lt;br /&gt;
integer MSG_MODE_ADJUST=368;&lt;br /&gt;
integer MSG_MODE_CHAT=367;&lt;br /&gt;
integer MSG_MODE_BALLUSERS=366;&lt;br /&gt;
integer MSG_MODE_OFF=365;&lt;br /&gt;
&lt;br /&gt;
integer MSG_UPDATE_POS=363;&lt;br /&gt;
integer MSG_ALL_UNSIT =381;&lt;br /&gt;
&lt;br /&gt;
integer MSG_SET_DEFAULT_POSE = 359;&lt;br /&gt;
integer MSG_DO_DEFAULT_POSE = 358;&lt;br /&gt;
&lt;br /&gt;
integer MSG_RLV_GRAB=308;&lt;br /&gt;
integer MSG_RLV_RELEASE=309;&lt;br /&gt;
integer MSG_RLV_VICTIM_LIST=307;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_MENU_CURRENTMENU = 305;&lt;br /&gt;
&lt;br /&gt;
//incoming&lt;br /&gt;
integer MSG_DO_MENU_COMMAND = -12002;&lt;br /&gt;
&lt;br /&gt;
verbose(string text) {&lt;br /&gt;
    //llOwnerSay (text);&lt;br /&gt;
    if (mode_chat)&lt;br /&gt;
        llSay (0, text);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string onOff(integer value) {&lt;br /&gt;
    if (value) return &amp;quot;On&amp;quot;; else return &amp;quot;Off&amp;quot;;   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string aclMode(integer value) {&lt;br /&gt;
    if (0==value)&lt;br /&gt;
        return &amp;quot;ALL&amp;quot;;&lt;br /&gt;
    else&lt;br /&gt;
    if (1==value)&lt;br /&gt;
        return &amp;quot;GROUP&amp;quot;;&lt;br /&gt;
    else&lt;br /&gt;
    if (2==value)&lt;br /&gt;
        return &amp;quot;OWNER&amp;quot;;&lt;br /&gt;
    else&lt;br /&gt;
    if (3==value)&lt;br /&gt;
        return &amp;quot;USER&amp;quot;;&lt;br /&gt;
    else&lt;br /&gt;
        return &amp;quot;UNKNOWN&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
reset(integer resetSelf) {&lt;br /&gt;
    integer i;&lt;br /&gt;
    for (i=0; i&amp;lt;llGetInventoryNumber(INVENTORY_SCRIPT); i++) {&lt;br /&gt;
        string s=llGetInventoryName(INVENTORY_SCRIPT, i);&lt;br /&gt;
        if (-1&amp;lt;llSubStringIndex(s, &amp;quot;~TMCP &amp;quot;)) {&lt;br /&gt;
            if (s!=llGetScriptName()) {&lt;br /&gt;
                llResetOtherScript(s);    &lt;br /&gt;
            }   &lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    if (resetSelf)&lt;br /&gt;
        llResetScript();        &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setRunning(integer running) {&lt;br /&gt;
    integer i;&lt;br /&gt;
    for (i=0; i&amp;lt;llGetInventoryNumber(INVENTORY_SCRIPT); i++) {&lt;br /&gt;
        string s=llGetInventoryName(INVENTORY_SCRIPT, i);&lt;br /&gt;
        if (-1&amp;lt;llSubStringIndex(s, &amp;quot;~TMCP &amp;quot;)) {&lt;br /&gt;
            if (s!=llGetScriptName()) {&lt;br /&gt;
                llSetScriptState (s, running);&lt;br /&gt;
            }   &lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
integer hasDialogAccess(key id) {&lt;br /&gt;
    &lt;br /&gt;
    //OWNER ALWAYS&lt;br /&gt;
    if (id==llGetOwner())&lt;br /&gt;
        return TRUE;&lt;br /&gt;
        &lt;br /&gt;
    if (-1&amp;lt;llListFindList(rlvVictims, [(string)id]))&lt;br /&gt;
        return FALSE;&lt;br /&gt;
        &lt;br /&gt;
    //ALL&lt;br /&gt;
    if ((!mode_menu)/* || (id==llGetOwner())*/)&lt;br /&gt;
        return TRUE; //little speed optimalization to avoid call to samegroup&lt;br /&gt;
        &lt;br /&gt;
    //USER&lt;br /&gt;
    if (mode_menu==3) {&lt;br /&gt;
        //user must be sitted to access, or no-one sitted at all&lt;br /&gt;
        integer someSit=FALSE;&lt;br /&gt;
        integer i;&lt;br /&gt;
        for (i=0; i&amp;lt;=llGetNumberOfPrims(); i++) {&lt;br /&gt;
            if (llGetLinkKey(i)==id)&lt;br /&gt;
                return TRUE;&lt;br /&gt;
            if (llGetAgentSize(llGetLinkKey(i)))&lt;br /&gt;
                someSit=TRUE;   &lt;br /&gt;
        }&lt;br /&gt;
        return (!someSit);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //GROUP&lt;br /&gt;
    return (mode_menu==1) &amp;amp;&amp;amp; llSameGroup(id);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer hasMenuAccess (key id, string menu) {&lt;br /&gt;
    //supposed to be trimmed already?&lt;br /&gt;
    if (id==llGetOwner())&lt;br /&gt;
        return TRUE;&lt;br /&gt;
    string access=&lt;br /&gt;
        llStringTrim(&lt;br /&gt;
            llList2String(&lt;br /&gt;
                llParseString2List(&lt;br /&gt;
                    llList2String(menuDetails, 1+llListFindList(menuDetails, [menu]) )&lt;br /&gt;
                , [&amp;quot;|&amp;quot;], [])&lt;br /&gt;
            , 0)&lt;br /&gt;
        , STRING_TRIM);&lt;br /&gt;
    if (access==&amp;quot;OWNER&amp;quot;) {&lt;br /&gt;
        return id==llGetOwner();&lt;br /&gt;
    }&lt;br /&gt;
    if (access==&amp;quot;GROUP&amp;quot;) {&lt;br /&gt;
        return (id==llGetOwner()) || llSameGroup(id);        &lt;br /&gt;
    }&lt;br /&gt;
    if (access==&amp;quot;USER&amp;quot;) {&lt;br /&gt;
        integer i;&lt;br /&gt;
        for (i=0; i&amp;lt;=llGetNumberOfPrims(); i++)&lt;br /&gt;
            if (llGetLinkKey(i)==id)&lt;br /&gt;
                return TRUE;&lt;br /&gt;
        return FALSE;   &lt;br /&gt;
    }&lt;br /&gt;
    //defaults to all.. learn to edit notecards if you made an error.&lt;br /&gt;
    //future options might be a name or some. dunnow.&lt;br /&gt;
    return TRUE;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
makeMenu(string name, key id) {&lt;br /&gt;
    &lt;br /&gt;
    if (id); else return; //might be invoked by remote scripts. can&#039;t pop menu&#039;s to none-avi&#039;s.&lt;br /&gt;
    &lt;br /&gt;
    //present user a fine menu   &lt;br /&gt;
    integer idx=0;&lt;br /&gt;
    &lt;br /&gt;
    integer offset;&lt;br /&gt;
    &lt;br /&gt;
    if ((name==&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;) || (name==&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;)) {&lt;br /&gt;
        //offset making&lt;br /&gt;
        //rename to the last found menu&lt;br /&gt;
        /*&lt;br /&gt;
        if (name==&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;)&lt;br /&gt;
            offset+=10;&lt;br /&gt;
        if (name==&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;)&lt;br /&gt;
            offset-=10;                   &lt;br /&gt;
        */&lt;br /&gt;
        menuHistory+=name; //next step will fix this&lt;br /&gt;
        //llOwnerSay (&amp;quot;history: &amp;quot;+(string)menuHistory);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    integer ho=llGetListLength(menuHistory)-1;&lt;br /&gt;
    while ((ho&amp;gt;1) &amp;amp;&amp;amp; (-1&amp;lt;llListFindList([&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;, &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;], [llList2String(menuHistory, ho)])) ) {&lt;br /&gt;
        //adjust offset&lt;br /&gt;
        string s=llList2String(menuHistory, ho);&lt;br /&gt;
        if (s==&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;)&lt;br /&gt;
            offset-=10;&lt;br /&gt;
        if (s==&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;)&lt;br /&gt;
            offset+=10;&lt;br /&gt;
        name=llList2String(menuHistory, ho-1);&lt;br /&gt;
        ho--;            &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
        &lt;br /&gt;
    if (name) {&lt;br /&gt;
        idx=llListFindList(menuNames, [name]);&lt;br /&gt;
        if (idx&amp;lt;0) {            &lt;br /&gt;
            //llOwnerSay (&amp;quot;No menu entry for &amp;quot;+name);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
    } else {&lt;br /&gt;
        //make it main menu&lt;br /&gt;
        name=llList2String(menuNames, 0); //assume at least 1 menu item please.. else its bugged anyways.&lt;br /&gt;
        menuHistory=[];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    currentMenu=name;&lt;br /&gt;
        &lt;br /&gt;
    integer i=llListFindList (menuHistory, [name]);&lt;br /&gt;
    if (i&amp;gt;=0) {&lt;br /&gt;
        //truncate rest from history, maybe we went back.&lt;br /&gt;
        menuHistory = llList2List(menuHistory, 0, i);   &lt;br /&gt;
    } else &lt;br /&gt;
        menuHistory += name;&lt;br /&gt;
&lt;br /&gt;
        &lt;br /&gt;
    list present=llCSV2List(llList2String(menuEntries, idx));&lt;br /&gt;
&lt;br /&gt;
    if (llAbs(offset)&amp;gt;=(llGetListLength(present))) offset=0;&lt;br /&gt;
                                &lt;br /&gt;
    integer o=offset;&lt;br /&gt;
    while (o&amp;gt;0) {&lt;br /&gt;
        menuHistory += &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;;&lt;br /&gt;
        o-=10;   &lt;br /&gt;
        if (o&amp;lt;0)&lt;br /&gt;
            o=0;&lt;br /&gt;
    }&lt;br /&gt;
    while (o&amp;lt;0) {&lt;br /&gt;
        menuHistory += &amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;;&lt;br /&gt;
        o+=10;   &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    string h=&amp;quot;&amp;gt;&amp;gt;&amp;quot;;&lt;br /&gt;
    for (i=0; i&amp;lt;llGetListLength(menuHistory); i++)&lt;br /&gt;
        h+=&amp;quot;&amp;gt; &amp;quot;+llList2String(menuHistory,i)+&amp;quot; &amp;quot;;&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    if (currentPose)&lt;br /&gt;
        h+=&amp;quot;\n\nCurrent pose: &amp;quot;+currentPose;&lt;br /&gt;
    //todo somewhere. some better wrap around.&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    if ((offset) || (llGetListLength(present)&amp;gt;12))&lt;br /&gt;
        present = llList2List(present, offset, offset+8) + [&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;, &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;, &amp;quot;BACK&amp;quot;];        &lt;br /&gt;
    &lt;br /&gt;
    if (llGetListLength(rlvVictims)) {&lt;br /&gt;
        h+=&amp;quot;\nCaptured (RLV): &amp;quot;;&lt;br /&gt;
        for (i=0; i&amp;lt;llGetListLength(rlvVictims); i++)&lt;br /&gt;
            h+=llKey2Name((key)llList2String(rlvVictims, i))+&amp;quot;\n&amp;quot;;&lt;br /&gt;
    }    &lt;br /&gt;
    &lt;br /&gt;
    //got our filled up menu here? prolly need to sort it, for now just present it&lt;br /&gt;
    //llOwnerSay (name+&amp;quot;:&amp;quot;+llList2CSV(present));&lt;br /&gt;
    &lt;br /&gt;
    //invert our list&lt;br /&gt;
    list p;&lt;br /&gt;
    for (i=0; i&amp;lt;12; i+=3)&lt;br /&gt;
        p = p+llList2List (present, -i-3, -i-1);&lt;br /&gt;
    &lt;br /&gt;
    llDialog (id, version+&amp;quot;\n&amp;quot;+h, p, channel);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
processCommand (key id, string message) {&lt;br /&gt;
        integer typeidx=llListFindList (itemNames, [message]);&lt;br /&gt;
        string param;&lt;br /&gt;
        integer newMenu=TRUE;&lt;br /&gt;
        &lt;br /&gt;
        if (typeidx&amp;lt;0) {&lt;br /&gt;
            list l=llParseString2List(message, [&amp;quot;::&amp;quot;], []);&lt;br /&gt;
            message=llList2String(l,0);&lt;br /&gt;
            param=llList2String(l,1);&lt;br /&gt;
            typeidx=llListFindList (itemNames, [message]);&lt;br /&gt;
            //llOwnerSay (&amp;quot;Message &amp;quot;+message+&amp;quot; got param &amp;quot;+param);            &lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if (typeidx&amp;lt;0) {&lt;br /&gt;
            //llOwnerSay (&amp;quot;Error - no menu entry for &amp;quot;+message);&lt;br /&gt;
            return;    &lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
           &lt;br /&gt;
        integer type=llList2Integer(itemTypes, typeidx);&lt;br /&gt;
        //llOwnerSay (&amp;quot;Type for &amp;quot;+message+&amp;quot; is &amp;quot;+(string)type);&lt;br /&gt;
        if (type==TYPE_MENU) {&lt;br /&gt;
            if (hasMenuAccess(id, message)) {&lt;br /&gt;
                makeMenu(message, id);           &lt;br /&gt;
                newMenu=FALSE;                &lt;br /&gt;
            } else {&lt;br /&gt;
                llRegionSayTo (id, 0, &amp;quot;Access to menu &amp;quot;+message+&amp;quot; is denied.&amp;quot;);&lt;br /&gt;
                //makeMenu(currentMenu, id);                   &lt;br /&gt;
                //return;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (type==TYPE_POSE) {&lt;br /&gt;
            llMessageLinked (LINK_THIS, MSG_DO_POSE, message, &amp;quot;&amp;quot;);&lt;br /&gt;
            currentPose=message;&lt;br /&gt;
            llMessageLinked (LINK_THIS, MSG_MENU_META,llList2String(menuDetails, 1+llListFindList(menuDetails, [currentMenu])), &amp;quot;&amp;quot;);            &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (type==TYPE_LM_NOMENU) {&lt;br /&gt;
            llMessageLinked (LINK_THIS, MSG_DO_LM, message, id);&lt;br /&gt;
            newMenu=FALSE;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (type==TYPE_LM_MENU) {&lt;br /&gt;
            llMessageLinked (LINK_THIS, MSG_DO_LM, message, id);&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (type==TYPE_SOUND) {&lt;br /&gt;
            llMessageLinked (LINK_THIS, MSG_DO_SOUND, message, id);               &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        //some built in messages&lt;br /&gt;
        if (type=TYPE_SPECIAL) {&lt;br /&gt;
        &lt;br /&gt;
            if  (message==&amp;quot;SWAP&amp;quot;) {&lt;br /&gt;
                &lt;br /&gt;
                if ((integer)param) {            &lt;br /&gt;
                    llMessageLinked (LINK_THIS, MSG_DO_SWAP, param, id);&lt;br /&gt;
                }&lt;br /&gt;
                else {&lt;br /&gt;
                    llMessageLinked (LINK_THIS, MSG_MENU_SWAP, (string)channel, id);             &lt;br /&gt;
                    newMenu=FALSE;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
    &lt;br /&gt;
            if  (message==&amp;quot;STOP&amp;quot;) {&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_DO_STOP, &amp;quot;&amp;quot;, id);&lt;br /&gt;
                newMenu=FALSE;&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
                &lt;br /&gt;
            if  (message==&amp;quot;BACK&amp;quot;) {&lt;br /&gt;
                //check menu history&lt;br /&gt;
                string newM=&amp;quot;&amp;quot;;&lt;br /&gt;
                integer i=llGetListLength (menuHistory)-1;            &lt;br /&gt;
                while ((i&amp;gt;0) &amp;amp;&amp;amp; (-1&amp;lt;llListFindList([&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;, &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;], [llList2String(menuHistory, i)]))) i--;&lt;br /&gt;
                if (i&amp;gt;0) {&lt;br /&gt;
                    menuHistory=llList2List(menuHistory, 0, i);&lt;br /&gt;
                    newM=llList2String(menuHistory,i-1);                        &lt;br /&gt;
                }&lt;br /&gt;
                makeMenu(newM, id);&lt;br /&gt;
                newMenu=FALSE;&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if ((message==&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;quot;) || (message==&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;quot;)) {&lt;br /&gt;
                //previous and next. let menumaker solve this.&lt;br /&gt;
                makeMenu(message, id);&lt;br /&gt;
                newMenu=FALSE;&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if (message==&amp;quot;&amp;lt;BACK&amp;quot;) {&lt;br /&gt;
                //makeMenu(currentMenu, id);&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            //anything we don&#039;t know off for some reason. include it anyways.&lt;br /&gt;
            if (message==&amp;quot;DUMP&amp;quot;) {&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_DUMP_POSITIONS, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);                   &lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if (message==&amp;quot;CHAT&amp;quot;) {&lt;br /&gt;
                mode_chat=!mode_chat;&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_MODE_CHAT, (string)mode_chat, id);&lt;br /&gt;
                llRegionSayTo (id, 0, &amp;quot;Chat &amp;quot;+onOff(mode_chat));   &lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if (message==&amp;quot;ADJUST&amp;quot;) {&lt;br /&gt;
                mode_adjust=!mode_adjust;&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_MODE_ADJUST, (string)mode_adjust, id);                &lt;br /&gt;
                llRegionSayTo (id, 0, &amp;quot;Adjusting : &amp;quot;+onOff(mode_adjust));   &lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if (message==&amp;quot;MENUUSERS&amp;quot;) {&lt;br /&gt;
                mode_menu++;&lt;br /&gt;
                if (mode_menu&amp;gt;3)&lt;br /&gt;
                    mode_menu=0;&lt;br /&gt;
                llRegionSayTo (id, 0, &amp;quot;Menu access set to &amp;quot;+aclMode(mode_menu));                   &lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if (message==&amp;quot;BALLUSERS&amp;quot;) {&lt;br /&gt;
                mode_ball++;&lt;br /&gt;
                if (mode_ball&amp;gt;2)&lt;br /&gt;
                    mode_ball=0;&lt;br /&gt;
                llRegionSayTo (id, 0, &amp;quot;Usage access set to &amp;quot;+aclMode(mode_ball));                   &lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_MODE_BALLUSERS, (string)mode_ball, id);                                &lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if (-1&amp;lt;llListFindList ([&amp;quot;RESET&amp;quot;, &amp;quot;RESTART&amp;quot;, &amp;quot;RELOAD&amp;quot;], [message])) {&lt;br /&gt;
                llSay (0, &amp;quot;Reset sequence started... Touch me again in a few seconds to reload the configuration.&amp;quot;);&lt;br /&gt;
                reset(TRUE);   &lt;br /&gt;
                newMenu=FALSE;&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if (message==&amp;quot;Z&amp;quot;) {&lt;br /&gt;
                if (&amp;quot;+&amp;quot;==llGetSubString(param,0,0))&lt;br /&gt;
                    param=llGetSubString(param,1,-1);                &lt;br /&gt;
                llSetObjectDesc((string)((integer)llGetObjectDesc()+(integer)param)+llGetSubString(llGetObjectDesc(), llStringLength((string)((integer)llGetObjectDesc())), -1));&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_UPDATE_POS, (string)mode_ball, id);                &lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if (message==&amp;quot;OFF&amp;quot;) {&lt;br /&gt;
                state Off;&lt;br /&gt;
                newMenu=FALSE;&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if (message==&amp;quot;SAVE&amp;quot;) {&lt;br /&gt;
                defaultPose=currentPose;&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_SET_DEFAULT_POSE, currentPose, &amp;quot;&amp;quot;);&lt;br /&gt;
   &lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if (message==&amp;quot;GRAB&amp;quot;) {&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_RLV_GRAB, &amp;quot;&amp;quot;, id);&lt;br /&gt;
                newMenu=FALSE;                               &lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            if (message==&amp;quot;RELEASE&amp;quot;) {&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_RLV_RELEASE, &amp;quot;&amp;quot;, id);                            &lt;br /&gt;
            }&lt;br /&gt;
            else {&lt;br /&gt;
                //forward to whoever handles it&lt;br /&gt;
                llMessageLinked (LINK_THIS, MSG_DO_SPECIAL, message, id);            &lt;br /&gt;
            }&lt;br /&gt;
        }  &lt;br /&gt;
                  &lt;br /&gt;
        if (newMenu)&lt;br /&gt;
            makeMenu(currentMenu, id);            &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
upgrade() {string self = llGetScriptName(); string basename = self; if (llSubStringIndex(self, &amp;quot; &amp;quot;) &amp;gt;= 0) {integer start = 2; string tail = llGetSubString(self, llStringLength(self) - start, -1); while (llGetSubString(tail, 0, 0) != &amp;quot; &amp;quot;) {start++; tail = llGetSubString(self, llStringLength(self) - start, -1);} if ((integer)tail &amp;gt; 0) {basename = llGetSubString(self, 0, -llStringLength(tail) - 1);}} integer n = llGetInventoryNumber(INVENTORY_SCRIPT); while (n-- &amp;gt; 0) {string item = llGetInventoryName(INVENTORY_SCRIPT, n); if (item != self &amp;amp;&amp;amp; 0 == llSubStringIndex(item, basename)) {llRemoveInventory(item);}}}&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        upgrade();&lt;br /&gt;
        state WaitTouch;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state WaitTouch&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        reset(FALSE);&lt;br /&gt;
        llSay (0,&amp;quot;TMCP resetted - Touch me to load the configuration&amp;quot;);&lt;br /&gt;
    }    &lt;br /&gt;
    touch_start (integer n) {&lt;br /&gt;
        llSay (0,&amp;quot;TMCP startup - reading data&amp;quot;);&lt;br /&gt;
        state reading_data;   &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
state reading_data&lt;br /&gt;
{    &lt;br /&gt;
    state_entry() {&lt;br /&gt;
        llMessageLinked (LINK_THIS, MSG_DATA_START_READ, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);   &lt;br /&gt;
    }&lt;br /&gt;
    link_message (integer sn, integer n, string m, key id) {&lt;br /&gt;
        if (n==MSG_DATA_MENU) {&lt;br /&gt;
            //add action    &lt;br /&gt;
            menuNames+=m;&lt;br /&gt;
            menuEntries+=(string)id;&lt;br /&gt;
        } else&lt;br /&gt;
        if (n==MSG_DATA_MENU_DETAILS) {&lt;br /&gt;
            //add action    &lt;br /&gt;
            menuDetails+= [m, (string)id];&lt;br /&gt;
        } else&lt;br /&gt;
        &lt;br /&gt;
        if (n==MSG_DATA_TYPE) {&lt;br /&gt;
            //set type&lt;br /&gt;
            itemNames+=m;&lt;br /&gt;
            itemTypes+=(integer)((string)id);   &lt;br /&gt;
        }&lt;br /&gt;
        if (n==MSG_SET_RUNNING)&lt;br /&gt;
            state running;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state running {&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llOwnerSay (&amp;quot;Menu ready. &amp;quot;+(string)llGetFreeMemory());&lt;br /&gt;
        channel=-(integer)llFrand(1309123)-492345;&lt;br /&gt;
        listenhandle=llListen (channel, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    touch_start(integer total_number)&lt;br /&gt;
    {&lt;br /&gt;
        key id=llDetectedKey(0);&lt;br /&gt;
        if (!hasDialogAccess(id)) {&lt;br /&gt;
            if (mode_chat)&lt;br /&gt;
                llWhisper (0, &amp;quot;Sorry &amp;quot;+llKey2Name(id)+&amp;quot;, but menu usage is limited to &amp;quot;+aclMode(mode_menu));&lt;br /&gt;
            return;   &lt;br /&gt;
        }        &lt;br /&gt;
        makeMenu(&amp;quot;&amp;quot;,id);&lt;br /&gt;
    } &lt;br /&gt;
    &lt;br /&gt;
    listen (integer ch, string name, key id, string message) {&lt;br /&gt;
        &lt;br /&gt;
        if (!hasDialogAccess(id)) {&lt;br /&gt;
            if (mode_chat)&lt;br /&gt;
                llWhisper (0, &amp;quot;Sorry &amp;quot;+llKey2Name(id)+&amp;quot;, but menu usage is limited to &amp;quot;+aclMode(mode_menu));&lt;br /&gt;
            return;   &lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if (hibernate) {&lt;br /&gt;
            setRunning(TRUE);&lt;br /&gt;
            hibernate=FALSE;   &lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        //llSetTimerEvent (3600.);&lt;br /&gt;
        &lt;br /&gt;
        processCommand (id, message);&lt;br /&gt;
        &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    link_message (integer sn, integer n, string m, key id) {&lt;br /&gt;
        if (n==MSG_DO_MENU_COMMAND) {&lt;br /&gt;
            processCommand (id, m);    &lt;br /&gt;
        }   &lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_DO_DEFAULT_POSE) {&lt;br /&gt;
            currentPose = defaultPose;   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_RLV_VICTIM_LIST) {&lt;br /&gt;
            rlvVictims=llCSV2List(m);   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (n==MSG_DO_MENU_CURRENTMENU) {&lt;br /&gt;
            makeMenu(currentMenu, id);   &lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    timer() {&lt;br /&gt;
        //inactivity detected, sleep all other scripts.        &lt;br /&gt;
        llSetTimerEvent(0.);&lt;br /&gt;
        hibernate=TRUE;&lt;br /&gt;
        setRunning(FALSE);   &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state Off {&lt;br /&gt;
    state_entry() {&lt;br /&gt;
        llMessageLinked (LINK_THIS, MSG_ALL_UNSIT, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);    &lt;br /&gt;
        llWhisper (0,&amp;quot;Switching off in 10... 9...&amp;quot;);&lt;br /&gt;
        llSleep (5.0);&lt;br /&gt;
        setRunning(FALSE);        &lt;br /&gt;
        llSleep (5.0);&lt;br /&gt;
        llSitTarget(ZERO_VECTOR, ZERO_ROTATION);        &lt;br /&gt;
    }   &lt;br /&gt;
    &lt;br /&gt;
    touch_start(integer n) {&lt;br /&gt;
        key id=llDetectedKey(0);&lt;br /&gt;
        if (id==llGetOwner())&lt;br /&gt;
            state running;&lt;br /&gt;
        if ((mode_menu==1) &amp;amp;&amp;amp; llSameGroup(id))&lt;br /&gt;
            state running;&lt;br /&gt;
        llRegionSayTo (id, 0, &amp;quot;Sorry, but this object is switched OFF. Ask the owner to turn it on.&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    state_exit() {&lt;br /&gt;
        setRunning(TRUE);&lt;br /&gt;
        hibernate=FALSE; &lt;br /&gt;
        llWhisper (0, &amp;quot;Switching on&amp;quot;);&lt;br /&gt;
          &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==TMCP - notecard reader==&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
//read MLP notecards&lt;br /&gt;
//see how much memory headroom we got after for other stuff&lt;br /&gt;
&lt;br /&gt;
integer notecardidx;&lt;br /&gt;
key notecardkey;&lt;br /&gt;
integer notecardtype;&lt;br /&gt;
integer notecardline;&lt;br /&gt;
string notecardname;&lt;br /&gt;
list positions;&lt;br /&gt;
list tempMenu;&lt;br /&gt;
list menuNames;&lt;br /&gt;
list menuEntries; //menus that appear in &#039;auto&#039; menu&lt;br /&gt;
list toMenu; //menus with pointers&lt;br /&gt;
list linkedMsg;&lt;br /&gt;
&lt;br /&gt;
integer hasReset=FALSE; //indicates if there is a reset option in *some* menu. If absent, we add it for safety.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
integer TYPE_MENU=1;&lt;br /&gt;
integer TYPE_POSE=2;&lt;br /&gt;
integer TYPE_LM_NOMENU=3;&lt;br /&gt;
integer TYPE_LM_MENU=4;&lt;br /&gt;
integer TYPE_IGNORE=5;&lt;br /&gt;
integer TYPE_SPECIAL=6;&lt;br /&gt;
integer TYPE_UNKNOWN=7;&lt;br /&gt;
integer TYPE_SOUND=8;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DATA_MENU=310;&lt;br /&gt;
integer MSG_DATA_MENU_DETAILS=311;&lt;br /&gt;
integer MSG_DATA_TYPE=320;&lt;br /&gt;
integer MSG_DATA_POSE=330;&lt;br /&gt;
integer MSG_DATA_POSITION=331;&lt;br /&gt;
integer MSG_DATA_LM=335;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_POSE=350;&lt;br /&gt;
integer MSG_DO_LM=351;&lt;br /&gt;
integer MSG_DO_SPECIAL=352;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DO_STOP=353;&lt;br /&gt;
integer MSG_DO_SWAP=354;&lt;br /&gt;
&lt;br /&gt;
integer MSG_SET_RUNNING=390;&lt;br /&gt;
integer MSG_STORAGE_RESET=391;&lt;br /&gt;
integer MSG_DATA_READY=309;&lt;br /&gt;
&lt;br /&gt;
integer MSG_DATA_START_READ=301;&lt;br /&gt;
&lt;br /&gt;
verbose(string text) {&lt;br /&gt;
    llOwnerSay (text);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
startNotecard() {&lt;br /&gt;
    integer i;&lt;br /&gt;
    notecardline=0;    &lt;br /&gt;
    for (;notecardidx&amp;lt;llGetInventoryNumber(INVENTORY_NOTECARD); notecardidx++) {                &lt;br /&gt;
        //loop until we found appropiate card&lt;br /&gt;
        notecardname=llGetInventoryName(INVENTORY_NOTECARD, notecardidx);&lt;br /&gt;
        if (llGetSubString(notecardname,0,9)==&amp;quot;.MENUITEMS&amp;quot;) {&lt;br /&gt;
            //neato. go fetch it&lt;br /&gt;
            notecardtype=1;&lt;br /&gt;
            notecardkey=llGetNotecardLine(notecardname, 0);&lt;br /&gt;
            verbose (&amp;quot;Reading menu from &amp;quot;+notecardname);&lt;br /&gt;
            return;            &lt;br /&gt;
        }&lt;br /&gt;
        if (llGetSubString(notecardname,0,9)==&amp;quot;.POSITIONS&amp;quot;) {&lt;br /&gt;
            //neato. go fetch it&lt;br /&gt;
            notecardtype=2;&lt;br /&gt;
            notecardkey=llGetNotecardLine(notecardname, 0);&lt;br /&gt;
            verbose (&amp;quot;Reading positions from &amp;quot;+notecardname);&lt;br /&gt;
            return;            &lt;br /&gt;
        }     &lt;br /&gt;
        verbose (&amp;quot;Skipping &amp;quot;+notecardname);&lt;br /&gt;
        &lt;br /&gt;
    }&lt;br /&gt;
    //still here? then we&#039;r done&lt;br /&gt;
    //verbose (&amp;quot;Done reading all notecards&amp;quot;);&lt;br /&gt;
    postFixMenu();&lt;br /&gt;
    sendMenuItems();&lt;br /&gt;
    llSleep (2.0);&lt;br /&gt;
    llMessageLinked (LINK_THIS, MSG_SET_RUNNING, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;); //set to running&lt;br /&gt;
    verbose (&amp;quot;Ready.&amp;quot;);&lt;br /&gt;
    //llOwnerSay (&amp;quot;Notecard reader free memory: &amp;quot;+(string)llGetFreeMemory());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
addPose (string name, list data) {&lt;br /&gt;
    //add pose info.. link to position info exactly when again?   &lt;br /&gt;
    //positions+=[name, data];&lt;br /&gt;
    llMessageLinked (LINK_THIS, MSG_DATA_POSE, name, llDumpList2String(data, &amp;quot;|&amp;quot;));       &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
addMenuDetails (string name, list data) {&lt;br /&gt;
    //add menu details.. access, color of balls.&lt;br /&gt;
    llMessageLinked (LINK_THIS, MSG_DATA_MENU_DETAILS, name, llDumpList2String(data, &amp;quot;|&amp;quot;));       &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
addLM (string name, string data) {&lt;br /&gt;
    llMessageLinked (LINK_THIS, MSG_DATA_LM, name, data);   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
setType (string name, integer type) {&lt;br /&gt;
    llMessageLinked (LINK_THIS, MSG_DATA_TYPE, name, (string)type);       &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
parseMenu() {&lt;br /&gt;
    //parse our temporary menu to a real menu;   &lt;br /&gt;
    //this is where the real stuff happens.&lt;br /&gt;
    integer i;&lt;br /&gt;
    string menuName=&amp;quot;&amp;quot;; //MLP 1 compatability: don&#039;t add stuff to menu as long as menu name is empty. add poses though.&lt;br /&gt;
    list options;&lt;br /&gt;
    for (i=0; i&amp;lt;llGetListLength(tempMenu); i++) {&lt;br /&gt;
        string data=llList2String(tempMenu, i);&lt;br /&gt;
        integer posspace=llSubStringIndex(data, &amp;quot; &amp;quot;);&lt;br /&gt;
        string cmd=data;&lt;br /&gt;
        string param=&amp;quot;&amp;quot;;&lt;br /&gt;
        string option=&amp;quot;&amp;quot;;&lt;br /&gt;
        if (posspace&amp;gt;0) {&lt;br /&gt;
            cmd=llGetSubString(data,0,posspace-1);&lt;br /&gt;
            param=llGetSubString(data, posspace+1, -1);   &lt;br /&gt;
        }&lt;br /&gt;
        list paramsTmp=llParseString2List(param, [&amp;quot;|&amp;quot;], []);&lt;br /&gt;
        integer j;&lt;br /&gt;
        list params;&lt;br /&gt;
        for (j=0; j&amp;lt;llGetListLength(paramsTmp); j++)&lt;br /&gt;
            params+=llStringTrim(llList2String(paramsTmp, j), STRING_TRIM);&lt;br /&gt;
        //params are now nice seperated on |, still allowed to contain spaces in the middle but trimmed from the outside.&lt;br /&gt;
        string p1=llList2String(params, 0);&lt;br /&gt;
        string p2=llList2String(params, 1);&lt;br /&gt;
        string p3=llList2String(params, 2);&lt;br /&gt;
        //got our set of command and optional parameters now. let&#039;s test them.&lt;br /&gt;
        if (cmd==&amp;quot;MENU&amp;quot;) {&lt;br /&gt;
            addMenuDetails (p1, llDeleteSubList(params,0,0));&lt;br /&gt;
            //menuEntries+=p1;&lt;br /&gt;
            menuName=p1; //additional params hint the number of available seats            &lt;br /&gt;
            setType (p1, TYPE_MENU);  &lt;br /&gt;
        } else&lt;br /&gt;
        if (cmd==&amp;quot;POSE&amp;quot;) {&lt;br /&gt;
            addPose (p1, llDeleteSubList(params,0,0));   &lt;br /&gt;
            option = p1;&lt;br /&gt;
            setType (p1, TYPE_POSE);&lt;br /&gt;
        } else&lt;br /&gt;
        if (cmd==&amp;quot;SOUND&amp;quot;) {&lt;br /&gt;
            addLM (p1, p2);   &lt;br /&gt;
            option = p1;&lt;br /&gt;
            setType (p1, TYPE_SOUND);&lt;br /&gt;
        } else&lt;br /&gt;
        if (-1 != llListFindList ([&amp;quot;BACK&amp;quot;, &amp;quot;STOP&amp;quot;,&amp;quot;SWAP&amp;quot;,&amp;quot;RESET&amp;quot;,&amp;quot;RESTART&amp;quot;, &amp;quot;MENUUSERS&amp;quot;, &amp;quot;BALLUSERS&amp;quot;,&amp;quot;ADJUST&amp;quot;, &amp;quot;DUMP&amp;quot;, &amp;quot;CHAT&amp;quot;, &amp;quot;RELOAD&amp;quot;, &amp;quot;OFF&amp;quot;], [cmd])) {&lt;br /&gt;
            //recognized simple options&lt;br /&gt;
            option = cmd;   &lt;br /&gt;
            setType (cmd, TYPE_SPECIAL);&lt;br /&gt;
            if (-1!= llListFindList ([&amp;quot;RESET&amp;quot;,&amp;quot;RESTART&amp;quot;, &amp;quot;RELOAD&amp;quot;], [cmd]))&lt;br /&gt;
                hasReset=TRUE;&lt;br /&gt;
        } else&lt;br /&gt;
        if (-1 != llListFindList ([&amp;quot;SAVE&amp;quot;, &amp;quot;CHECK&amp;quot;], [cmd])) {&lt;br /&gt;
            //recognized simple options&lt;br /&gt;
            option = cmd;   &lt;br /&gt;
            setType (cmd, TYPE_IGNORE);&lt;br /&gt;
        } else&lt;br /&gt;
        if (cmd==&amp;quot;TOMENU&amp;quot;) {&lt;br /&gt;
            if (p1!=&amp;quot;-&amp;quot;)&lt;br /&gt;
                toMenu+=p1;&lt;br /&gt;
            option=p1;   &lt;br /&gt;
        } else&lt;br /&gt;
        if (cmd==&amp;quot;LINKMSG&amp;quot;) {&lt;br /&gt;
            //linkedMsg+=[p1,p2];&lt;br /&gt;
            addLM (p1, p2);&lt;br /&gt;
            option=p1;&lt;br /&gt;
            if ((integer)p2)&lt;br /&gt;
                setType (p1, TYPE_LM_NOMENU);&lt;br /&gt;
            else&lt;br /&gt;
                setType (p1, TYPE_LM_MENU);&lt;br /&gt;
        } else&lt;br /&gt;
        if (-1&amp;lt;llListFindList([&amp;quot;Z+&amp;quot;, &amp;quot;Z-&amp;quot;], [llGetSubString(cmd, 0, 1)])) {&lt;br /&gt;
            //Z command, we&#039;ll rewrite it&lt;br /&gt;
            option = &amp;quot;Z::&amp;quot;+llGetSubString(cmd, 1, -1);&lt;br /&gt;
            setType (&amp;quot;Z&amp;quot;, TYPE_SPECIAL);&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (-1&amp;lt;llListFindList ([&amp;quot;GRAB&amp;quot;, &amp;quot;Grab.Fem&amp;quot;], [cmd])) {&lt;br /&gt;
            option = &amp;quot;GRAB&amp;quot;;&lt;br /&gt;
            setType (&amp;quot;GRAB&amp;quot;, TYPE_SPECIAL);               &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (-1&amp;lt;llListFindList ([&amp;quot;Grab.Male&amp;quot;,&amp;quot;RELEASE&amp;quot;], [cmd])) {&lt;br /&gt;
            option = &amp;quot;RELEASE&amp;quot;;&lt;br /&gt;
            setType (&amp;quot;RELEASE&amp;quot;, TYPE_SPECIAL);                           &lt;br /&gt;
        }&lt;br /&gt;
        //todo.. fill in a bunch of MLP commands here, implemented or not&lt;br /&gt;
        else&lt;br /&gt;
        { //we checked all commands. Anything defined here is considered undefined and we list it just as is.&lt;br /&gt;
            option = cmd;&lt;br /&gt;
            //don&#039;t set type. it may be defined elsewhere.&lt;br /&gt;
            //setType (cmd, TYPE_UNKNOWN);            &lt;br /&gt;
        }&lt;br /&gt;
        if (menuName) if (option)&lt;br /&gt;
            options+=option;&lt;br /&gt;
    }&lt;br /&gt;
    tempMenu=[];&lt;br /&gt;
    if (options!=[]) {&lt;br /&gt;
        llOwnerSay (&amp;quot;Menu &amp;quot;+menuName +&amp;quot; [&amp;quot;+(string)llGetListLength(options)+&amp;quot;]&amp;quot;);&lt;br /&gt;
        //menuAll+=options+&amp;quot;!--!&amp;quot;;&lt;br /&gt;
        //menuAll+=[menuName,llList2CSV(options)];&lt;br /&gt;
        menuNames+=menuName;&lt;br /&gt;
        menuEntries+=llList2CSV(options);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
addMenuItem(string data) {&lt;br /&gt;
    integer posslash=llSubStringIndex(data, &amp;quot;//&amp;quot;);&lt;br /&gt;
    if (posslash&amp;gt;=0) {&lt;br /&gt;
        data=llDeleteSubString(data, posslash, -1);&lt;br /&gt;
    }&lt;br /&gt;
    data=llStringTrim(data,STRING_TRIM);&lt;br /&gt;
    //llOwnerSay (&amp;quot;menu data: &amp;quot;+data);&lt;br /&gt;
    &lt;br /&gt;
    if (data==&amp;quot;&amp;quot;) //comment or some but not empty line, silently ignore&lt;br /&gt;
        return;&lt;br /&gt;
    &lt;br /&gt;
    if (llGetSubString (data,0,3+1)==&amp;quot;MENU &amp;quot;) {&lt;br /&gt;
        //what a surprise, new menu. finish old one.&lt;br /&gt;
        parseMenu();&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //what&#039;s left, add it to our temp menu. We&#039;l parse it later.&lt;br /&gt;
    tempMenu+=data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
postFixMenu() {&lt;br /&gt;
    //on failed configurations - add some default stuff&lt;br /&gt;
    if (!llGetListLength(menuNames)) {&lt;br /&gt;
        &lt;br /&gt;
        llOwnerSay (&amp;quot;Warning - no reset function found in menu cards. Adding menu &#039;Reset&#039;.&amp;quot;);&lt;br /&gt;
        //add a default menu with a reset button.&lt;br /&gt;
        &lt;br /&gt;
        addMenuItem (&amp;quot;MENU Reset...|OWNER&amp;quot;);&lt;br /&gt;
        addMenuItem (&amp;quot;RESET&amp;quot;);&lt;br /&gt;
        parseMenu();&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    //dont add mainmenu&lt;br /&gt;
    list entries=llDeleteSubList(menuNames,0,0);&lt;br /&gt;
    &lt;br /&gt;
    integer i;&lt;br /&gt;
    &lt;br /&gt;
    //llOwnerSay (&amp;quot;PF entries: &amp;quot;+(string)entries);&lt;br /&gt;
    //llOwnerSay (&amp;quot;PF tomenu: &amp;quot;+(string)toMenu);    &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    for (i=0; i&amp;lt;llGetListLength(toMenu); i++) {        &lt;br /&gt;
        integer j=llListFindList (entries, [llList2String(toMenu, i)]);&lt;br /&gt;
        if (j&amp;gt;-1) {&lt;br /&gt;
            entries=llDeleteSubList(entries, j, j);&lt;br /&gt;
        }        &lt;br /&gt;
    }&lt;br /&gt;
    //llOwnerSay (&amp;quot;PF entries after: &amp;quot;+(string)entries);&lt;br /&gt;
    &lt;br /&gt;
    list MainMenu=llCSV2List(llList2String(menuEntries, 0));&lt;br /&gt;
    for (i=0; i&amp;lt;llGetListLength(entries); i++) {&lt;br /&gt;
        integer j=llListFindList(MainMenu, [&amp;quot;-&amp;quot;]);&lt;br /&gt;
        if (j&amp;gt;-1) {&lt;br /&gt;
            MainMenu=llListReplaceList(MainMenu, [llList2String(entries, i)], j, j);            &lt;br /&gt;
        }   &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    i=llListFindList(MainMenu, [&amp;quot;-&amp;quot;]);&lt;br /&gt;
    while (-1&amp;lt;i) {&lt;br /&gt;
        MainMenu=llDeleteSubList(MainMenu, i, i);&lt;br /&gt;
        i=llListFindList(MainMenu, [&amp;quot;-&amp;quot;]);               &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    if (MainMenu)&lt;br /&gt;
        menuEntries = llListReplaceList(menuEntries, [llList2CSV(MainMenu)], 0, 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sendMenuItems() {&lt;br /&gt;
    //llOwnerSay (&amp;quot;Applying menu information&amp;quot;);&lt;br /&gt;
    &lt;br /&gt;
    integer i;&lt;br /&gt;
    for (i=0; i&amp;lt;llGetListLength(menuNames); i++) {&lt;br /&gt;
        llMessageLinked (LINK_THIS, MSG_DATA_MENU, llList2String(menuNames, i), llList2String(menuEntries, i));            &lt;br /&gt;
        llSleep (0.25);&lt;br /&gt;
    }    &lt;br /&gt;
    &lt;br /&gt;
    llMessageLinked (LINK_THIS, MSG_DATA_READY, &amp;quot;Done&amp;quot;, &amp;quot;TTP&amp;quot;);    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
addPosition(string data) {&lt;br /&gt;
    //some memory optimalization possible here in last half.&lt;br /&gt;
    integer curlyopen = llSubStringIndex(data, &amp;quot;{&amp;quot;);&lt;br /&gt;
    integer curlyclose = llSubStringIndex(data, &amp;quot;}&amp;quot;);&lt;br /&gt;
    if ((curlyopen&amp;lt;0) || (curlyclose&amp;lt;curlyopen))&lt;br /&gt;
        return;&lt;br /&gt;
    string pose=llGetSubString(data, curlyopen+1, curlyclose-1);&lt;br /&gt;
    data=llGetSubString(data, curlyclose+1, -1);&lt;br /&gt;
    list posrotsraw=llParseString2List(data, [&amp;quot;&amp;gt;&amp;quot;], []);&lt;br /&gt;
    //llOwnerSay (&amp;quot;raw pos data &amp;quot;+data+&amp;quot; convert to &amp;quot;+(string)posrotsraw);&lt;br /&gt;
    &lt;br /&gt;
    list posrots;&lt;br /&gt;
    integer i;&lt;br /&gt;
    for (i=0; i&amp;lt;llGetListLength(posrotsraw); i++) {&lt;br /&gt;
        if (-1&amp;lt;llSubStringIndex (llList2String(posrotsraw,i), &amp;quot;&amp;lt;&amp;quot;)) {&lt;br /&gt;
            list v=llParseString2List(llList2String(posrotsraw,i), [&amp;quot;&amp;lt;&amp;quot;, &amp;quot;,&amp;quot;, &amp;quot; &amp;quot;], []);         &lt;br /&gt;
            posrots += &amp;lt;(float)llList2String(v,0), (float)llList2String(v,1),(float)llList2String(v,2)&amp;gt;;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //llOwnerSay (&amp;quot;position data for &amp;quot;+pose+&amp;quot; : &amp;quot;+(string)posrots);&lt;br /&gt;
    //positions+=[pose, llList2CSV(posrots)];&lt;br /&gt;
    llMessageLinked (LINK_THIS,MSG_DATA_POSITION, pose, llDumpList2String(posrots,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
upgrade() {string self = llGetScriptName(); string basename = self; if (llSubStringIndex(self, &amp;quot; &amp;quot;) &amp;gt;= 0) {integer start = 2; string tail = llGetSubString(self, llStringLength(self) - start, -1); while (llGetSubString(tail, 0, 0) != &amp;quot; &amp;quot;) {start++; tail = llGetSubString(self, llStringLength(self) - start, -1);} if ((integer)tail &amp;gt; 0) {basename = llGetSubString(self, 0, -llStringLength(tail) - 1);}} integer n = llGetInventoryNumber(INVENTORY_SCRIPT); while (n-- &amp;gt; 0) {string item = llGetInventoryName(INVENTORY_SCRIPT, n); if (item != self &amp;amp;&amp;amp; 0 == llSubStringIndex(item, basename)) {llRemoveInventory(item);}}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
default &lt;br /&gt;
{&lt;br /&gt;
    state_entry() {        &lt;br /&gt;
        upgrade();&lt;br /&gt;
        //state ReadMenu;           &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    link_message (integer sn, integer n, string m, key id) {&lt;br /&gt;
        if (n==301)&lt;br /&gt;
            state ReadMenu;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state ReadMenu&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llMessageLinked (LINK_THIS, MSG_STORAGE_RESET, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;); //reset data storage scripts&lt;br /&gt;
        llSleep (2.0);&lt;br /&gt;
        //fetch first notecard, go on from there&lt;br /&gt;
        startNotecard ();&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    dataserver(key id, string data) {&lt;br /&gt;
        //llOwnerSay (&amp;quot;card &amp;quot;+notecardname+&amp;quot; line &amp;quot;+(string)notecardline+&amp;quot; data &amp;quot;+data);&lt;br /&gt;
        &lt;br /&gt;
        if (id!=notecardkey)&lt;br /&gt;
            return; //not for us&lt;br /&gt;
            &lt;br /&gt;
        if (data==EOF) {&lt;br /&gt;
            if (notecardtype==1)&lt;br /&gt;
                parseMenu(); //clean up any menu leftovers&lt;br /&gt;
            //read next notecard&lt;br /&gt;
            notecardidx++;&lt;br /&gt;
            startNotecard();&lt;br /&gt;
        } else   &lt;br /&gt;
        {&lt;br /&gt;
            if (notecardtype==1)&lt;br /&gt;
                addMenuItem(data);&lt;br /&gt;
            else&lt;br /&gt;
                addPosition(data);&lt;br /&gt;
            notecardkey=llGetNotecardLine(notecardname, ++notecardline);&lt;br /&gt;
&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==TMCP RLV extensions (optional)==&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
//Changes by Tano Toll for seamless MLCP compatability, and to dodge &#039;double locking&#039;:&lt;br /&gt;
&lt;br /&gt;
//*sit and unsit events do not trigger an RLV command (master script already does this)&lt;br /&gt;
//*identifier is changed to object name, url encoded.&lt;br /&gt;
//*delayed but automatic notecard read on inventory change&lt;br /&gt;
&lt;br /&gt;
// ----------------------------------------------------------------------------------&lt;br /&gt;
// MLPV2 Plugin for RLV Script V1.02&lt;br /&gt;
//&lt;br /&gt;
// Use with a notecard named .RLV with the format:&lt;br /&gt;
// Pose|Ball no.: 0,1...*|@RLV-Command&lt;br /&gt;
// e.g.&lt;br /&gt;
// Missionary|1|@unsit=n&lt;br /&gt;
// stand|*|!release&lt;br /&gt;
// ----------------------------------------------------------------------------------&lt;br /&gt;
// Copyright (c) 2010, Jenni Eales. All rights reserved.&lt;br /&gt;
// ----------------------------------------------------------------------------------&lt;br /&gt;
// Redistribution and use in source and binary forms, with or without modification,&lt;br /&gt;
// are permitted provided that the following conditions are met:&lt;br /&gt;
//&lt;br /&gt;
//    * Redistributions of source code must retain the above copyright notice,&lt;br /&gt;
//      this list of conditions and the following disclaimer.&lt;br /&gt;
//    * Redistributions in binary form must reproduce the above copyright notice,&lt;br /&gt;
//      this list of conditions and the following disclaimer in the documentation&lt;br /&gt;
//      and/or other materials provided with the distribution.&lt;br /&gt;
//    * The names of its contributors may not be used to endorse or promote products&lt;br /&gt;
//      derived from this software without specific prior written permission.&lt;br /&gt;
//&lt;br /&gt;
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &amp;quot;AS IS&amp;quot; AND ANY&lt;br /&gt;
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES&lt;br /&gt;
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.&lt;br /&gt;
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,&lt;br /&gt;
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,&lt;br /&gt;
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,&lt;br /&gt;
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,&lt;br /&gt;
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)&lt;br /&gt;
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY&lt;br /&gt;
// OF SUCH DAMAGE.&lt;br /&gt;
//&lt;br /&gt;
// Changes:&lt;br /&gt;
// ----------------------------------------------------------------------------------&lt;br /&gt;
// Version 1.02&lt;br /&gt;
// - use | as seperator&lt;br /&gt;
// - support multiple lines for one pose&lt;br /&gt;
// - additional link message for direct call from ball menu&lt;br /&gt;
//&lt;br /&gt;
// Version 1.01&lt;br /&gt;
// - use ; instead of | as seperator&lt;br /&gt;
//&lt;br /&gt;
// Version 1.0&lt;br /&gt;
// - first version released&lt;br /&gt;
// ----------------------------------------------------------------------------------&lt;br /&gt;
//&lt;br /&gt;
// constants&lt;br /&gt;
string NOTECARD         = &amp;quot;.RLV&amp;quot;; // name of config notecard&lt;br /&gt;
integer DEBUG           = FALSE;  // switch debug on/off&lt;br /&gt;
integer RELAY_CHANNEL   = -1812221819; // channel for RLV relay&lt;br /&gt;
float TIMER_SEC         = 1800.0; // 30 min.&lt;br /&gt;
string CMD_RELEASE      = &amp;quot;!release&amp;quot;;  // release command&lt;br /&gt;
integer LM_NUMBER       = -1819;  // number for link message&lt;br /&gt;
 &lt;br /&gt;
// internal use&lt;br /&gt;
key kQuery;&lt;br /&gt;
integer iLine;&lt;br /&gt;
 &lt;br /&gt;
string pose = &amp;quot;stand&amp;quot;; // pose set by the Ball Menu&lt;br /&gt;
list poses    = [];    // configured poses&lt;br /&gt;
list balls    = [];    // configured balls&lt;br /&gt;
list commands = [];    // configured commands&lt;br /&gt;
list avatars  = [];    // avatars sitting on balls&lt;br /&gt;
&lt;br /&gt;
integer wants_init;&lt;br /&gt;
 &lt;br /&gt;
// log a message&lt;br /&gt;
log(string message)&lt;br /&gt;
{&lt;br /&gt;
    if(DEBUG) llOwnerSay(message);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// only for testing purposes&lt;br /&gt;
log_data()&lt;br /&gt;
{&lt;br /&gt;
    log(&amp;quot;List:&amp;quot;);&lt;br /&gt;
    integer total_number = llGetListLength(commands);&lt;br /&gt;
    integer i;&lt;br /&gt;
    for(i=0; i&amp;lt;total_number; i++)&lt;br /&gt;
    {&lt;br /&gt;
        log(&amp;quot;- &amp;quot; + llList2String(poses, i) + &amp;quot;: (&amp;quot; + llList2String(balls, i) + &amp;quot;) &amp;quot;+ llList2String(commands, i));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// write a message to the RLV Relay&lt;br /&gt;
relay(key avatar, string message)&lt;br /&gt;
{&lt;br /&gt;
    list tokens = llParseString2List(message, [&amp;quot;|&amp;quot;], [&amp;quot;&amp;quot;]);&lt;br /&gt;
    integer total_number = llGetListLength(tokens);&lt;br /&gt;
    integer i;&lt;br /&gt;
    for(i=0; i&amp;lt;total_number; i++)&lt;br /&gt;
    {&lt;br /&gt;
        string token = llList2String(tokens, i);&lt;br /&gt;
        log(&amp;quot;RLV: MLPV2,&amp;quot; + (string) avatar + &amp;quot;,&amp;quot; + token);&lt;br /&gt;
        llSay(RELAY_CHANNEL, llEscapeURL(llGetObjectName())+&amp;quot;,&amp;quot; + (string) avatar + &amp;quot;,&amp;quot; + token);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// find commands for pose and play it for avatars on ball&lt;br /&gt;
rlv(string pose)&lt;br /&gt;
{&lt;br /&gt;
    log(&amp;quot;command for: &amp;quot; + pose);&lt;br /&gt;
    llSetTimerEvent(TIMER_SEC);&lt;br /&gt;
 &lt;br /&gt;
    integer total_number = llGetListLength(poses);&lt;br /&gt;
    integer i;&lt;br /&gt;
    for(i=0; i&amp;lt;total_number; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if (pose == llList2String(poses, i))&lt;br /&gt;
        {&lt;br /&gt;
            string ball = llList2String(balls, i);&lt;br /&gt;
            log(&amp;quot;command for pose: &amp;quot; + pose + &amp;quot; (&amp;quot; + ball + &amp;quot;)&amp;quot;);&lt;br /&gt;
            if (ball == &amp;quot;*&amp;quot;)&lt;br /&gt;
            {&lt;br /&gt;
                integer b;&lt;br /&gt;
                for (b=0; b&amp;lt;6; b++)&lt;br /&gt;
                {&lt;br /&gt;
                    // get avatar for ball index&lt;br /&gt;
                    key avatar = llList2Key(avatars, b);&lt;br /&gt;
                    if(avatar != NULL_KEY) relay(avatar, llList2String(commands, i));&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                key avatar = llList2Key(avatars, (integer) ball);&lt;br /&gt;
                if(avatar != NULL_KEY) relay(avatar, llList2String(commands, i));&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// new find: pose and ball needs to match&lt;br /&gt;
integer find_pose(string pose, string ball)&lt;br /&gt;
{&lt;br /&gt;
    integer total_number = llGetListLength(poses);&lt;br /&gt;
    integer i;&lt;br /&gt;
    for(i=0; i&amp;lt;total_number; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if (pose == llList2String(poses, i) &amp;amp;&amp;amp; ball == llList2String(balls, i))&lt;br /&gt;
        {&lt;br /&gt;
            return i;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return -1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// add a pose/ball/command entry&lt;br /&gt;
add_pose(string pose, string ball, string command)&lt;br /&gt;
{&lt;br /&gt;
    // look for existing entry for pose&lt;br /&gt;
    integer found = find_pose(pose, ball);&lt;br /&gt;
    if (found == -1)&lt;br /&gt;
    {&lt;br /&gt;
        // add a new pose&lt;br /&gt;
        poses += [pose];&lt;br /&gt;
        balls += [ball];&lt;br /&gt;
        commands += [command];&lt;br /&gt;
 &lt;br /&gt;
        log(&amp;quot;Added from &amp;quot; + NOTECARD + &amp;quot;: &amp;quot; + pose + &amp;quot; | &amp;quot; + ball + &amp;quot; | &amp;quot; + command);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        // append to existing pose&lt;br /&gt;
        string c = llList2String(commands, found) + &amp;quot;|&amp;quot; + command;&lt;br /&gt;
        commands = llListReplaceList(commands, [c], found, found);&lt;br /&gt;
 &lt;br /&gt;
        log(&amp;quot;Added &amp;quot; + command + &amp;quot; to pose &amp;quot; + pose);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// parse and store a line&lt;br /&gt;
process_line(string line)&lt;br /&gt;
{&lt;br /&gt;
    list tokens = llParseString2List(line, [&amp;quot;  |  &amp;quot;,&amp;quot;  | &amp;quot;,&amp;quot; |  &amp;quot;,&amp;quot; | &amp;quot;,&amp;quot; |&amp;quot;,&amp;quot;| &amp;quot;,&amp;quot;|&amp;quot;],[&amp;quot;&amp;quot;]);&lt;br /&gt;
    if(llGetListLength(tokens) &amp;lt; 3) return;&lt;br /&gt;
 &lt;br /&gt;
    string pose = llList2String(tokens, 0);&lt;br /&gt;
    string ball = llList2String(tokens, 1);&lt;br /&gt;
 &lt;br /&gt;
    integer total_number = llGetListLength(tokens);&lt;br /&gt;
    integer i;&lt;br /&gt;
    for(i=2; i&amp;lt;total_number; i++)&lt;br /&gt;
    {&lt;br /&gt;
        add_pose(pose, ball, llList2String(tokens, i));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// check if object is in the inventory&lt;br /&gt;
integer exists_notecard(string notecard) {&lt;br /&gt;
    return llGetInventoryType(notecard) == INVENTORY_NOTECARD;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// initialize me&lt;br /&gt;
initialize()&lt;br /&gt;
{&lt;br /&gt;
    log(&amp;quot;Initializing...&amp;quot;);&lt;br /&gt;
    poses = [];&lt;br /&gt;
    balls = [];&lt;br /&gt;
    commands = [];&lt;br /&gt;
    avatars = [NULL_KEY, NULL_KEY, NULL_KEY, NULL_KEY, NULL_KEY, NULL_KEY];&lt;br /&gt;
 &lt;br /&gt;
    if (exists_notecard(NOTECARD))&lt;br /&gt;
    {&lt;br /&gt;
        log(&amp;quot;Reading &amp;quot; + NOTECARD + &amp;quot;...&amp;quot;);&lt;br /&gt;
        iLine = 0;&lt;br /&gt;
        kQuery = llGetNotecardLine(NOTECARD, iLine);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        llOwnerSay(&amp;quot;Not found: &amp;quot; + NOTECARD );&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
upgrade() {string self = llGetScriptName(); string basename = self; if (llSubStringIndex(self, &amp;quot; &amp;quot;) &amp;gt;= 0) {integer start = 2; string tail = llGetSubString(self, llStringLength(self) - start, -1); while (llGetSubString(tail, 0, 0) != &amp;quot; &amp;quot;) {start++; tail = llGetSubString(self, llStringLength(self) - start, -1);} if ((integer)tail &amp;gt; 0) {basename = llGetSubString(self, 0, -llStringLength(tail) - 1);}} integer n = llGetInventoryNumber(INVENTORY_SCRIPT); while (n-- &amp;gt; 0) {string item = llGetInventoryName(INVENTORY_SCRIPT, n); if (item != self &amp;amp;&amp;amp; 0 == llSubStringIndex(item, basename)) {llRemoveInventory(item);}}}&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    // on state entry initialize me&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        upgrade();&lt;br /&gt;
        &lt;br /&gt;
        initialize();&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    // reset on Inventory change&lt;br /&gt;
    changed(integer change)&lt;br /&gt;
    {&lt;br /&gt;
        if (change &amp;amp; CHANGED_INVENTORY) {&lt;br /&gt;
            wants_init=TRUE;&lt;br /&gt;
            llSetTimerEvent (15.0);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    // read a line from notecard&lt;br /&gt;
    dataserver(key _query_id, string _data) {&lt;br /&gt;
        // were we called to work on notecard?&lt;br /&gt;
        if (_query_id == kQuery) {&lt;br /&gt;
            // this is a line of our notecard&lt;br /&gt;
            if (_data == EOF) {&lt;br /&gt;
                if (DEBUG) log_data();&lt;br /&gt;
                log(NOTECARD + &amp;quot; read.&amp;quot;);&lt;br /&gt;
            } else {&lt;br /&gt;
                    // increment line count&lt;br /&gt;
                    // data has the current line from this notecard&lt;br /&gt;
                    if(_data != &amp;quot;&amp;quot;) {&lt;br /&gt;
                        process_line(_data);&lt;br /&gt;
                    }&lt;br /&gt;
 &lt;br /&gt;
                // request next line&lt;br /&gt;
                // read another line when you can&lt;br /&gt;
                iLine++;&lt;br /&gt;
                kQuery = llGetNotecardLine(NOTECARD, iLine);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    timer()&lt;br /&gt;
    {&lt;br /&gt;
        if (wants_init) {&lt;br /&gt;
            wants_init = FALSE;&lt;br /&gt;
              initialize();        &lt;br /&gt;
            llSetTimerEvent (0.0);&lt;br /&gt;
            return;    &lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        integer b;&lt;br /&gt;
        for (b=0; b&amp;lt;6; b++)&lt;br /&gt;
        {&lt;br /&gt;
            // get avatar for ball index&lt;br /&gt;
            key avatar = llList2Key(avatars, b);&lt;br /&gt;
 &lt;br /&gt;
            // if not null send command&lt;br /&gt;
            if(avatar != NULL_KEY) relay(avatar, CMD_RELEASE);&lt;br /&gt;
        }&lt;br /&gt;
        llSetTimerEvent(0.0);&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    // link message from MLPV2&lt;br /&gt;
    link_message(integer sender_number, integer number, string message, key id)&lt;br /&gt;
    {&lt;br /&gt;
        /*&lt;br /&gt;
        // pose from ball menu selected&lt;br /&gt;
        if (number == 0 &amp;amp;&amp;amp; message == &amp;quot;POSEB&amp;quot;) {&lt;br /&gt;
            pose = (string)id;&lt;br /&gt;
            rlv(pose);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        */&lt;br /&gt;
 &lt;br /&gt;
        // direct call from ball menu&lt;br /&gt;
        // configure in .MENUITEMS with&lt;br /&gt;
        // LINKMSG Resctriction | 0,-1,-1819,Restriction&lt;br /&gt;
        if (number == LM_NUMBER) {&lt;br /&gt;
            //llOwnerSay (&amp;quot;RLV: -- &amp;quot;+message);&lt;br /&gt;
            pose = message;&lt;br /&gt;
            rlv(pose);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        // unsit avatar&lt;br /&gt;
        if (number == -11001)&lt;br /&gt;
        {&lt;br /&gt;
            integer ball = (integer) message;&lt;br /&gt;
            log(&amp;quot;Avatar unsit from ball &amp;quot; + (string) ball +&amp;quot;: &amp;quot; + (string) llList2Key(avatars, ball));&lt;br /&gt;
            //relay(llList2Key(avatars, ball), CMD_RELEASE);&lt;br /&gt;
            avatars = llListReplaceList(avatars, [NULL_KEY], ball, ball);&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        // sit avatar&lt;br /&gt;
        if (number == -11000)&lt;br /&gt;
        {&lt;br /&gt;
            list tokens = llParseString2List(message, [&amp;quot;|&amp;quot;], [&amp;quot; &amp;quot;]);&lt;br /&gt;
            integer ball = llList2Integer(tokens, 0);&lt;br /&gt;
            log(&amp;quot;Avatar sit on ball &amp;quot; + (string) ball +&amp;quot;: &amp;quot; + (string) id);&lt;br /&gt;
            avatars = llListReplaceList(avatars, [id], ball, ball);&lt;br /&gt;
            //rlv(pose);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tano Toll</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:Tano_Toll&amp;diff=1167122</id>
		<title>User:Tano Toll</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:Tano_Toll&amp;diff=1167122"/>
		<updated>2012-05-12T03:01:43Z</updated>

		<summary type="html">&lt;p&gt;Tano Toll: Added links&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some of my work for the public domain:&lt;br /&gt;
&lt;br /&gt;
* [[ParcelChatRelay]] - Parcel Chat Relay efficiently allows parcel-wide channel0 talk&lt;br /&gt;
&lt;br /&gt;
* [[Stream_Music_In_PHP]] - Stream a static mp3 stream, synchronized for all listeners, using php&lt;/div&gt;</summary>
		<author><name>Tano Toll</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=ParcelChatRelay&amp;diff=1167121</id>
		<title>ParcelChatRelay</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=ParcelChatRelay&amp;diff=1167121"/>
		<updated>2012-05-12T02:54:26Z</updated>

		<summary type="html">&lt;p&gt;Tano Toll: Parcel Chat Relay - Communications helper script - description&amp;amp;code&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Parcel Chat Relay==&lt;br /&gt;
&lt;br /&gt;
===Description:===&lt;br /&gt;
Communicate on your land in general chat regardless of distance between avatars. Useful when building, in clubs, for roleplay, etc.&lt;br /&gt;
&lt;br /&gt;
Messages will be intelligently relayed - a listener will never hear a message twice! It will either be heard normally, or relayed. Using the new llRegionSayTo() api, chat messages are only relayed to avatars that are out of range.&lt;br /&gt;
&lt;br /&gt;
===How to use:===&lt;br /&gt;
* Rez 1 or more relays on your parcel, in a way that you could hear each avatar (&amp;lt;20m). Do not worry overlapping, but don&#039;t overdo it either - less relays will still be less lag.&lt;br /&gt;
* If you rez a relay on its&#039; final position, it will immediately be &#039;tuned&#039; and part of the network.&lt;br /&gt;
* If you move or remove a relay, it might take up to 10 minutes for the network to catch up.&lt;br /&gt;
&lt;br /&gt;
===Features:===&lt;br /&gt;
* Muliple relays can be rezzed to cover each part of your parcel.&lt;br /&gt;
* Dedoubling without any overhead&lt;br /&gt;
* Low lag - relays do not have to communicate to dedouble messages&lt;br /&gt;
&lt;br /&gt;
===Limitations:===&lt;br /&gt;
* Works only per parcel (by design). Agents on neighboring land will not receive relayed messages.&lt;br /&gt;
* Receivers have to be within radar range (96m) of the receiving relay&lt;br /&gt;
* Scripts cannot distinguish normal say, whispering and shouting. Normal say is assumed. Shouts may be heard double by the receiver&lt;br /&gt;
* Moving avatars might experience &#039;border&#039; cases - where a message sometimes accidentally is not relayed or double relayed. Due to the fast response time unlikely&lt;br /&gt;
* The displayed (&#039;faked&#039;) name is the official linden name, and chat is colored like objects, not avatars. Also depends on viewer settings.&lt;br /&gt;
Remarks on the parcel limitation.. Other options (sim wide, range based) would be easily possible, but i like the item to be zero-config (&#039;just works&#039;). Feel free to mod the script at your demands.&lt;br /&gt;
&lt;br /&gt;
===License:===&lt;br /&gt;
Modified BSD / public domain&lt;br /&gt;
&lt;br /&gt;
This script is also available at marketplace for your convenience: https://marketplace.secondlife.com/p/Parcel-Chat-Relay/3157725&lt;br /&gt;
&lt;br /&gt;
===Notes:===&lt;br /&gt;
Possible easy-to-adjust modifications: do not use parcel key but owner key as handle, allowing cross parcel-but-same-owner chat, or specifying a fixed key for region-wide that.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
//2011-2012 Tano Toll - TSL License//&lt;br /&gt;
&lt;br /&gt;
//Short summorization:&lt;br /&gt;
//Relays will know of eachothers existance&lt;br /&gt;
//Relays listen to public chat&lt;br /&gt;
//The relay _closest_ to sending agent is responsible for relaying the message&lt;br /&gt;
//Messages will only be relayed to agents further than 20 meter away from the speaker&lt;br /&gt;
//Messages will only be relayed to agents on the same parcel&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//list of detected nearby agents:&lt;br /&gt;
list insim;&lt;br /&gt;
&lt;br /&gt;
//just a hash. change to use several systems on a single parcel.&lt;br /&gt;
string tag=&amp;quot;+-/&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//key of the parcel where we are rezzed&lt;br /&gt;
key parcelkey;&lt;br /&gt;
&lt;br /&gt;
//chat channel handle made with key as base&lt;br /&gt;
integer parcelhandle;&lt;br /&gt;
&lt;br /&gt;
//list of detected nearby relays&lt;br /&gt;
list repeaters;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
announce() {&lt;br /&gt;
    llRegionSay (parcelhandle, tag+(string)parcelkey);   &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llSetText(&amp;quot;Chat Relay started...&amp;quot;,ZERO_VECTOR,1);&lt;br /&gt;
        if (llGetAttached()) {&lt;br /&gt;
            //owner relay only mode&lt;br /&gt;
            //redundant in this script.&lt;br /&gt;
            //llListen (0, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
        } else {&lt;br /&gt;
            //relay all agents&lt;br /&gt;
            llListen (0, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;);   &lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        //scan for nearby agents&lt;br /&gt;
        llSensorRepeat (&amp;quot;&amp;quot;, &amp;quot;&amp;quot;, AGENT, 65, TWO_PI, 20);&lt;br /&gt;
        &lt;br /&gt;
        //make up a inter-relay channel, so they can find eachother&lt;br /&gt;
        parcelkey=llList2Key(llGetParcelDetails(llGetPos(), [PARCEL_DETAILS_ID]),0);&lt;br /&gt;
        parcelhandle=-10909-(integer)(&amp;quot;0x&amp;quot;+llGetSubString(parcelkey,1,5));&lt;br /&gt;
        llListen(parcelhandle, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, tag+(string)parcelkey);&lt;br /&gt;
        &lt;br /&gt;
        //broadcast our existance about every 5 minutes&lt;br /&gt;
        llSetTimerEvent(290.0+llFrand (20.0)); //about each 300 seconds, not all at once&lt;br /&gt;
        announce();&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    on_rez(integer n) {&lt;br /&gt;
        //simply reset&lt;br /&gt;
        llResetScript();   &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    timer() {        &lt;br /&gt;
        //announce self&lt;br /&gt;
        announce();&lt;br /&gt;
        &lt;br /&gt;
        //and clear list. repeaters with an too old timestamp will be removed.&lt;br /&gt;
        integer n=llGetListLength(repeaters)-1;&lt;br /&gt;
        integer t=llGetUnixTime();&lt;br /&gt;
        while (n&amp;gt;0) {&lt;br /&gt;
            if ((t-llList2Integer(repeaters, n))&amp;gt;390) { //time out&lt;br /&gt;
                repeaters=llDeleteSubList(repeaters, n-2, n);&lt;br /&gt;
            }&lt;br /&gt;
            n-=3;&lt;br /&gt;
        }   &lt;br /&gt;
        llSetText (&amp;quot;Node(s): &amp;quot;+(string)(1+llGetListLength(repeaters)/3), &amp;lt;1,1,1&amp;gt;, 1);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    sensor (integer n) {&lt;br /&gt;
        //add detected agents to our list&lt;br /&gt;
        while (~--n) {&lt;br /&gt;
            key id=llDetectedKey(n);&lt;br /&gt;
            if (!~llListFindList(insim, [id]))&lt;br /&gt;
                insim+=id;    &lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        //clean up agents that are no longer in sim&lt;br /&gt;
        n=llGetListLength(insim);&lt;br /&gt;
        while (~--n)&lt;br /&gt;
            if (llGetAgentSize(llList2Key(insim,n))); else&lt;br /&gt;
                insim=llDeleteSubList(insim,n,n);   &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    no_sensor() {&lt;br /&gt;
        insim=[];&lt;br /&gt;
        /*&lt;br /&gt;
        //clean up agents that are no longer in sim&lt;br /&gt;
        integer n=llGetListLength(insim);&lt;br /&gt;
        while (~--n)&lt;br /&gt;
            if (llGetAgentSize(llList2Key(insim,n))); else&lt;br /&gt;
                insim=llDeleteSubList(insim,n,n);   &lt;br /&gt;
        */&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    listen (integer channel, string name, key id, string m) {&lt;br /&gt;
        &lt;br /&gt;
        &lt;br /&gt;
        if (!channel) { //channel 0&lt;br /&gt;
            //only relay agents, not objects&lt;br /&gt;
            if (llGetAgentSize(id));else&lt;br /&gt;
                return;&lt;br /&gt;
                &lt;br /&gt;
            //see if another relay is more nearby&lt;br /&gt;
            integer n=0;&lt;br /&gt;
            vector senderpos=llList2Vector(llGetObjectDetails(id, [OBJECT_POS]), 0);&lt;br /&gt;
            float d=llVecDist(senderpos, llGetPos());            &lt;br /&gt;
            while (n&amp;lt;llGetListLength(repeaters)) {&lt;br /&gt;
                if (d&amp;gt;llVecDist(senderpos, llList2Vector(repeaters, n+1)))&lt;br /&gt;
                    return;&lt;br /&gt;
                n+=3;&lt;br /&gt;
            }&lt;br /&gt;
            //We are nearest repeater. Our job to relay.&lt;br /&gt;
            &lt;br /&gt;
            //relay to everyone in range. that&#039;s fixed to minimum 20 mins maximum 60.&lt;br /&gt;
            //get position of chatter&lt;br /&gt;
            vector o=llList2Vector(llGetObjectDetails(id, [OBJECT_POS]), 0);&lt;br /&gt;
        &lt;br /&gt;
            n=llGetListLength(insim);&lt;br /&gt;
            string oname=llGetObjectName();&lt;br /&gt;
            llSetObjectName(name);&lt;br /&gt;
            while (~--n) {&lt;br /&gt;
                vector t=llList2Vector(llGetObjectDetails(llList2Key(insim, n), [OBJECT_POS]), 0);        &lt;br /&gt;
                float d=llVecDist (o,t);&lt;br /&gt;
                if (d&amp;gt;=20/* &amp;amp;&amp;amp; d&amp;lt;=60*/) {&lt;br /&gt;
                    //same parcel?&lt;br /&gt;
                    if (parcelkey==llList2Key(llGetParcelDetails(llList2Vector(llGetObjectDetails(llList2Key(insim,n), [OBJECT_POS]),0), [PARCEL_DETAILS_ID]),0))&lt;br /&gt;
                        llRegionSayTo (llList2Key(insim,n), 0, m);   &lt;br /&gt;
                }&lt;br /&gt;
            }       &lt;br /&gt;
            llSetObjectName(oname);&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        if (channel==parcelhandle) {&lt;br /&gt;
            //there&#039;s another repeater..&lt;br /&gt;
            vector pos=llList2Vector(llGetObjectDetails(id, [OBJECT_POS]),0);&lt;br /&gt;
            &lt;br /&gt;
            integer p=llListFindList(repeaters, [id, pos]);&lt;br /&gt;
            if (~p)&lt;br /&gt;
                repeaters=llDeleteSubList(repeaters, p, p+2);&lt;br /&gt;
            repeaters += [id, pos, llGetUnixTime()];&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
--[[User:Tano Toll|Tano Toll]] 19:54, 11 May 2012 (PDT)&lt;/div&gt;</summary>
		<author><name>Tano Toll</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:Tano_Toll&amp;diff=1167119</id>
		<title>User:Tano Toll</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:Tano_Toll&amp;diff=1167119"/>
		<updated>2012-05-12T02:46:01Z</updated>

		<summary type="html">&lt;p&gt;Tano Toll: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some of my work for the public domain:&lt;br /&gt;
&lt;br /&gt;
* [[ParcelChatRelay]] - Parcel Chat Relay efficiently allows parcel-wide channel0 talk&lt;/div&gt;</summary>
		<author><name>Tano Toll</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:Tano_Toll&amp;diff=1167118</id>
		<title>User:Tano Toll</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:Tano_Toll&amp;diff=1167118"/>
		<updated>2012-05-12T02:45:41Z</updated>

		<summary type="html">&lt;p&gt;Tano Toll: Created page with &amp;quot;Some of my work for the public domain:  * ParcelChatRelay - Parcel Chat Relay efficiently allows parcel-wide channel0 talk&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some of my work for the public domain:&lt;br /&gt;
&lt;br /&gt;
* ParcelChatRelay - Parcel Chat Relay efficiently allows parcel-wide channel0 talk&lt;/div&gt;</summary>
		<author><name>Tano Toll</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Stream_Music_In_PHP&amp;diff=1155838</id>
		<title>Stream Music In PHP</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Stream_Music_In_PHP&amp;diff=1155838"/>
		<updated>2011-10-17T12:54:39Z</updated>

		<summary type="html">&lt;p&gt;Tano Toll: typo and extra warning&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Various residents host their own music for the parcel. Quite often, this is just a big MP3 file. The issues of hosting such big MP3 are, that the viewer will download the file &#039;as-is&#039;. While this is no issue for short files (a few megabyte), it is when the podcast is several hours in length.&lt;br /&gt;
&lt;br /&gt;
To be able to stream my own parcel music, without the use of (commercial/difficult to setup/) streamers like icecast, i written a simple PHP script that streams a huge mp3 file. It performs some extra tricks to make the listening experience glitch-free for SL viewers. This very script has been tested for quite a while, and it does just what it needs to do: host hassle free music for my parcel.&lt;br /&gt;
&lt;br /&gt;
You will need to prepare your own podcast / mp3 stream, as a single file. This script will not serve a playlist, it will just endlessly loop a big MP3 file, whilst synchronizing listeners. Make sure you have appropiate bandwith. Also, usage is only recommended for the more experienced web server admins, if you do not know what &#039;LAMP&#039; means, have no scripting experience, or have no root access to the server you are hosting this on (in case of a malfunction), please refrain from using this code.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;?&lt;br /&gt;
 //GPL3&lt;br /&gt;
 &lt;br /&gt;
 //MP3 STREAMING FROM PHP&lt;br /&gt;
 //This script streams a big MP3 file at an appropiate speed&lt;br /&gt;
 //Also, it will synchronize several listeners to the same position in the mp3&lt;br /&gt;
 &lt;br /&gt;
 //Quick usage: Edit the 3 variables below in the &#039;settings&#039; section, host this script together with a big MP3 on a lamp server.&lt;br /&gt;
 &lt;br /&gt;
 //This script was optimized for Second Life music streaming, issues dodged:&lt;br /&gt;
 //* The mp3 is actively streamed, instead of sent as a whole file at once&lt;br /&gt;
 //* Listeners are synchronized, so they actually will hear the same song whilst being on the same parcel&lt;br /&gt;
 //* MP3 is nicely (instead of arbitrary) split in chunks to dodge &#039;skipping&#039; errors that SL viewers tend to behave&lt;br /&gt;
 //* Insignificant server load(** up to a reasonable amount of viewers, say, &amp;lt;20)&lt;br /&gt;
 //* Tested for over a year for proper functioning without raising issues&lt;br /&gt;
 &lt;br /&gt;
 //Limitations&lt;br /&gt;
 //Requires an MPEG1 LAYER III file as input (the most common MP3 format)&lt;br /&gt;
 //Assumes a single big file (&#039;&#039;podcast&#039;&#039;). This script was not made to stream a playlist.&lt;br /&gt;
 //The file should be properly encoded to avoid issues with the SL player:&lt;br /&gt;
 //* VBR _might_ work but is not recommended due to the viewers&#039; real-time broadcast skipping&lt;br /&gt;
 //* If the encoder supports &#039;bit buckets&#039; - make sure they are disabled as they are incompatible with SL&#039;s player(**)&lt;br /&gt;
 //(**) When streaming &#039;live&#039; - SL player seems to understand if the whole file was downloaded instead of streamed.&lt;br /&gt;
 //The resolution of the synchronisation is not precise, though generally &amp;lt;1 second. As listeners join, slight offsets might accumulate&lt;br /&gt;
 //This script is ment as example how to stream using proper timekeeping and chunking.&lt;br /&gt;
 //It is missing features as streaming multiple files from a directory, though such behaviour is easily customized.&lt;br /&gt;
 &lt;br /&gt;
 //Feature, not bug&lt;br /&gt;
 //With zero listeners, the stream will not progress, instead it&#039;ll &#039;wait&#039; at current position untill at least 1 listener joins&lt;br /&gt;
 &lt;br /&gt;
 //Issues:&lt;br /&gt;
 //If the mp3 exists but has zero length, the script may end in an endless loop eating 100% cpu time. please fix.&lt;br /&gt;
 &lt;br /&gt;
 //Requirements:&lt;br /&gt;
 //LAP(Linux, Apache, PHP) configuration&lt;br /&gt;
 //(WAP(Windows) may work but untested, potentional issues revolve around microtime(), fastcgi and locked temporary files).&lt;br /&gt;
 //PHP configuration that allows overriding script run time to infinite&lt;br /&gt;
 //Writeable TMP directory&lt;br /&gt;
 //Properly created MP3 stream (&#039;&#039;podcast&#039;&#039;), preferably several hours in length:&lt;br /&gt;
 // * Simply concatting files may work for testing but is not recommended and may lead to audible glitches&lt;br /&gt;
 // * The prefered way is to either: stream your playlist with an audio player like winamp, then output the stream as .mp3&lt;br /&gt;
 // * Or use an editor (like audacity) to create your podcast, output as single file&lt;br /&gt;
 // * Any other means or software to create a podcast&lt;br /&gt;
 //The intention of this script is to generate a glitch-free audio experience, using no more bandwidth than required&lt;br /&gt;
 &lt;br /&gt;
 //CHANGE HISTORY&lt;br /&gt;
 //0.01 - initial version&lt;br /&gt;
 //0.02 - removed dependancy from external mp3 header library. please set bitrate manually. auto-detect wasn&#039;t reliable anyways&lt;br /&gt;
 //0.03 - documented some more and cleaned up code a tiny bit. might release it as GPL&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 //settings, please fill this variables with your own&lt;br /&gt;
 $mp3=&amp;quot;bigstreamfile.mp3&amp;quot;;&lt;br /&gt;
 $bitrate=128;&lt;br /&gt;
 &lt;br /&gt;
 //adjust for your system. use a unique lock file for each mp3 you serve.&lt;br /&gt;
 //$tmp=&amp;quot;/tmp/${mp3}.posinfo&amp;quot;;&lt;br /&gt;
 $tmp=&amp;quot;/tmp/stream1pos&amp;quot;; &lt;br /&gt;
 &lt;br /&gt;
 //Enable debug to get textual output in a browser. The stream is not listenable with debug enabled.&lt;br /&gt;
 $debug=0; //false; //true;&lt;br /&gt;
 &lt;br /&gt;
 //disable error reporting if you like&lt;br /&gt;
 error_reporting (E_ALL);&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 // NO EDITING REQUIRED BELOW THIS LINE, EDIT AT OWN RESPONSABILITY //&lt;br /&gt;
 &lt;br /&gt;
 //SUPPORT FUNCTIONS&lt;br /&gt;
 function writePos() {&lt;br /&gt;
     global $h, $timekeeper;&lt;br /&gt;
     $fff=fopen ($tmp, &amp;quot;w&amp;quot;);&lt;br /&gt;
     fputs ($fff, &amp;quot;&amp;quot;.ftell ($h).&amp;quot;\n&amp;quot;);&lt;br /&gt;
     fputs ($fff, $timekeeper.&amp;quot;\n&amp;quot;);&lt;br /&gt;
     fclose ($fff);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 //global $buffcache;&lt;br /&gt;
 &lt;br /&gt;
 function sendBuff($bff) {&lt;br /&gt;
     print $bff;&lt;br /&gt;
     flush();&lt;br /&gt;
     return;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 function readBuffs($fh) {&lt;br /&gt;
     $b=&amp;quot;&amp;quot;;&lt;br /&gt;
     for ($i = 0; $i&amp;lt;22; $i++) {&lt;br /&gt;
   $b.=readBuff($fh);&lt;br /&gt;
     } &lt;br /&gt;
     return $b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 function readBuff($fh) {&lt;br /&gt;
     global $framesize;&lt;br /&gt;
     //read from file untill we receive a $FF marker&lt;br /&gt;
     $m=&amp;quot;&amp;quot;;&lt;br /&gt;
     do {&lt;br /&gt;
   $m=fread($fh, 4);&lt;br /&gt;
   if (feof($fh))&lt;br /&gt;
    return &amp;quot;&amp;quot;;&lt;br /&gt;
   //requiring mpeg1 layer 3. Adjust for other containers / chunkmarkers / right here&lt;br /&gt;
   } while (($m[0]!=chr(255)) || !(($m[1]==chr(250)) || ($m[1]==chr(251))) );&lt;br /&gt;
     $bl=$framesize-4;&lt;br /&gt;
     if (ord($m[2]) &amp;amp; 2) //padding&lt;br /&gt;
  $bl++;&lt;br /&gt;
     $m.=fread ($fh, $bl);&lt;br /&gt;
     return $m;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 //`main()`&lt;br /&gt;
   &lt;br /&gt;
  $file=$mp3;&lt;br /&gt;
  if (!file_exists($file))&lt;br /&gt;
   die();&lt;br /&gt;
  $framesize=floor (144000.0 * $bitrate / 44100);&lt;br /&gt;
  $blocksize=16384;&lt;br /&gt;
  $playspeed=1000.0 * $bitrate / 8.0;&lt;br /&gt;
  $sleeptime = (1.0 * $blocksize / ($playspeed));&lt;br /&gt;
     &lt;br /&gt;
  if ($debug)&lt;br /&gt;
      header (&amp;quot;Content-Type: text/plain&amp;quot;);&lt;br /&gt;
  else {&lt;br /&gt;
      header (&amp;quot;Content-Type: audio/mpeg&amp;quot;);&lt;br /&gt;
      header (&amp;quot;Content-Transfer-Encoding: binary&amp;quot;);&lt;br /&gt;
      header (&amp;quot;Pragma: no-cache&amp;quot;);&lt;br /&gt;
      header (&amp;quot;icy-br: &amp;quot;.$bitrate);&lt;br /&gt;
  }&lt;br /&gt;
   &lt;br /&gt;
  //request unlimited runtime&lt;br /&gt;
  set_time_limit(0);&lt;br /&gt;
  if ($debug)&lt;br /&gt;
      print (&amp;quot;framesize: &amp;quot;.$framesize);&lt;br /&gt;
    &lt;br /&gt;
  $h=fopen($file, &amp;quot;rb&amp;quot;);&lt;br /&gt;
    &lt;br /&gt;
  if (file_exists ($tmp)) {&lt;br /&gt;
      //read our position from file.&lt;br /&gt;
      $ff=fopen ($tmp, &amp;quot;r&amp;quot;);&lt;br /&gt;
      $position=fgets($ff);&lt;br /&gt;
      $postime=fgets($ff);&lt;br /&gt;
      fclose ($ff);&lt;br /&gt;
  }&lt;br /&gt;
    &lt;br /&gt;
  //increase position by elapsed time for syncing listeners.&lt;br /&gt;
  if ($postime) {&lt;br /&gt;
      $elapsed = microtime(true)-$postime;&lt;br /&gt;
      //we force to float to bypass a 32 bit integer limit&lt;br /&gt;
      //looping for multiple days if needed (its not an issue)&lt;br /&gt;
      $position += 1.0 * $elapsed * ($bitrate / 8);&lt;br /&gt;
      $fs=filesize($file);&lt;br /&gt;
      while ($position&amp;gt;$fs) {&lt;br /&gt;
   $position-=$fs;&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
  fseek ($h, $position);&lt;br /&gt;
  //send a reasonable buffer to start&lt;br /&gt;
  for ($j=0; $j&amp;lt;3; $j++) {&lt;br /&gt;
          $buff=readBuffs($h).readBuffs($h).readBuffs($h);&lt;br /&gt;
      print $buff;&lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
  $buff=readBuffs($h);&lt;br /&gt;
  $timekeeper=microtime(true);&lt;br /&gt;
  $counter=0;&lt;br /&gt;
   &lt;br /&gt;
  //main loop:&lt;br /&gt;
  while (($buff!=&amp;quot;&amp;quot;) &amp;amp;&amp;amp;  !connection_aborted()) {&lt;br /&gt;
   if ($debug) {&lt;br /&gt;
       echo &amp;quot;Buff size: &amp;quot;.strlen($buff).&amp;quot; first chars: &amp;quot;.ord($buff[0]).&amp;quot; &amp;quot;.ord($buff[1]).&amp;quot; &amp;quot;.ord($buff[2]).&amp;quot; &amp;quot;.ord($buff[3]).&amp;quot; file pointer &amp;quot;.ftell($h).&amp;quot;\n&amp;quot;;&lt;br /&gt;
   } else&lt;br /&gt;
       echo ($buff);&lt;br /&gt;
   flush();&lt;br /&gt;
   $counter++;&lt;br /&gt;
   if (!($counter%30))&lt;br /&gt;
       writePos();&lt;br /&gt;
   $bwl=strlen($buff);&lt;br /&gt;
   $buff=readBuffs($h);&lt;br /&gt;
   if ($buff==&amp;quot;&amp;quot;) {&lt;br /&gt;
       fseek ($h, 0);&lt;br /&gt;
       $buff=readBuff($h);&lt;br /&gt;
   }&lt;br /&gt;
   $timekeeper=$timekeeper+1.0*$bwl/$playspeed;&lt;br /&gt;
   time_sleep_until($timekeeper);   &lt;br /&gt;
  }&lt;br /&gt;
   &lt;br /&gt;
  writePos();&lt;br /&gt;
  fclose($h);&lt;br /&gt;
 &lt;br /&gt;
 ?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[User:Tano Toll|Tano Toll]] 06:05, 15 October 2011 (PDT)&lt;/div&gt;</summary>
		<author><name>Tano Toll</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Stream_Music_In_PHP&amp;diff=1155806</id>
		<title>Stream Music In PHP</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Stream_Music_In_PHP&amp;diff=1155806"/>
		<updated>2011-10-15T13:05:17Z</updated>

		<summary type="html">&lt;p&gt;Tano Toll: Streaming parcel music with simple php script&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Various residents host their own music for the parcel. Quite often, this is just a big MP3 file. The issues of hosting such big MP3 are, that the viewer will download the file &#039;as-is&#039;. While this is no issue for short files (a few megabyte), it is when the podcast is several hours in length.&lt;br /&gt;
&lt;br /&gt;
To be able to stream my own parcel music, without the use of (commercial/difficult to setup/) streamers like icecast, i written a simple PHP script that streams a huge mp3 file. It performs some extra tricks to make the listening experience glitch-free for SL viewers. This very script has been tested for quite a while, and it does just what it needs to do: host hassle free music for my parcel.&lt;br /&gt;
&lt;br /&gt;
You will need to prepare your own podcast / mp3 stream, as a single file. This script will not serve a playlist, it will just endlessly loop a big MP3 file, whilst synchronizing listeners. Make sure you have appropiate bandwith. Also, usage is only recommended for the more experienced web server admins, if you do not know what &#039;LAMP&#039; means, please refrain from using this code.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;?&lt;br /&gt;
 //GPL3&lt;br /&gt;
 &lt;br /&gt;
 //MP3 STREAMING FROM PHP&lt;br /&gt;
 //This script streams a big MP3 file at an appropiate speed&lt;br /&gt;
 //Also, it will synchronize several listeners to the same position in the mp3&lt;br /&gt;
 &lt;br /&gt;
 //Quick usage: Edit the 3 variables below in the &#039;settings&#039; section, host this script together with a big MP3 on a lamp server.&lt;br /&gt;
 &lt;br /&gt;
 //This script was optimized for Second Life music streaming, issues dodged:&lt;br /&gt;
 //* The mp3 is actively streamed, instead of sent as a whole file at once&lt;br /&gt;
 //* Listeners are synchronized, so they actually will hear the same song whilst being on the same parcel&lt;br /&gt;
 //* MP3 is nicely (instead of arbitrary) split in chunks to dodge &#039;skipping&#039; errors that SL viewers tend to behave&lt;br /&gt;
 //* Insignificant server load(** up to a reasonable amount of viewers, say, &amp;lt;20)&lt;br /&gt;
 //* Tested for over a year for proper functioning without raising issues&lt;br /&gt;
 &lt;br /&gt;
 //Limitations&lt;br /&gt;
 //Requires an MPEG1 LAYER III file as input (the most common MP3 format)&lt;br /&gt;
 //Assumes a single big file (&#039;&#039;podcast&#039;&#039;). This script was not made to stream a playlist.&lt;br /&gt;
 //The file should be properly encoded to avoid issues with the SL player:&lt;br /&gt;
 //* VBR _might_ work but is not recommended due to the viewers&#039; real-time broadcast skipping&lt;br /&gt;
 //* If the encoder supports &#039;bit buckets&#039; - make sure they are enabled as they are incompatible with SL&#039;s player(**)&lt;br /&gt;
 //(**) When streaming &#039;live&#039; - SL player seems to understand if the whole file was downloaded instead of streamed.&lt;br /&gt;
 //The resolution of the synchronisation is not precise, though generally &amp;lt;1 second. As listeners join, slight offsets might accumulate&lt;br /&gt;
 //This script is ment as example how to stream using proper timekeeping and chunking.&lt;br /&gt;
 //It is missing features as streaming multiple files from a directory, though such behaviour is easily customized.&lt;br /&gt;
 &lt;br /&gt;
 //Feature, not bug&lt;br /&gt;
 //With zero listeners, the stream will not progress, instead it&#039;ll &#039;wait&#039; at current position untill at least 1 listener joins&lt;br /&gt;
 &lt;br /&gt;
 //Issues:&lt;br /&gt;
 //If the mp3 exists but has zero length, the script may end in an endless loop eating 100% cpu time. please fix.&lt;br /&gt;
 &lt;br /&gt;
 //Requirements:&lt;br /&gt;
 //LAP(Linux, Apache, PHP) configuration&lt;br /&gt;
 //(WAP(Windows) may work but untested, potentional issues revolve around microtime(), fastcgi and locked temporary files).&lt;br /&gt;
 //PHP configuration that allows overriding script run time to infinite&lt;br /&gt;
 //Writeable TMP directory&lt;br /&gt;
 //Properly created MP3 stream (&#039;&#039;podcast&#039;&#039;), preferably several hours in length:&lt;br /&gt;
 // * Simply concatting files may work for testing but is not recommended and may lead to audible glitches&lt;br /&gt;
 // * The prefered way is to either: stream your playlist with an audio player like winamp, then output the stream as .mp3&lt;br /&gt;
 // * Or use an editor (like audacity) to create your podcast, output as single file&lt;br /&gt;
 // * Any other means or software to create a podcast&lt;br /&gt;
 //The intention of this script is to generate a glitch-free audio experience, using no more bandwidth than required&lt;br /&gt;
 &lt;br /&gt;
 //CHANGE HISTORY&lt;br /&gt;
 //0.01 - initial version&lt;br /&gt;
 //0.02 - removed dependancy from external mp3 header library. please set bitrate manually. auto-detect wasn&#039;t reliable anyways&lt;br /&gt;
 //0.03 - documented some more and cleaned up code a tiny bit. might release it as GPL&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 //settings, please fill this variables with your own&lt;br /&gt;
 $mp3=&amp;quot;bigstreamfile.mp3&amp;quot;;&lt;br /&gt;
 $bitrate=128;&lt;br /&gt;
 &lt;br /&gt;
 //adjust for your system. use a unique lock file for each mp3 you serve.&lt;br /&gt;
 //$tmp=&amp;quot;/tmp/${mp3}.posinfo&amp;quot;;&lt;br /&gt;
 $tmp=&amp;quot;/tmp/stream1pos&amp;quot;; &lt;br /&gt;
 &lt;br /&gt;
 //Enable debug to get textual output in a browser. The stream is not listenable with debug enabled.&lt;br /&gt;
 $debug=0; //false; //true;&lt;br /&gt;
 &lt;br /&gt;
 //disable error reporting if you like&lt;br /&gt;
 error_reporting (E_ALL);&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 // NO EDITING REQUIRED BELOW THIS LINE, EDIT AT OWN RESPONSABILITY //&lt;br /&gt;
 &lt;br /&gt;
 //SUPPORT FUNCTIONS&lt;br /&gt;
 function writePos() {&lt;br /&gt;
     global $h, $timekeeper;&lt;br /&gt;
     $fff=fopen ($tmp, &amp;quot;w&amp;quot;);&lt;br /&gt;
     fputs ($fff, &amp;quot;&amp;quot;.ftell ($h).&amp;quot;\n&amp;quot;);&lt;br /&gt;
     fputs ($fff, $timekeeper.&amp;quot;\n&amp;quot;);&lt;br /&gt;
     fclose ($fff);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 //global $buffcache;&lt;br /&gt;
 &lt;br /&gt;
 function sendBuff($bff) {&lt;br /&gt;
     print $bff;&lt;br /&gt;
     flush();&lt;br /&gt;
     return;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 function readBuffs($fh) {&lt;br /&gt;
     $b=&amp;quot;&amp;quot;;&lt;br /&gt;
     for ($i = 0; $i&amp;lt;22; $i++) {&lt;br /&gt;
   $b.=readBuff($fh);&lt;br /&gt;
     } &lt;br /&gt;
     return $b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 function readBuff($fh) {&lt;br /&gt;
     global $framesize;&lt;br /&gt;
     //read from file untill we receive a $FF marker&lt;br /&gt;
     $m=&amp;quot;&amp;quot;;&lt;br /&gt;
     do {&lt;br /&gt;
   $m=fread($fh, 4);&lt;br /&gt;
   if (feof($fh))&lt;br /&gt;
    return &amp;quot;&amp;quot;;&lt;br /&gt;
   //requiring mpeg1 layer 3. Adjust for other containers / chunkmarkers / right here&lt;br /&gt;
   } while (($m[0]!=chr(255)) || !(($m[1]==chr(250)) || ($m[1]==chr(251))) );&lt;br /&gt;
     $bl=$framesize-4;&lt;br /&gt;
     if (ord($m[2]) &amp;amp; 2) //padding&lt;br /&gt;
  $bl++;&lt;br /&gt;
     $m.=fread ($fh, $bl);&lt;br /&gt;
     return $m;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 //`main()`&lt;br /&gt;
   &lt;br /&gt;
  $file=$mp3;&lt;br /&gt;
  if (!file_exists($file))&lt;br /&gt;
   die();&lt;br /&gt;
  $framesize=floor (144000.0 * $bitrate / 44100);&lt;br /&gt;
  $blocksize=16384;&lt;br /&gt;
  $playspeed=1000.0 * $bitrate / 8.0;&lt;br /&gt;
  $sleeptime = (1.0 * $blocksize / ($playspeed));&lt;br /&gt;
     &lt;br /&gt;
  if ($debug)&lt;br /&gt;
      header (&amp;quot;Content-Type: text/plain&amp;quot;);&lt;br /&gt;
  else {&lt;br /&gt;
      header (&amp;quot;Content-Type: audio/mpeg&amp;quot;);&lt;br /&gt;
      header (&amp;quot;Content-Transfer-Encoding: binary&amp;quot;);&lt;br /&gt;
      header (&amp;quot;Pragma: no-cache&amp;quot;);&lt;br /&gt;
      header (&amp;quot;icy-br: &amp;quot;.$bitrate);&lt;br /&gt;
  }&lt;br /&gt;
   &lt;br /&gt;
  //request unlimited runtime&lt;br /&gt;
  set_time_limit(0);&lt;br /&gt;
  if ($debug)&lt;br /&gt;
      print (&amp;quot;framesize: &amp;quot;.$framesize);&lt;br /&gt;
    &lt;br /&gt;
  $h=fopen($file, &amp;quot;rb&amp;quot;);&lt;br /&gt;
    &lt;br /&gt;
  if (file_exists ($tmp)) {&lt;br /&gt;
      //read our position from file.&lt;br /&gt;
      $ff=fopen ($tmp, &amp;quot;r&amp;quot;);&lt;br /&gt;
      $position=fgets($ff);&lt;br /&gt;
      $postime=fgets($ff);&lt;br /&gt;
      fclose ($ff);&lt;br /&gt;
  }&lt;br /&gt;
    &lt;br /&gt;
  //increase position by elapsed time for syncing listeners.&lt;br /&gt;
  if ($postime) {&lt;br /&gt;
      $elapsed = microtime(true)-$postime;&lt;br /&gt;
      //we force to float to bypass a 32 bit integer limit&lt;br /&gt;
      //looping for multiple days if needed (its not an issue)&lt;br /&gt;
      $position += 1.0 * $elapsed * ($bitrate / 8);&lt;br /&gt;
      $fs=filesize($file);&lt;br /&gt;
      while ($position&amp;gt;$fs) {&lt;br /&gt;
   $position-=$fs;&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
  fseek ($h, $position);&lt;br /&gt;
  //send a reasonable buffer to start&lt;br /&gt;
  for ($j=0; $j&amp;lt;3; $j++) {&lt;br /&gt;
          $buff=readBuffs($h).readBuffs($h).readBuffs($h);&lt;br /&gt;
      print $buff;&lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
  $buff=readBuffs($h);&lt;br /&gt;
  $timekeeper=microtime(true);&lt;br /&gt;
  $counter=0;&lt;br /&gt;
   &lt;br /&gt;
  //main loop:&lt;br /&gt;
  while (($buff!=&amp;quot;&amp;quot;) &amp;amp;&amp;amp;  !connection_aborted()) {&lt;br /&gt;
   if ($debug) {&lt;br /&gt;
       echo &amp;quot;Buff size: &amp;quot;.strlen($buff).&amp;quot; first chars: &amp;quot;.ord($buff[0]).&amp;quot; &amp;quot;.ord($buff[1]).&amp;quot; &amp;quot;.ord($buff[2]).&amp;quot; &amp;quot;.ord($buff[3]).&amp;quot; file pointer &amp;quot;.ftell($h).&amp;quot;\n&amp;quot;;&lt;br /&gt;
   } else&lt;br /&gt;
       echo ($buff);&lt;br /&gt;
   flush();&lt;br /&gt;
   $counter++;&lt;br /&gt;
   if (!($counter%30))&lt;br /&gt;
       writePos();&lt;br /&gt;
   $bwl=strlen($buff);&lt;br /&gt;
   $buff=readBuffs($h);&lt;br /&gt;
   if ($buff==&amp;quot;&amp;quot;) {&lt;br /&gt;
       fseek ($h, 0);&lt;br /&gt;
       $buff=readBuff($h);&lt;br /&gt;
   }&lt;br /&gt;
   $timekeeper=$timekeeper+1.0*$bwl/$playspeed;&lt;br /&gt;
   time_sleep_until($timekeeper);   &lt;br /&gt;
  }&lt;br /&gt;
   &lt;br /&gt;
  writePos();&lt;br /&gt;
  fclose($h);&lt;br /&gt;
 &lt;br /&gt;
 ?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[User:Tano Toll|Tano Toll]] 06:05, 15 October 2011 (PDT)&lt;/div&gt;</summary>
		<author><name>Tano Toll</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=String_Compare&amp;diff=603963</id>
		<title>String Compare</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=String_Compare&amp;diff=603963"/>
		<updated>2009-10-17T11:51:25Z</updated>

		<summary type="html">&lt;p&gt;Tano Toll: /* Notes: */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{LSL Header}}&lt;br /&gt;
=== String compare ===&lt;br /&gt;
Created by [[User:Xaviar Czervik|Xaviar Czervik]]. Do whatever you wish with this function: Sell it (good luck), use it, or modify it.&lt;br /&gt;
&lt;br /&gt;
The following code returns 1, -1 or 0. The 1 and -1 are essentially random, however it will return the same value every time the script is executed. 0 Is returned when, and only when, the strings are exactly equal. Completely re-designed to use a few tricks I learned in the past months. Also much easier to read now.&lt;br /&gt;
&lt;br /&gt;
I have used this script for comparing the [[Key|Keys]] of two objects in a dynamic set of sensors, to decide which one should be the &amp;quot;Master&amp;quot; in the region to tell me information. I&#039;m sure there can be more uses to this...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
integer compare(string s1, string s2) {&lt;br /&gt;
    if (s1 == s2) {&lt;br /&gt;
        return 0;&lt;br /&gt;
    } else if (llStringLength(s1) &amp;lt; llStringLength(s2)) {&lt;br /&gt;
        return 1;&lt;br /&gt;
    } else if (llStringLength(s1) &amp;gt; llStringLength(s2)) {&lt;br /&gt;
        return -1;&lt;br /&gt;
    } else {&lt;br /&gt;
        list l = [s1, s2];&lt;br /&gt;
        l = llListSort(l, 0, 1);&lt;br /&gt;
        if (s1 == llList2String(l, 0))&lt;br /&gt;
            return 1;&lt;br /&gt;
        return -1;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Notes: ===&lt;br /&gt;
I&#039;m not sure why the string length comparison is in above function, it is not needed for string comparison functions where you rely on alphabetical order. The concept is nice though. I&#039;ve modified this function. Given strings s1 and s2, it&#039;l return 1 if s1&amp;gt;s2, -1 if s1&amp;lt;s2 and 0 if they are equal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
integer compare(string s1, string s2) {&lt;br /&gt;
   if (s1 == s2) {&lt;br /&gt;
        return 0;&lt;br /&gt;
    } else {&lt;br /&gt;
        list l = [s1, s2];&lt;br /&gt;
        l = llListSort(l, 1, FALSE);&lt;br /&gt;
        if (s1 == llList2String(l, 0)) //s1&amp;gt;s2&lt;br /&gt;
            return 1;&lt;br /&gt;
        return -1;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
Above function not extensively tested, but it seems to suit my purpose (having users enter a set of characters within certain range, filter out anything else since it will be submitted to a webpage).&lt;br /&gt;
If only linden would give us &#039;normal&#039; string comparison functions like any other language, instead of spending expensive cpu cycles to validate user input.&lt;br /&gt;
&lt;br /&gt;
{{LSLC|Library}}&lt;br /&gt;
{{LSLC|Examples}}&lt;/div&gt;</summary>
		<author><name>Tano Toll</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=String_Compare&amp;diff=603953</id>
		<title>String Compare</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=String_Compare&amp;diff=603953"/>
		<updated>2009-10-17T11:46:36Z</updated>

		<summary type="html">&lt;p&gt;Tano Toll: /* String compare */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{LSL Header}}&lt;br /&gt;
=== String compare ===&lt;br /&gt;
Created by [[User:Xaviar Czervik|Xaviar Czervik]]. Do whatever you wish with this function: Sell it (good luck), use it, or modify it.&lt;br /&gt;
&lt;br /&gt;
The following code returns 1, -1 or 0. The 1 and -1 are essentially random, however it will return the same value every time the script is executed. 0 Is returned when, and only when, the strings are exactly equal. Completely re-designed to use a few tricks I learned in the past months. Also much easier to read now.&lt;br /&gt;
&lt;br /&gt;
I have used this script for comparing the [[Key|Keys]] of two objects in a dynamic set of sensors, to decide which one should be the &amp;quot;Master&amp;quot; in the region to tell me information. I&#039;m sure there can be more uses to this...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
integer compare(string s1, string s2) {&lt;br /&gt;
    if (s1 == s2) {&lt;br /&gt;
        return 0;&lt;br /&gt;
    } else if (llStringLength(s1) &amp;lt; llStringLength(s2)) {&lt;br /&gt;
        return 1;&lt;br /&gt;
    } else if (llStringLength(s1) &amp;gt; llStringLength(s2)) {&lt;br /&gt;
        return -1;&lt;br /&gt;
    } else {&lt;br /&gt;
        list l = [s1, s2];&lt;br /&gt;
        l = llListSort(l, 0, 1);&lt;br /&gt;
        if (s1 == llList2String(l, 0))&lt;br /&gt;
            return 1;&lt;br /&gt;
        return -1;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Notes: ===&lt;br /&gt;
I&#039;m not sure why the string length comparison is in above function, it is not needed. The concept is nice though. I&#039;ve modified this function. Given strings s1 and s2, it&#039;l return 1 if s1&amp;gt;s2, -1 if s1&amp;lt;s2 and 0 if they are equal:&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
integer compare(string s1, string s2) {&lt;br /&gt;
   if (s1 == s2) {&lt;br /&gt;
        return 0;&lt;br /&gt;
    } else {&lt;br /&gt;
        list l = [s1, s2];&lt;br /&gt;
        l = llListSort(l, 1, FALSE);&lt;br /&gt;
        if (s1 == llList2String(l, 0)) //s1&amp;gt;s2&lt;br /&gt;
            return 1;&lt;br /&gt;
        return -1;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
{{LSLC|Library}}&lt;br /&gt;
{{LSLC|Examples}}&lt;/div&gt;</summary>
		<author><name>Tano Toll</name></author>
	</entry>
</feed>